Source file
src/runtime/debuglog.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package runtime
17
18 import (
19 "runtime/internal/atomic"
20 "unsafe"
21 )
22
23
24
25
26 const debugLogBytes = 16 << 10
27
28
29
30 const debugLogStringLimit = debugLogBytes / 8
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 func dlog() *dlogger {
50 if !dlogEnabled {
51 return nil
52 }
53
54
55 tick, nano := uint64(cputicks()), uint64(nanotime())
56
57
58 l := getCachedDlogger()
59
60
61
62 if l == nil {
63 allp := (*uintptr)(unsafe.Pointer(&allDloggers))
64 all := (*dlogger)(unsafe.Pointer(atomic.Loaduintptr(allp)))
65 for l1 := all; l1 != nil; l1 = l1.allLink {
66 if atomic.Load(&l1.owned) == 0 && atomic.Cas(&l1.owned, 0, 1) {
67 l = l1
68 break
69 }
70 }
71 }
72
73
74 if l == nil {
75 l = (*dlogger)(sysAlloc(unsafe.Sizeof(dlogger{}), nil))
76 if l == nil {
77 throw("failed to allocate debug log")
78 }
79 l.w.r.data = &l.w.data
80 l.owned = 1
81
82
83 headp := (*uintptr)(unsafe.Pointer(&allDloggers))
84 for {
85 head := atomic.Loaduintptr(headp)
86 l.allLink = (*dlogger)(unsafe.Pointer(head))
87 if atomic.Casuintptr(headp, head, uintptr(unsafe.Pointer(l))) {
88 break
89 }
90 }
91 }
92
93
94
95
96 const deltaLimit = 1<<(3*7) - 1
97 if tick-l.w.tick > deltaLimit || nano-l.w.nano > deltaLimit {
98 l.w.writeSync(tick, nano)
99 }
100
101
102 l.w.ensure(debugLogHeaderSize)
103 l.w.write += debugLogHeaderSize
104
105
106 l.w.uvarint(tick - l.w.tick)
107 l.w.uvarint(nano - l.w.nano)
108 gp := getg()
109 if gp != nil && gp.m != nil && gp.m.p != 0 {
110 l.w.varint(int64(gp.m.p.ptr().id))
111 } else {
112 l.w.varint(-1)
113 }
114
115 return l
116 }
117
118
119
120
121
122
123
124 type dlogger struct {
125 w debugLogWriter
126
127
128 allLink *dlogger
129
130
131
132 owned uint32
133 }
134
135
136
137
138 var allDloggers *dlogger
139
140
141 func (l *dlogger) end() {
142 if !dlogEnabled {
143 return
144 }
145
146
147 size := l.w.write - l.w.r.end
148 if !l.w.writeFrameAt(l.w.r.end, size) {
149 throw("record too large")
150 }
151
152
153 l.w.r.end = l.w.write
154
155
156 if putCachedDlogger(l) {
157 return
158 }
159
160
161 atomic.Store(&l.owned, 0)
162 }
163
164 const (
165 debugLogUnknown = 1 + iota
166 debugLogBoolTrue
167 debugLogBoolFalse
168 debugLogInt
169 debugLogUint
170 debugLogHex
171 debugLogPtr
172 debugLogString
173 debugLogConstString
174 debugLogStringOverflow
175
176 debugLogPC
177 debugLogTraceback
178 )
179
180
181 func (l *dlogger) b(x bool) *dlogger {
182 if !dlogEnabled {
183 return l
184 }
185 if x {
186 l.w.byte(debugLogBoolTrue)
187 } else {
188 l.w.byte(debugLogBoolFalse)
189 }
190 return l
191 }
192
193
194 func (l *dlogger) i(x int) *dlogger {
195 return l.i64(int64(x))
196 }
197
198
199 func (l *dlogger) i8(x int8) *dlogger {
200 return l.i64(int64(x))
201 }
202
203
204 func (l *dlogger) i16(x int16) *dlogger {
205 return l.i64(int64(x))
206 }
207
208
209 func (l *dlogger) i32(x int32) *dlogger {
210 return l.i64(int64(x))
211 }
212
213
214 func (l *dlogger) i64(x int64) *dlogger {
215 if !dlogEnabled {
216 return l
217 }
218 l.w.byte(debugLogInt)
219 l.w.varint(x)
220 return l
221 }
222
223
224 func (l *dlogger) u(x uint) *dlogger {
225 return l.u64(uint64(x))
226 }
227
228
229 func (l *dlogger) uptr(x uintptr) *dlogger {
230 return l.u64(uint64(x))
231 }
232
233
234 func (l *dlogger) u8(x uint8) *dlogger {
235 return l.u64(uint64(x))
236 }
237
238
239 func (l *dlogger) u16(x uint16) *dlogger {
240 return l.u64(uint64(x))
241 }
242
243
244 func (l *dlogger) u32(x uint32) *dlogger {
245 return l.u64(uint64(x))
246 }
247
248
249 func (l *dlogger) u64(x uint64) *dlogger {
250 if !dlogEnabled {
251 return l
252 }
253 l.w.byte(debugLogUint)
254 l.w.uvarint(x)
255 return l
256 }
257
258
259 func (l *dlogger) hex(x uint64) *dlogger {
260 if !dlogEnabled {
261 return l
262 }
263 l.w.byte(debugLogHex)
264 l.w.uvarint(x)
265 return l
266 }
267
268
269 func (l *dlogger) p(x any) *dlogger {
270 if !dlogEnabled {
271 return l
272 }
273 l.w.byte(debugLogPtr)
274 if x == nil {
275 l.w.uvarint(0)
276 } else {
277 v := efaceOf(&x)
278 switch v._type.kind & kindMask {
279 case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer:
280 l.w.uvarint(uint64(uintptr(v.data)))
281 default:
282 throw("not a pointer type")
283 }
284 }
285 return l
286 }
287
288
289 func (l *dlogger) s(x string) *dlogger {
290 if !dlogEnabled {
291 return l
292 }
293 str := stringStructOf(&x)
294 datap := &firstmoduledata
295 if len(x) > 4 && datap.etext <= uintptr(str.str) && uintptr(str.str) < datap.end {
296
297
298
299 l.w.byte(debugLogConstString)
300 l.w.uvarint(uint64(str.len))
301 l.w.uvarint(uint64(uintptr(str.str) - datap.etext))
302 } else {
303 l.w.byte(debugLogString)
304 var b []byte
305 bb := (*slice)(unsafe.Pointer(&b))
306 bb.array = str.str
307 bb.len, bb.cap = str.len, str.len
308 if len(b) > debugLogStringLimit {
309 b = b[:debugLogStringLimit]
310 }
311 l.w.uvarint(uint64(len(b)))
312 l.w.bytes(b)
313 if len(b) != len(x) {
314 l.w.byte(debugLogStringOverflow)
315 l.w.uvarint(uint64(len(x) - len(b)))
316 }
317 }
318 return l
319 }
320
321
322 func (l *dlogger) pc(x uintptr) *dlogger {
323 if !dlogEnabled {
324 return l
325 }
326 l.w.byte(debugLogPC)
327 l.w.uvarint(uint64(x))
328 return l
329 }
330
331
332 func (l *dlogger) traceback(x []uintptr) *dlogger {
333 if !dlogEnabled {
334 return l
335 }
336 l.w.byte(debugLogTraceback)
337 l.w.uvarint(uint64(len(x)))
338 for _, pc := range x {
339 l.w.uvarint(uint64(pc))
340 }
341 return l
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 type debugLogWriter struct {
360 write uint64
361 data debugLogBuf
362
363
364
365 tick, nano uint64
366
367
368
369
370 r debugLogReader
371
372
373
374 buf [10]byte
375 }
376
377
378 type debugLogBuf [debugLogBytes]byte
379
380 const (
381
382
383 debugLogHeaderSize = 2
384
385
386 debugLogSyncSize = debugLogHeaderSize + 2*8
387 )
388
389
390 func (l *debugLogWriter) ensure(n uint64) {
391 for l.write+n >= l.r.begin+uint64(len(l.data)) {
392
393 if l.r.skip() == ^uint64(0) {
394
395
396
397
398
399
400 throw("record wrapped around")
401 }
402 }
403 }
404
405
406 func (l *debugLogWriter) writeFrameAt(pos, size uint64) bool {
407 l.data[pos%uint64(len(l.data))] = uint8(size)
408 l.data[(pos+1)%uint64(len(l.data))] = uint8(size >> 8)
409 return size <= 0xFFFF
410 }
411
412
413 func (l *debugLogWriter) writeSync(tick, nano uint64) {
414 l.tick, l.nano = tick, nano
415 l.ensure(debugLogHeaderSize)
416 l.writeFrameAt(l.write, 0)
417 l.write += debugLogHeaderSize
418 l.writeUint64LE(tick)
419 l.writeUint64LE(nano)
420 l.r.end = l.write
421 }
422
423
424 func (l *debugLogWriter) writeUint64LE(x uint64) {
425 var b [8]byte
426 b[0] = byte(x)
427 b[1] = byte(x >> 8)
428 b[2] = byte(x >> 16)
429 b[3] = byte(x >> 24)
430 b[4] = byte(x >> 32)
431 b[5] = byte(x >> 40)
432 b[6] = byte(x >> 48)
433 b[7] = byte(x >> 56)
434 l.bytes(b[:])
435 }
436
437
438 func (l *debugLogWriter) byte(x byte) {
439 l.ensure(1)
440 pos := l.write
441 l.write++
442 l.data[pos%uint64(len(l.data))] = x
443 }
444
445
446 func (l *debugLogWriter) bytes(x []byte) {
447 l.ensure(uint64(len(x)))
448 pos := l.write
449 l.write += uint64(len(x))
450 for len(x) > 0 {
451 n := copy(l.data[pos%uint64(len(l.data)):], x)
452 pos += uint64(n)
453 x = x[n:]
454 }
455 }
456
457
458 func (l *debugLogWriter) varint(x int64) {
459 var u uint64
460 if x < 0 {
461 u = (^uint64(x) << 1) | 1
462 } else {
463 u = (uint64(x) << 1)
464 }
465 l.uvarint(u)
466 }
467
468
469 func (l *debugLogWriter) uvarint(u uint64) {
470 i := 0
471 for u >= 0x80 {
472 l.buf[i] = byte(u) | 0x80
473 u >>= 7
474 i++
475 }
476 l.buf[i] = byte(u)
477 i++
478 l.bytes(l.buf[:i])
479 }
480
481 type debugLogReader struct {
482 data *debugLogBuf
483
484
485
486 begin, end uint64
487
488
489 tick, nano uint64
490 }
491
492
493 func (r *debugLogReader) skip() uint64 {
494
495 if r.begin+debugLogHeaderSize > r.end {
496 return ^uint64(0)
497 }
498 size := uint64(r.readUint16LEAt(r.begin))
499 if size == 0 {
500
501 r.tick = r.readUint64LEAt(r.begin + debugLogHeaderSize)
502 r.nano = r.readUint64LEAt(r.begin + debugLogHeaderSize + 8)
503 size = debugLogSyncSize
504 }
505 if r.begin+size > r.end {
506 return ^uint64(0)
507 }
508 r.begin += size
509 return size
510 }
511
512
513 func (r *debugLogReader) readUint16LEAt(pos uint64) uint16 {
514 return uint16(r.data[pos%uint64(len(r.data))]) |
515 uint16(r.data[(pos+1)%uint64(len(r.data))])<<8
516 }
517
518
519 func (r *debugLogReader) readUint64LEAt(pos uint64) uint64 {
520 var b [8]byte
521 for i := range b {
522 b[i] = r.data[pos%uint64(len(r.data))]
523 pos++
524 }
525 return uint64(b[0]) | uint64(b[1])<<8 |
526 uint64(b[2])<<16 | uint64(b[3])<<24 |
527 uint64(b[4])<<32 | uint64(b[5])<<40 |
528 uint64(b[6])<<48 | uint64(b[7])<<56
529 }
530
531 func (r *debugLogReader) peek() (tick uint64) {
532
533 size := uint64(0)
534 for size == 0 {
535 if r.begin+debugLogHeaderSize > r.end {
536 return ^uint64(0)
537 }
538 size = uint64(r.readUint16LEAt(r.begin))
539 if size != 0 {
540 break
541 }
542 if r.begin+debugLogSyncSize > r.end {
543 return ^uint64(0)
544 }
545
546 r.tick = r.readUint64LEAt(r.begin + debugLogHeaderSize)
547 r.nano = r.readUint64LEAt(r.begin + debugLogHeaderSize + 8)
548 r.begin += debugLogSyncSize
549 }
550
551
552 if r.begin+size > r.end {
553 return ^uint64(0)
554 }
555 pos := r.begin + debugLogHeaderSize
556 var u uint64
557 for i := uint(0); ; i += 7 {
558 b := r.data[pos%uint64(len(r.data))]
559 pos++
560 u |= uint64(b&^0x80) << i
561 if b&0x80 == 0 {
562 break
563 }
564 }
565 if pos > r.begin+size {
566 return ^uint64(0)
567 }
568 return r.tick + u
569 }
570
571 func (r *debugLogReader) header() (end, tick, nano uint64, p int) {
572
573
574 size := uint64(r.readUint16LEAt(r.begin))
575 end = r.begin + size
576 r.begin += debugLogHeaderSize
577
578
579 tick = r.uvarint() + r.tick
580 nano = r.uvarint() + r.nano
581 p = int(r.varint())
582
583 return
584 }
585
586 func (r *debugLogReader) uvarint() uint64 {
587 var u uint64
588 for i := uint(0); ; i += 7 {
589 b := r.data[r.begin%uint64(len(r.data))]
590 r.begin++
591 u |= uint64(b&^0x80) << i
592 if b&0x80 == 0 {
593 break
594 }
595 }
596 return u
597 }
598
599 func (r *debugLogReader) varint() int64 {
600 u := r.uvarint()
601 var v int64
602 if u&1 == 0 {
603 v = int64(u >> 1)
604 } else {
605 v = ^int64(u >> 1)
606 }
607 return v
608 }
609
610 func (r *debugLogReader) printVal() bool {
611 typ := r.data[r.begin%uint64(len(r.data))]
612 r.begin++
613
614 switch typ {
615 default:
616 print("<unknown field type ", hex(typ), " pos ", r.begin-1, " end ", r.end, ">\n")
617 return false
618
619 case debugLogUnknown:
620 print("<unknown kind>")
621
622 case debugLogBoolTrue:
623 print(true)
624
625 case debugLogBoolFalse:
626 print(false)
627
628 case debugLogInt:
629 print(r.varint())
630
631 case debugLogUint:
632 print(r.uvarint())
633
634 case debugLogHex, debugLogPtr:
635 print(hex(r.uvarint()))
636
637 case debugLogString:
638 sl := r.uvarint()
639 if r.begin+sl > r.end {
640 r.begin = r.end
641 print("<string length corrupted>")
642 break
643 }
644 for sl > 0 {
645 b := r.data[r.begin%uint64(len(r.data)):]
646 if uint64(len(b)) > sl {
647 b = b[:sl]
648 }
649 r.begin += uint64(len(b))
650 sl -= uint64(len(b))
651 gwrite(b)
652 }
653
654 case debugLogConstString:
655 len, ptr := int(r.uvarint()), uintptr(r.uvarint())
656 ptr += firstmoduledata.etext
657 str := stringStruct{
658 str: unsafe.Pointer(ptr),
659 len: len,
660 }
661 s := *(*string)(unsafe.Pointer(&str))
662 print(s)
663
664 case debugLogStringOverflow:
665 print("..(", r.uvarint(), " more bytes)..")
666
667 case debugLogPC:
668 printDebugLogPC(uintptr(r.uvarint()), false)
669
670 case debugLogTraceback:
671 n := int(r.uvarint())
672 for i := 0; i < n; i++ {
673 print("\n\t")
674
675
676
677
678 printDebugLogPC(uintptr(r.uvarint()), true)
679 }
680 }
681
682 return true
683 }
684
685
686 func printDebugLog() {
687 if !dlogEnabled {
688 return
689 }
690
691
692
693
694 printlock()
695
696
697 allp := (*uintptr)(unsafe.Pointer(&allDloggers))
698 all := (*dlogger)(unsafe.Pointer(atomic.Loaduintptr(allp)))
699
700
701 n := 0
702 for l := all; l != nil; l = l.allLink {
703 n++
704 }
705 if n == 0 {
706 printunlock()
707 return
708 }
709
710
711 type readState struct {
712 debugLogReader
713 first bool
714 lost uint64
715 nextTick uint64
716 }
717 state1 := sysAlloc(unsafe.Sizeof(readState{})*uintptr(n), nil)
718 if state1 == nil {
719 println("failed to allocate read state for", n, "logs")
720 printunlock()
721 return
722 }
723 state := (*[1 << 20]readState)(state1)[:n]
724 {
725 l := all
726 for i := range state {
727 s := &state[i]
728 s.debugLogReader = l.w.r
729 s.first = true
730 s.lost = l.w.r.begin
731 s.nextTick = s.peek()
732 l = l.allLink
733 }
734 }
735
736
737 for {
738
739 var best struct {
740 tick uint64
741 i int
742 }
743 best.tick = ^uint64(0)
744 for i := range state {
745 if state[i].nextTick < best.tick {
746 best.tick = state[i].nextTick
747 best.i = i
748 }
749 }
750 if best.tick == ^uint64(0) {
751 break
752 }
753
754
755 s := &state[best.i]
756 if s.first {
757 print(">> begin log ", best.i)
758 if s.lost != 0 {
759 print("; lost first ", s.lost>>10, "KB")
760 }
761 print(" <<\n")
762 s.first = false
763 }
764
765 end, _, nano, p := s.header()
766 oldEnd := s.end
767 s.end = end
768
769 print("[")
770 var tmpbuf [21]byte
771 pnano := int64(nano) - runtimeInitTime
772 if pnano < 0 {
773
774 pnano = 0
775 }
776 print(string(itoaDiv(tmpbuf[:], uint64(pnano), 9)))
777 print(" P ", p, "] ")
778
779 for i := 0; s.begin < s.end; i++ {
780 if i > 0 {
781 print(" ")
782 }
783 if !s.printVal() {
784
785 print("<aborting P log>")
786 end = oldEnd
787 break
788 }
789 }
790 println()
791
792
793 s.begin = end
794 s.end = oldEnd
795 s.nextTick = s.peek()
796 }
797
798 printunlock()
799 }
800
801
802
803 func printDebugLogPC(pc uintptr, returnPC bool) {
804 fn := findfunc(pc)
805 if returnPC && (!fn.valid() || pc > fn.entry()) {
806
807
808 pc--
809 }
810
811 print(hex(pc))
812 if !fn.valid() {
813 print(" [unknown PC]")
814 } else {
815 name := funcname(fn)
816 file, line := funcline(fn, pc)
817 print(" [", name, "+", hex(pc-fn.entry()),
818 " ", file, ":", line, "]")
819 }
820 }
821
View as plain text