package runtime
import (
)
const debugLogBytes = 16 << 10
const debugLogStringLimit = debugLogBytes / 8
func () *dlogger {
if !dlogEnabled {
return nil
}
, := uint64(cputicks()), uint64(nanotime())
:= getCachedDlogger()
if == nil {
:= (*uintptr)(unsafe.Pointer(&allDloggers))
:= (*dlogger)(unsafe.Pointer(atomic.Loaduintptr()))
for := ; != nil; = .allLink {
if atomic.Load(&.owned) == 0 && atomic.Cas(&.owned, 0, 1) {
=
break
}
}
}
if == nil {
= (*dlogger)(sysAlloc(unsafe.Sizeof(dlogger{}), nil))
if == nil {
throw("failed to allocate debug log")
}
.w.r.data = &.w.data
.owned = 1
:= (*uintptr)(unsafe.Pointer(&allDloggers))
for {
:= atomic.Loaduintptr()
.allLink = (*dlogger)(unsafe.Pointer())
if atomic.Casuintptr(, , uintptr(unsafe.Pointer())) {
break
}
}
}
const = 1<<(3*7) - 1
if -.w.tick > || -.w.nano > {
.w.writeSync(, )
}
.w.ensure(debugLogHeaderSize)
.w.write += debugLogHeaderSize
.w.uvarint( - .w.tick)
.w.uvarint( - .w.nano)
:= getg()
if != nil && .m != nil && .m.p != 0 {
.w.varint(int64(.m.p.ptr().id))
} else {
.w.varint(-1)
}
return
}
type dlogger struct {
w debugLogWriter
allLink *dlogger
owned uint32
}
var allDloggers *dlogger
func ( *dlogger) () {
if !dlogEnabled {
return
}
:= .w.write - .w.r.end
if !.w.writeFrameAt(.w.r.end, ) {
throw("record too large")
}
.w.r.end = .w.write
if putCachedDlogger() {
return
}
atomic.Store(&.owned, 0)
}
const (
debugLogUnknown = 1 + iota
debugLogBoolTrue
debugLogBoolFalse
debugLogInt
debugLogUint
debugLogHex
debugLogPtr
debugLogString
debugLogConstString
debugLogStringOverflow
debugLogPC
debugLogTraceback
)
func ( *dlogger) ( bool) *dlogger {
if !dlogEnabled {
return
}
if {
.w.byte(debugLogBoolTrue)
} else {
.w.byte(debugLogBoolFalse)
}
return
}
func ( *dlogger) ( int) *dlogger {
return .i64(int64())
}
func ( *dlogger) ( int8) *dlogger {
return .i64(int64())
}
func ( *dlogger) ( int16) *dlogger {
return .i64(int64())
}
func ( *dlogger) ( int32) *dlogger {
return .i64(int64())
}
func ( *dlogger) ( int64) *dlogger {
if !dlogEnabled {
return
}
.w.byte(debugLogInt)
.w.varint()
return
}
func ( *dlogger) ( uint) *dlogger {
return .u64(uint64())
}
func ( *dlogger) ( uintptr) *dlogger {
return .u64(uint64())
}
func ( *dlogger) ( uint8) *dlogger {
return .u64(uint64())
}
func ( *dlogger) ( uint16) *dlogger {
return .u64(uint64())
}
func ( *dlogger) ( uint32) *dlogger {
return .u64(uint64())
}
func ( *dlogger) ( uint64) *dlogger {
if !dlogEnabled {
return
}
.w.byte(debugLogUint)
.w.uvarint()
return
}
func ( *dlogger) ( uint64) *dlogger {
if !dlogEnabled {
return
}
.w.byte(debugLogHex)
.w.uvarint()
return
}
func ( *dlogger) ( interface{}) *dlogger {
if !dlogEnabled {
return
}
.w.byte(debugLogPtr)
if == nil {
.w.uvarint(0)
} else {
:= efaceOf(&)
switch ._type.kind & kindMask {
case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer:
.w.uvarint(uint64(uintptr(.data)))
default:
throw("not a pointer type")
}
}
return
}
func ( *dlogger) ( string) *dlogger {
if !dlogEnabled {
return
}
:= stringStructOf(&)
:= &firstmoduledata
if len() > 4 && .etext <= uintptr(.str) && uintptr(.str) < .end {
.w.byte(debugLogConstString)
.w.uvarint(uint64(.len))
.w.uvarint(uint64(uintptr(.str) - .etext))
} else {
.w.byte(debugLogString)
var []byte
:= (*slice)(unsafe.Pointer(&))
.array = .str
.len, .cap = .len, .len
if len() > debugLogStringLimit {
= [:debugLogStringLimit]
}
.w.uvarint(uint64(len()))
.w.bytes()
if len() != len() {
.w.byte(debugLogStringOverflow)
.w.uvarint(uint64(len() - len()))
}
}
return
}
func ( *dlogger) ( uintptr) *dlogger {
if !dlogEnabled {
return
}
.w.byte(debugLogPC)
.w.uvarint(uint64())
return
}
func ( *dlogger) ( []uintptr) *dlogger {
if !dlogEnabled {
return
}
.w.byte(debugLogTraceback)
.w.uvarint(uint64(len()))
for , := range {
.w.uvarint(uint64())
}
return
}
type debugLogWriter struct {
write uint64
data debugLogBuf
tick, nano uint64
r debugLogReader
buf [10]byte
}
type debugLogBuf [debugLogBytes]byte
const (
debugLogHeaderSize = 2
debugLogSyncSize = debugLogHeaderSize + 2*8
)
func ( *debugLogWriter) ( uint64) {
for .write+ >= .r.begin+uint64(len(.data)) {
if .r.skip() == ^uint64(0) {
throw("record wrapped around")
}
}
}
func ( *debugLogWriter) (, uint64) bool {
.data[%uint64(len(.data))] = uint8()
.data[(+1)%uint64(len(.data))] = uint8( >> 8)
return <= 0xFFFF
}
func ( *debugLogWriter) (, uint64) {
.tick, .nano = ,
.ensure(debugLogHeaderSize)
.writeFrameAt(.write, 0)
.write += debugLogHeaderSize
.writeUint64LE()
.writeUint64LE()
.r.end = .write
}
func ( *debugLogWriter) ( uint64) {
var [8]byte
[0] = byte()
[1] = byte( >> 8)
[2] = byte( >> 16)
[3] = byte( >> 24)
[4] = byte( >> 32)
[5] = byte( >> 40)
[6] = byte( >> 48)
[7] = byte( >> 56)
.bytes([:])
}
func ( *debugLogWriter) ( byte) {
.ensure(1)
:= .write
.write++
.data[%uint64(len(.data))] =
}
func ( *debugLogWriter) ( []byte) {
.ensure(uint64(len()))
:= .write
.write += uint64(len())
for len() > 0 {
:= copy(.data[%uint64(len(.data)):], )
+= uint64()
= [:]
}
}
func ( *debugLogWriter) ( int64) {
var uint64
if < 0 {
= (^uint64() << 1) | 1
} else {
= (uint64() << 1)
}
.uvarint()
}
func ( *debugLogWriter) ( uint64) {
:= 0
for >= 0x80 {
.buf[] = byte() | 0x80
>>= 7
++
}
.buf[] = byte()
++
.bytes(.buf[:])
}
type debugLogReader struct {
data *debugLogBuf
begin, end uint64
tick, nano uint64
}
func ( *debugLogReader) () uint64 {
if .begin+debugLogHeaderSize > .end {
return ^uint64(0)
}
:= uint64(.readUint16LEAt(.begin))
if == 0 {
.tick = .readUint64LEAt(.begin + debugLogHeaderSize)
.nano = .readUint64LEAt(.begin + debugLogHeaderSize + 8)
= debugLogSyncSize
}
if .begin+ > .end {
return ^uint64(0)
}
.begin +=
return
}
func ( *debugLogReader) ( uint64) uint16 {
return uint16(.data[%uint64(len(.data))]) |
uint16(.data[(+1)%uint64(len(.data))])<<8
}
func ( *debugLogReader) ( uint64) uint64 {
var [8]byte
for := range {
[] = .data[%uint64(len(.data))]
++
}
return uint64([0]) | uint64([1])<<8 |
uint64([2])<<16 | uint64([3])<<24 |
uint64([4])<<32 | uint64([5])<<40 |
uint64([6])<<48 | uint64([7])<<56
}
func ( *debugLogReader) () ( uint64) {
:= uint64(0)
for == 0 {
if .begin+debugLogHeaderSize > .end {
return ^uint64(0)
}
= uint64(.readUint16LEAt(.begin))
if != 0 {
break
}
if .begin+debugLogSyncSize > .end {
return ^uint64(0)
}
.tick = .readUint64LEAt(.begin + debugLogHeaderSize)
.nano = .readUint64LEAt(.begin + debugLogHeaderSize + 8)
.begin += debugLogSyncSize
}
if .begin+ > .end {
return ^uint64(0)
}
:= .begin + debugLogHeaderSize
var uint64
for := uint(0); ; += 7 {
:= .data[%uint64(len(.data))]
++
|= uint64(&^0x80) <<
if &0x80 == 0 {
break
}
}
if > .begin+ {
return ^uint64(0)
}
return .tick +
}
func ( *debugLogReader) () (, , uint64, int) {
:= uint64(.readUint16LEAt(.begin))
= .begin +
.begin += debugLogHeaderSize
= .uvarint() + .tick
= .uvarint() + .nano
= int(.varint())
return
}
func ( *debugLogReader) () uint64 {
var uint64
for := uint(0); ; += 7 {
:= .data[.begin%uint64(len(.data))]
.begin++
|= uint64(&^0x80) <<
if &0x80 == 0 {
break
}
}
return
}
func ( *debugLogReader) () int64 {
:= .uvarint()
var int64
if &1 == 0 {
= int64( >> 1)
} else {
= ^int64( >> 1)
}
return
}
func ( *debugLogReader) () bool {
:= .data[.begin%uint64(len(.data))]
.begin++
switch {
default:
print("<unknown field type ", hex(), " pos ", .begin-1, " end ", .end, ">\n")
return false
case debugLogUnknown:
print("<unknown kind>")
case debugLogBoolTrue:
print(true)
case debugLogBoolFalse:
print(false)
case debugLogInt:
print(.varint())
case debugLogUint:
print(.uvarint())
case debugLogHex, debugLogPtr:
print(hex(.uvarint()))
case debugLogString:
:= .uvarint()
if .begin+ > .end {
.begin = .end
print("<string length corrupted>")
break
}
for > 0 {
:= .data[.begin%uint64(len(.data)):]
if uint64(len()) > {
= [:]
}
.begin += uint64(len())
-= uint64(len())
gwrite()
}
case debugLogConstString:
, := int(.uvarint()), uintptr(.uvarint())
+= firstmoduledata.etext
:= stringStruct{
str: unsafe.Pointer(),
len: ,
}
:= *(*string)(unsafe.Pointer(&))
print()
case debugLogStringOverflow:
print("..(", .uvarint(), " more bytes)..")
case debugLogPC:
printDebugLogPC(uintptr(.uvarint()), false)
case debugLogTraceback:
:= int(.uvarint())
for := 0; < ; ++ {
print("\n\t")
printDebugLogPC(uintptr(.uvarint()), true)
}
}
return true
}
func () {
if !dlogEnabled {
return
}
printlock()
:= (*uintptr)(unsafe.Pointer(&allDloggers))
:= (*dlogger)(unsafe.Pointer(atomic.Loaduintptr()))
:= 0
for := ; != nil; = .allLink {
++
}
if == 0 {
printunlock()
return
}
type struct {
debugLogReader
bool
uint64
uint64
}
:= sysAlloc(unsafe.Sizeof({})*uintptr(), nil)
if == nil {
println("failed to allocate read state for", , "logs")
printunlock()
return
}
:= (*[1 << 20])()[:]
{
:=
for := range {
:= &[]
. = .w.r
. = true
. = .w.r.begin
. = .peek()
= .allLink
}
}
for {
var struct {
uint64
int
}
. = ^uint64(0)
for := range {
if []. < . {
. = [].
. =
}
}
if . == ^uint64(0) {
break
}
:= &[.]
if . {
print(">> begin log ", .)
if . != 0 {
print("; lost first ", .>>10, "KB")
}
print(" <<\n")
. = false
}
, , , := .header()
:= .end
.end =
print("[")
var [21]byte
:= int64() - runtimeInitTime
if < 0 {
= 0
}
print(string(itoaDiv([:], uint64(), 9)))
print(" P ", , "] ")
for := 0; .begin < .end; ++ {
if > 0 {
print(" ")
}
if !.printVal() {
print("<aborting P log>")
=
break
}
}
println()
.begin =
.end =
. = .peek()
}
printunlock()
}
func ( uintptr, bool) {
:= findfunc()
if && (!.valid() || > .entry) {
--
}
print(hex())
if !.valid() {
print(" [unknown PC]")
} else {
:= funcname()
, := funcline(, )
print(" [", , "+", hex(-.entry),
" ", , ":", , "]")
}
}