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