1
2
3
4
5
6
7
8 package dwarf
9
10 import (
11 "bytes"
12 "cmd/internal/src"
13 "cmp"
14 "errors"
15 "fmt"
16 "internal/buildcfg"
17 "os/exec"
18 "slices"
19 "strconv"
20 "strings"
21 )
22
23
24 const InfoPrefix = "go:info."
25
26
27
28 const ConstInfoPrefix = "go:constinfo."
29
30
31
32 const CUInfoPrefix = "go:cuinfo."
33
34
35
36 const AbstractFuncSuffix = "$abstract"
37
38
39
40 var logDwarf bool
41
42
43 type Sym any
44
45
46 type Var struct {
47 Name string
48 Tag int
49 WithLoclist bool
50 IsReturnValue bool
51 IsInlFormal bool
52 DictIndex uint16
53 StackOffset int32
54
55
56 PutLocationList func(listSym, startPC Sym)
57 Scope int32
58 Type Sym
59 DeclFile string
60 DeclLine uint
61 DeclCol uint
62 InlIndex int32
63 ChildIndex int32
64 IsInAbstract bool
65 ClosureOffset int64
66 }
67
68
69
70
71
72
73
74 type Scope struct {
75 Parent int32
76 Ranges []Range
77 Vars []*Var
78 }
79
80
81 type Range struct {
82 Start, End int64
83 }
84
85
86
87 type FnState struct {
88 Name string
89 Info Sym
90 Loc Sym
91 Ranges Sym
92 Absfn Sym
93 StartPC Sym
94 StartPos src.Pos
95 Size int64
96 External bool
97 Scopes []Scope
98 InlCalls InlCalls
99 UseBASEntries bool
100
101 dictIndexToOffset []int64
102 }
103
104 func EnableLogging(doit bool) {
105 logDwarf = doit
106 }
107
108
109
110 func MergeRanges(in1, in2 []Range) []Range {
111 out := make([]Range, 0, len(in1)+len(in2))
112 i, j := 0, 0
113 for {
114 var cur Range
115 if i < len(in2) && j < len(in1) {
116 if in2[i].Start < in1[j].Start {
117 cur = in2[i]
118 i++
119 } else {
120 cur = in1[j]
121 j++
122 }
123 } else if i < len(in2) {
124 cur = in2[i]
125 i++
126 } else if j < len(in1) {
127 cur = in1[j]
128 j++
129 } else {
130 break
131 }
132
133 if n := len(out); n > 0 && cur.Start <= out[n-1].End {
134 out[n-1].End = cur.End
135 } else {
136 out = append(out, cur)
137 }
138 }
139
140 return out
141 }
142
143
144 func (s *Scope) UnifyRanges(c *Scope) {
145 s.Ranges = MergeRanges(s.Ranges, c.Ranges)
146 }
147
148
149
150 func (s *Scope) AppendRange(r Range) {
151 if r.End <= r.Start {
152 return
153 }
154 i := len(s.Ranges)
155 if i > 0 && s.Ranges[i-1].End == r.Start {
156 s.Ranges[i-1].End = r.End
157 return
158 }
159 s.Ranges = append(s.Ranges, r)
160 }
161
162 type InlCalls struct {
163 Calls []InlCall
164 }
165
166 type InlCall struct {
167
168 InlIndex int
169
170
171 CallPos src.Pos
172
173
174 AbsFunSym Sym
175
176
177 Children []int
178
179
180
181 InlVars []*Var
182
183
184 Ranges []Range
185
186
187 Root bool
188 }
189
190
191 type Context interface {
192 PtrSize() int
193 Size(s Sym) int64
194 AddInt(s Sym, size int, i int64)
195 AddBytes(s Sym, b []byte)
196 AddAddress(s Sym, t any, ofs int64)
197 AddCURelativeAddress(s Sym, t any, ofs int64)
198 AddSectionOffset(s Sym, size int, t any, ofs int64)
199 AddDWARFAddrSectionOffset(s Sym, t any, ofs int64)
200 AddIndirectTextRef(s Sym, t any)
201 CurrentOffset(s Sym) int64
202 RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int)
203 RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32)
204 AddString(s Sym, v string)
205 Logf(format string, args ...any)
206 }
207
208
209 func AppendUleb128(b []byte, v uint64) []byte {
210 for {
211 c := uint8(v & 0x7f)
212 v >>= 7
213 if v != 0 {
214 c |= 0x80
215 }
216 b = append(b, c)
217 if c&0x80 == 0 {
218 break
219 }
220 }
221 return b
222 }
223
224
225 func AppendSleb128(b []byte, v int64) []byte {
226 for {
227 c := uint8(v & 0x7f)
228 s := uint8(v & 0x40)
229 v >>= 7
230 if (v != -1 || s == 0) && (v != 0 || s != 0) {
231 c |= 0x80
232 }
233 b = append(b, c)
234 if c&0x80 == 0 {
235 break
236 }
237 }
238 return b
239 }
240
241
242 var sevenbits = [...]byte{
243 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
244 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
245 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
246 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
247 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
248 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
249 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
250 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
251 }
252
253
254
255 func sevenBitU(v int64) []byte {
256 if uint64(v) < uint64(len(sevenbits)) {
257 return sevenbits[v : v+1]
258 }
259 return nil
260 }
261
262
263
264 func sevenBitS(v int64) []byte {
265 if uint64(v) <= 63 {
266 return sevenbits[v : v+1]
267 }
268 if uint64(-v) <= 64 {
269 return sevenbits[128+v : 128+v+1]
270 }
271 return nil
272 }
273
274
275 func Uleb128put(ctxt Context, s Sym, v int64) {
276 b := sevenBitU(v)
277 if b == nil {
278 var encbuf [20]byte
279 b = AppendUleb128(encbuf[:0], uint64(v))
280 }
281 ctxt.AddBytes(s, b)
282 }
283
284
285 func Sleb128put(ctxt Context, s Sym, v int64) {
286 b := sevenBitS(v)
287 if b == nil {
288 var encbuf [20]byte
289 b = AppendSleb128(encbuf[:0], v)
290 }
291 ctxt.AddBytes(s, b)
292 }
293
294
302 type dwAttrForm struct {
303 attr uint16
304 form uint8
305 }
306
307
308 const (
309 DW_AT_go_kind = 0x2900
310 DW_AT_go_key = 0x2901
311 DW_AT_go_elem = 0x2902
312
313
314 DW_AT_go_embedded_field = 0x2903
315 DW_AT_go_runtime_type = 0x2904
316
317 DW_AT_go_package_name = 0x2905
318 DW_AT_go_dict_index = 0x2906
319 DW_AT_go_closure_offset = 0x2907
320
321 DW_AT_internal_location = 253
322 )
323
324
325 const (
326 DW_ABRV_NULL = iota
327 DW_ABRV_COMPUNIT
328 DW_ABRV_COMPUNIT_TEXTLESS
329 DW_ABRV_FUNCTION
330 DW_ABRV_WRAPPER
331 DW_ABRV_FUNCTION_ABSTRACT
332 DW_ABRV_FUNCTION_CONCRETE
333 DW_ABRV_WRAPPER_CONCRETE
334 DW_ABRV_INLINED_SUBROUTINE
335 DW_ABRV_INLINED_SUBROUTINE_RANGES
336 DW_ABRV_VARIABLE
337 DW_ABRV_INT_CONSTANT
338 DW_ABRV_LEXICAL_BLOCK_RANGES
339 DW_ABRV_LEXICAL_BLOCK_SIMPLE
340 DW_ABRV_STRUCTFIELD
341 DW_ABRV_FUNCTYPEPARAM
342 DW_ABRV_FUNCTYPEOUTPARAM
343 DW_ABRV_DOTDOTDOT
344 DW_ABRV_ARRAYRANGE
345 DW_ABRV_NULLTYPE
346 DW_ABRV_BASETYPE
347 DW_ABRV_ARRAYTYPE
348 DW_ABRV_CHANTYPE
349 DW_ABRV_FUNCTYPE
350 DW_ABRV_IFACETYPE
351 DW_ABRV_MAPTYPE
352 DW_ABRV_PTRTYPE
353 DW_ABRV_BARE_PTRTYPE
354 DW_ABRV_SLICETYPE
355 DW_ABRV_STRINGTYPE
356 DW_ABRV_STRUCTTYPE
357 DW_ABRV_TYPEDECL
358 DW_ABRV_DICT_INDEX
359 DW_ABRV_LINKER_TRAMPOLINE
360 DW_ABRV_PUTVAR_START
361 )
362
363 type dwAbbrev struct {
364 tag uint8
365 children uint8
366 attr []dwAttrForm
367 }
368
369 var abbrevsFinalized bool
370
371
372
373
374
375
376
377
378
379
380 func expandPseudoForm(form uint8) uint8 {
381 switch form {
382 case DW_FORM_udata_pseudo:
383 expandedForm := DW_FORM_udata
384 if buildcfg.GOOS == "darwin" || buildcfg.GOOS == "ios" {
385 expandedForm = DW_FORM_data4
386 }
387 return uint8(expandedForm)
388 case DW_FORM_lo_pc_pseudo:
389 if buildcfg.Experiment.Dwarf5 {
390 return DW_FORM_addrx
391 }
392 return DW_FORM_addr
393 case DW_FORM_hi_pc_pseudo:
394 if buildcfg.Experiment.Dwarf5 {
395 return DW_FORM_udata
396 }
397 return DW_FORM_addr
398 default:
399 return form
400 }
401 }
402
403
404
405 func Abbrevs() []dwAbbrev {
406 if abbrevsFinalized {
407 return abbrevs
408 }
409 abbrevs = append(abbrevs, putvarAbbrevs...)
410 for i := 1; i < len(abbrevs); i++ {
411 for j := 0; j < len(abbrevs[i].attr); j++ {
412 abbrevs[i].attr[j].form = expandPseudoForm(abbrevs[i].attr[j].form)
413 }
414 }
415 if buildcfg.Experiment.Dwarf5 {
416
417
418
419
420 for i := 1; i < len(abbrevs); i++ {
421 haveLo := false
422 for j := 0; j < len(abbrevs[i].attr); j++ {
423 if abbrevs[i].attr[j].attr == DW_AT_low_pc {
424 haveLo = true
425 }
426 }
427 if abbrevs[i].tag == DW_TAG_compile_unit && haveLo {
428 abbrevs[i].attr = append(abbrevs[i].attr,
429 dwAttrForm{DW_AT_addr_base, DW_FORM_sec_offset})
430 }
431 }
432 }
433
434 abbrevsFinalized = true
435 return abbrevs
436 }
437
438
439
440
441
442 var abbrevs = []dwAbbrev{
443
444 {0, 0, []dwAttrForm{}},
445
446
447 {
448 DW_TAG_compile_unit,
449 DW_CHILDREN_yes,
450 []dwAttrForm{
451 {DW_AT_name, DW_FORM_string},
452 {DW_AT_language, DW_FORM_data1},
453 {DW_AT_stmt_list, DW_FORM_sec_offset},
454 {DW_AT_low_pc, DW_FORM_addr},
455 {DW_AT_ranges, DW_FORM_sec_offset},
456 {DW_AT_comp_dir, DW_FORM_string},
457 {DW_AT_producer, DW_FORM_string},
458 {DW_AT_go_package_name, DW_FORM_string},
459
460 },
461 },
462
463
464 {
465 DW_TAG_compile_unit,
466 DW_CHILDREN_yes,
467 []dwAttrForm{
468 {DW_AT_name, DW_FORM_string},
469 {DW_AT_language, DW_FORM_data1},
470 {DW_AT_comp_dir, DW_FORM_string},
471 {DW_AT_producer, DW_FORM_string},
472 {DW_AT_go_package_name, DW_FORM_string},
473 },
474 },
475
476
477 {
478 DW_TAG_subprogram,
479 DW_CHILDREN_yes,
480 []dwAttrForm{
481 {DW_AT_name, DW_FORM_string},
482 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
483 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
484 {DW_AT_frame_base, DW_FORM_block1},
485 {DW_AT_decl_file, DW_FORM_data4},
486 {DW_AT_decl_line, DW_FORM_udata},
487 {DW_AT_external, DW_FORM_flag},
488 },
489 },
490
491
492 {
493 DW_TAG_subprogram,
494 DW_CHILDREN_yes,
495 []dwAttrForm{
496 {DW_AT_name, DW_FORM_string},
497 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
498 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
499 {DW_AT_frame_base, DW_FORM_block1},
500 {DW_AT_trampoline, DW_FORM_flag},
501 },
502 },
503
504
505 {
506 DW_TAG_subprogram,
507 DW_CHILDREN_yes,
508 []dwAttrForm{
509 {DW_AT_name, DW_FORM_string},
510 {DW_AT_inline, DW_FORM_data1},
511 {DW_AT_decl_line, DW_FORM_udata},
512 {DW_AT_external, DW_FORM_flag},
513 },
514 },
515
516
517 {
518 DW_TAG_subprogram,
519 DW_CHILDREN_yes,
520 []dwAttrForm{
521 {DW_AT_abstract_origin, DW_FORM_ref_addr},
522 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
523 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
524 {DW_AT_frame_base, DW_FORM_block1},
525 },
526 },
527
528
529 {
530 DW_TAG_subprogram,
531 DW_CHILDREN_yes,
532 []dwAttrForm{
533 {DW_AT_abstract_origin, DW_FORM_ref_addr},
534 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
535 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
536 {DW_AT_frame_base, DW_FORM_block1},
537 {DW_AT_trampoline, DW_FORM_flag},
538 },
539 },
540
541
542 {
543 DW_TAG_inlined_subroutine,
544 DW_CHILDREN_yes,
545 []dwAttrForm{
546 {DW_AT_abstract_origin, DW_FORM_ref_addr},
547 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
548 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
549 {DW_AT_call_file, DW_FORM_data4},
550 {DW_AT_call_line, DW_FORM_udata_pseudo},
551 },
552 },
553
554
555 {
556 DW_TAG_inlined_subroutine,
557 DW_CHILDREN_yes,
558 []dwAttrForm{
559 {DW_AT_abstract_origin, DW_FORM_ref_addr},
560 {DW_AT_ranges, DW_FORM_sec_offset},
561 {DW_AT_call_file, DW_FORM_data4},
562 {DW_AT_call_line, DW_FORM_udata_pseudo},
563 },
564 },
565
566
567 {
568 DW_TAG_variable,
569 DW_CHILDREN_no,
570 []dwAttrForm{
571 {DW_AT_name, DW_FORM_string},
572 {DW_AT_location, DW_FORM_block1},
573 {DW_AT_type, DW_FORM_ref_addr},
574 {DW_AT_external, DW_FORM_flag},
575 },
576 },
577
578
579 {
580 DW_TAG_constant,
581 DW_CHILDREN_no,
582 []dwAttrForm{
583 {DW_AT_name, DW_FORM_string},
584 {DW_AT_type, DW_FORM_ref_addr},
585 {DW_AT_const_value, DW_FORM_sdata},
586 },
587 },
588
589
590 {
591 DW_TAG_lexical_block,
592 DW_CHILDREN_yes,
593 []dwAttrForm{
594 {DW_AT_ranges, DW_FORM_sec_offset},
595 },
596 },
597
598
599 {
600 DW_TAG_lexical_block,
601 DW_CHILDREN_yes,
602 []dwAttrForm{
603
604
605 {DW_AT_low_pc, DW_FORM_addr},
606 {DW_AT_high_pc, DW_FORM_addr},
607 },
608 },
609
610
611 {
612 DW_TAG_member,
613 DW_CHILDREN_no,
614
615
616 []dwAttrForm{
617 {DW_AT_name, DW_FORM_string},
618 {DW_AT_data_member_location, DW_FORM_udata},
619 {DW_AT_type, DW_FORM_ref_addr},
620 {DW_AT_go_embedded_field, DW_FORM_flag},
621 },
622 },
623
624
625 {
626 DW_TAG_formal_parameter,
627 DW_CHILDREN_no,
628
629
630
631
632 []dwAttrForm{
633 {DW_AT_type, DW_FORM_ref_addr},
634 },
635 },
636
637
638 {
639 DW_TAG_formal_parameter,
640 DW_CHILDREN_no,
641
642
643
644
645 []dwAttrForm{
646 {DW_AT_variable_parameter, DW_FORM_flag},
647 {DW_AT_type, DW_FORM_ref_addr},
648 },
649 },
650
651
652 {
653 DW_TAG_unspecified_parameters,
654 DW_CHILDREN_no,
655
656
657
658 []dwAttrForm{},
659 },
660
661
662 {
663 DW_TAG_subrange_type,
664 DW_CHILDREN_no,
665
666
667
668
669 []dwAttrForm{
670 {DW_AT_type, DW_FORM_ref_addr},
671 {DW_AT_count, DW_FORM_udata},
672 },
673 },
674
675
676
677 {
678 DW_TAG_unspecified_type,
679 DW_CHILDREN_no,
680 []dwAttrForm{
681 {DW_AT_name, DW_FORM_string},
682 },
683 },
684
685
686 {
687 DW_TAG_base_type,
688 DW_CHILDREN_no,
689 []dwAttrForm{
690 {DW_AT_name, DW_FORM_string},
691 {DW_AT_encoding, DW_FORM_data1},
692 {DW_AT_byte_size, DW_FORM_data1},
693 {DW_AT_go_kind, DW_FORM_data1},
694 {DW_AT_go_runtime_type, DW_FORM_addr},
695 },
696 },
697
698
699
700 {
701 DW_TAG_array_type,
702 DW_CHILDREN_yes,
703 []dwAttrForm{
704 {DW_AT_name, DW_FORM_string},
705 {DW_AT_type, DW_FORM_ref_addr},
706 {DW_AT_byte_size, DW_FORM_udata},
707 {DW_AT_go_kind, DW_FORM_data1},
708 {DW_AT_go_runtime_type, DW_FORM_addr},
709 },
710 },
711
712
713 {
714 DW_TAG_typedef,
715 DW_CHILDREN_no,
716 []dwAttrForm{
717 {DW_AT_name, DW_FORM_string},
718 {DW_AT_type, DW_FORM_ref_addr},
719 {DW_AT_go_kind, DW_FORM_data1},
720 {DW_AT_go_runtime_type, DW_FORM_addr},
721 {DW_AT_go_elem, DW_FORM_ref_addr},
722 },
723 },
724
725
726 {
727 DW_TAG_subroutine_type,
728 DW_CHILDREN_yes,
729 []dwAttrForm{
730 {DW_AT_name, DW_FORM_string},
731 {DW_AT_byte_size, DW_FORM_udata},
732 {DW_AT_go_kind, DW_FORM_data1},
733 {DW_AT_go_runtime_type, DW_FORM_addr},
734 },
735 },
736
737
738 {
739 DW_TAG_typedef,
740 DW_CHILDREN_yes,
741 []dwAttrForm{
742 {DW_AT_name, DW_FORM_string},
743 {DW_AT_type, DW_FORM_ref_addr},
744 {DW_AT_go_kind, DW_FORM_data1},
745 {DW_AT_go_runtime_type, DW_FORM_addr},
746 },
747 },
748
749
750 {
751 DW_TAG_typedef,
752 DW_CHILDREN_no,
753 []dwAttrForm{
754 {DW_AT_name, DW_FORM_string},
755 {DW_AT_type, DW_FORM_ref_addr},
756 {DW_AT_go_kind, DW_FORM_data1},
757 {DW_AT_go_runtime_type, DW_FORM_addr},
758 {DW_AT_go_key, DW_FORM_ref_addr},
759 {DW_AT_go_elem, DW_FORM_ref_addr},
760 },
761 },
762
763
764 {
765 DW_TAG_pointer_type,
766 DW_CHILDREN_no,
767 []dwAttrForm{
768 {DW_AT_name, DW_FORM_string},
769 {DW_AT_type, DW_FORM_ref_addr},
770 {DW_AT_go_kind, DW_FORM_data1},
771 {DW_AT_go_runtime_type, DW_FORM_addr},
772 },
773 },
774
775
776 {
777 DW_TAG_pointer_type,
778 DW_CHILDREN_no,
779 []dwAttrForm{
780 {DW_AT_name, DW_FORM_string},
781 {DW_AT_go_runtime_type, DW_FORM_addr},
782 },
783 },
784
785
786 {
787 DW_TAG_structure_type,
788 DW_CHILDREN_yes,
789 []dwAttrForm{
790 {DW_AT_name, DW_FORM_string},
791 {DW_AT_byte_size, DW_FORM_udata},
792 {DW_AT_go_kind, DW_FORM_data1},
793 {DW_AT_go_runtime_type, DW_FORM_addr},
794 {DW_AT_go_elem, DW_FORM_ref_addr},
795 },
796 },
797
798
799 {
800 DW_TAG_structure_type,
801 DW_CHILDREN_yes,
802 []dwAttrForm{
803 {DW_AT_name, DW_FORM_string},
804 {DW_AT_byte_size, DW_FORM_udata},
805 {DW_AT_go_kind, DW_FORM_data1},
806 {DW_AT_go_runtime_type, DW_FORM_addr},
807 },
808 },
809
810
811 {
812 DW_TAG_structure_type,
813 DW_CHILDREN_yes,
814 []dwAttrForm{
815 {DW_AT_name, DW_FORM_string},
816 {DW_AT_byte_size, DW_FORM_udata},
817 {DW_AT_go_kind, DW_FORM_data1},
818 {DW_AT_go_runtime_type, DW_FORM_addr},
819 },
820 },
821
822
823 {
824 DW_TAG_typedef,
825 DW_CHILDREN_no,
826 []dwAttrForm{
827 {DW_AT_name, DW_FORM_string},
828 {DW_AT_type, DW_FORM_ref_addr},
829 },
830 },
831
832
833 {
834 DW_TAG_typedef,
835 DW_CHILDREN_no,
836 []dwAttrForm{
837 {DW_AT_name, DW_FORM_string},
838 {DW_AT_type, DW_FORM_ref_addr},
839 {DW_AT_go_dict_index, DW_FORM_udata},
840 },
841 },
842
843
844
845
846
847 {
848 DW_TAG_subprogram,
849 DW_CHILDREN_no,
850 []dwAttrForm{
851 {DW_AT_low_pc, DW_FORM_addr},
852 {DW_AT_high_pc, DW_FORM_udata},
853 {DW_AT_trampoline, DW_FORM_addr},
854 },
855 },
856 }
857
858
859 func GetAbbrev() []byte {
860 abbrevs := Abbrevs()
861 var buf []byte
862 for i := 1; i < len(abbrevs); i++ {
863
864 buf = AppendUleb128(buf, uint64(i))
865 buf = AppendUleb128(buf, uint64(abbrevs[i].tag))
866 buf = append(buf, abbrevs[i].children)
867 for _, f := range abbrevs[i].attr {
868 buf = AppendUleb128(buf, uint64(f.attr))
869 buf = AppendUleb128(buf, uint64(f.form))
870 }
871 buf = append(buf, 0, 0)
872 }
873 return append(buf, 0)
874 }
875
876
879
880
881
882
883
884
885
886 type DWAttr struct {
887 Link *DWAttr
888 Atr uint16
889 Cls uint8
890 Value int64
891 Data any
892 }
893
894
895 type DWDie struct {
896 Abbrev int
897 Link *DWDie
898 Child *DWDie
899 Attr *DWAttr
900 Sym Sym
901 }
902
903 func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data any) error {
904 switch form {
905 case DW_FORM_addr:
906
907 if data == nil && value == 0 {
908 ctxt.AddInt(s, ctxt.PtrSize(), 0)
909 break
910 }
911 if cls == DW_CLS_GO_TYPEREF {
912 ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, value)
913 break
914 }
915 ctxt.AddAddress(s, data, value)
916
917 case DW_FORM_block1:
918 if cls == DW_CLS_ADDRESS {
919 ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize()))
920 ctxt.AddInt(s, 1, DW_OP_addr)
921 ctxt.AddAddress(s, data, 0)
922 break
923 }
924
925 value &= 0xff
926 ctxt.AddInt(s, 1, value)
927 p := data.([]byte)[:value]
928 ctxt.AddBytes(s, p)
929
930 case DW_FORM_block2:
931 value &= 0xffff
932
933 ctxt.AddInt(s, 2, value)
934 p := data.([]byte)[:value]
935 ctxt.AddBytes(s, p)
936
937 case DW_FORM_block4:
938 value &= 0xffffffff
939
940 ctxt.AddInt(s, 4, value)
941 p := data.([]byte)[:value]
942 ctxt.AddBytes(s, p)
943
944 case DW_FORM_block:
945 Uleb128put(ctxt, s, value)
946
947 p := data.([]byte)[:value]
948 ctxt.AddBytes(s, p)
949
950 case DW_FORM_data1:
951 ctxt.AddInt(s, 1, value)
952
953 case DW_FORM_data2:
954 ctxt.AddInt(s, 2, value)
955
956 case DW_FORM_data4:
957 if cls == DW_CLS_PTR {
958 ctxt.AddDWARFAddrSectionOffset(s, data, value)
959 break
960 }
961 ctxt.AddInt(s, 4, value)
962
963 case DW_FORM_data8:
964 ctxt.AddInt(s, 8, value)
965
966 case DW_FORM_sdata:
967 Sleb128put(ctxt, s, value)
968
969 case DW_FORM_udata:
970 Uleb128put(ctxt, s, value)
971
972 case DW_FORM_string:
973 str := data.(string)
974 ctxt.AddString(s, str)
975
976 for i := int64(len(str)); i < value; i++ {
977 ctxt.AddInt(s, 1, 0)
978 }
979
980 case DW_FORM_flag:
981 if value != 0 {
982 ctxt.AddInt(s, 1, 1)
983 } else {
984 ctxt.AddInt(s, 1, 0)
985 }
986
987
988
989 case DW_FORM_ref_addr:
990 fallthrough
991 case DW_FORM_sec_offset:
992 if data == nil {
993 return fmt.Errorf("dwarf: null reference in %d", abbrev)
994 }
995 ctxt.AddDWARFAddrSectionOffset(s, data, value)
996
997 case DW_FORM_addrx:
998 ctxt.AddIndirectTextRef(s, data)
999
1000 case DW_FORM_ref1,
1001 DW_FORM_ref2,
1002 DW_FORM_ref4,
1003 DW_FORM_ref8,
1004 DW_FORM_ref_udata,
1005
1006 DW_FORM_strp,
1007 DW_FORM_indirect:
1008 fallthrough
1009 default:
1010 return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls)
1011 }
1012 return nil
1013 }
1014
1015
1016
1017
1018
1019 func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) {
1020 abbrevs := Abbrevs()
1021 Outer:
1022 for _, f := range abbrevs[abbrev].attr {
1023 for ap := attr; ap != nil; ap = ap.Link {
1024 if ap.Atr == f.attr {
1025 putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data)
1026 continue Outer
1027 }
1028 }
1029
1030 putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil)
1031 }
1032 }
1033
1034
1035 func HasChildren(die *DWDie) bool {
1036 abbrevs := Abbrevs()
1037 return abbrevs[die.Abbrev].children != 0
1038 }
1039
1040
1041 func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
1042 Uleb128put(ctxt, info, DW_ABRV_INT_CONSTANT)
1043 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1044 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1045 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
1046 }
1047
1048
1049 func PutGlobal(ctxt Context, info, typ, gvar Sym, name string) {
1050 Uleb128put(ctxt, info, DW_ABRV_VARIABLE)
1051 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1052 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_block1, DW_CLS_ADDRESS, 0, gvar)
1053 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1054 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_flag, DW_CLS_FLAG, 1, nil)
1055 }
1056
1057
1058
1059
1060 func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) {
1061 ps := ctxt.PtrSize()
1062
1063 for _, r := range ranges {
1064 ctxt.AddInt(sym, ps, r.Start)
1065 ctxt.AddInt(sym, ps, r.End)
1066 }
1067
1068 ctxt.AddInt(sym, ps, 0)
1069 ctxt.AddInt(sym, ps, 0)
1070 }
1071
1072
1073
1074 func PutRngListRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
1075 addULEB128 := func(v int64) {
1076 b := sevenBitU(v)
1077 if b == nil {
1078 var encbuf [20]byte
1079 b = AppendUleb128(encbuf[:0], uint64(v))
1080 }
1081 ctxt.AddBytes(sym, b)
1082 }
1083
1084 ctxt.AddInt(sym, 1, DW_RLE_base_addressx)
1085 ctxt.AddIndirectTextRef(sym, base)
1086
1087 for _, r := range ranges {
1088 ctxt.AddInt(sym, 1, DW_RLE_offset_pair)
1089 addULEB128(r.Start)
1090 addULEB128(r.End)
1091 }
1092
1093 ctxt.AddInt(sym, 1, DW_RLE_end_of_list)
1094 }
1095
1096
1097
1098 func (s *FnState) PutRanges(ctxt Context, ranges []Range) {
1099 ps := ctxt.PtrSize()
1100 sym, base := s.Ranges, s.StartPC
1101
1102 if buildcfg.Experiment.Dwarf5 {
1103 PutRngListRanges(ctxt, sym, base, ranges)
1104 return
1105 }
1106
1107 if s.UseBASEntries {
1108
1109
1110 ctxt.AddInt(sym, ps, -1)
1111 ctxt.AddAddress(sym, base, 0)
1112 PutBasedRanges(ctxt, sym, ranges)
1113 return
1114 }
1115
1116
1117 for _, r := range ranges {
1118 ctxt.AddCURelativeAddress(sym, base, r.Start)
1119 ctxt.AddCURelativeAddress(sym, base, r.End)
1120 }
1121
1122 ctxt.AddInt(sym, ps, 0)
1123 ctxt.AddInt(sym, ps, 0)
1124 }
1125
1126
1127
1128
1129 func isEmptyInlinedCall(slot int, calls *InlCalls) bool {
1130 ic := &calls.Calls[slot]
1131 if ic.InlIndex == -2 {
1132 return true
1133 }
1134 live := false
1135 for _, k := range ic.Children {
1136 if !isEmptyInlinedCall(k, calls) {
1137 live = true
1138 }
1139 }
1140 if len(ic.Ranges) > 0 {
1141 live = true
1142 }
1143 if !live {
1144 ic.InlIndex = -2
1145 }
1146 return !live
1147 }
1148
1149
1150
1151 func inlChildren(slot int, calls *InlCalls) []int {
1152 var kids []int
1153 if slot != -1 {
1154 for _, k := range calls.Calls[slot].Children {
1155 if !isEmptyInlinedCall(k, calls) {
1156 kids = append(kids, k)
1157 }
1158 }
1159 } else {
1160 for k := 0; k < len(calls.Calls); k += 1 {
1161 if calls.Calls[k].Root && !isEmptyInlinedCall(k, calls) {
1162 kids = append(kids, k)
1163 }
1164 }
1165 }
1166 return kids
1167 }
1168
1169 func inlinedVarTable(inlcalls *InlCalls) map[*Var]bool {
1170 vars := make(map[*Var]bool)
1171 for _, ic := range inlcalls.Calls {
1172 for _, v := range ic.InlVars {
1173 vars[v] = true
1174 }
1175 }
1176 return vars
1177 }
1178
1179
1180
1181
1182
1183
1184
1185 func putPrunedScopes(ctxt Context, s *FnState, fnabbrev int) error {
1186 if len(s.Scopes) == 0 {
1187 return nil
1188 }
1189 scopes := make([]Scope, len(s.Scopes), len(s.Scopes))
1190 pvars := inlinedVarTable(&s.InlCalls)
1191 for k, s := range s.Scopes {
1192 var pruned Scope = Scope{Parent: s.Parent, Ranges: s.Ranges}
1193 for i := 0; i < len(s.Vars); i++ {
1194 _, found := pvars[s.Vars[i]]
1195 if !found {
1196 pruned.Vars = append(pruned.Vars, s.Vars[i])
1197 }
1198 }
1199 slices.SortFunc(pruned.Vars, byChildIndexCmp)
1200 scopes[k] = pruned
1201 }
1202
1203 s.dictIndexToOffset = putparamtypes(ctxt, s, scopes, fnabbrev)
1204
1205 var encbuf [20]byte
1206 if putscope(ctxt, s, scopes, 0, fnabbrev, encbuf[:0]) < int32(len(scopes)) {
1207 return errors.New("multiple toplevel scopes")
1208 }
1209 return nil
1210 }
1211
1212
1213
1214
1215
1216
1217
1218
1219 func PutAbstractFunc(ctxt Context, s *FnState) error {
1220 if logDwarf {
1221 ctxt.Logf("PutAbstractFunc(%v)\n", s.Absfn)
1222 }
1223
1224 abbrev := DW_ABRV_FUNCTION_ABSTRACT
1225 Uleb128put(ctxt, s.Absfn, int64(abbrev))
1226
1227 fullname := s.Name
1228 if strings.HasPrefix(s.Name, `"".`) {
1229 return fmt.Errorf("unqualified symbol name: %v", s.Name)
1230 }
1231 putattr(ctxt, s.Absfn, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(fullname)), fullname)
1232
1233
1234 putattr(ctxt, s.Absfn, abbrev, DW_FORM_data1, DW_CLS_CONSTANT, int64(DW_INL_inlined), nil)
1235
1236
1237 putattr(ctxt, s.Absfn, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
1238
1239 var ev int64
1240 if s.External {
1241 ev = 1
1242 }
1243 putattr(ctxt, s.Absfn, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
1244
1245
1246 var flattened []*Var
1247
1248
1249
1250 var offsets []int32
1251
1252
1253 if len(s.Scopes) > 0 {
1254
1255
1256
1257 pvars := inlinedVarTable(&s.InlCalls)
1258 for _, scope := range s.Scopes {
1259 for i := 0; i < len(scope.Vars); i++ {
1260 _, found := pvars[scope.Vars[i]]
1261 if found || !scope.Vars[i].IsInAbstract {
1262 continue
1263 }
1264 flattened = append(flattened, scope.Vars[i])
1265 }
1266 }
1267 if len(flattened) > 0 {
1268 slices.SortFunc(flattened, byChildIndexCmp)
1269
1270 if logDwarf {
1271 ctxt.Logf("putAbstractScope(%v): vars:", s.Info)
1272 for i, v := range flattened {
1273 ctxt.Logf(" %d:%s", i, v.Name)
1274 }
1275 ctxt.Logf("\n")
1276 }
1277
1278
1279
1280
1281 for _, v := range flattened {
1282 offsets = append(offsets, int32(ctxt.CurrentOffset(s.Absfn)))
1283 putAbstractVar(ctxt, s.Absfn, v)
1284 }
1285 }
1286 }
1287 ctxt.RecordChildDieOffsets(s.Absfn, flattened, offsets)
1288
1289 Uleb128put(ctxt, s.Absfn, 0)
1290 return nil
1291 }
1292
1293
1294
1295 func dwarfFileIndex(pos src.Pos) int64 {
1296 return int64(1 + pos.FileIndex())
1297 }
1298
1299
1300
1301
1302
1303
1304 func putInlinedFunc(ctxt Context, s *FnState, callIdx int) error {
1305 ic := s.InlCalls.Calls[callIdx]
1306 callee := ic.AbsFunSym
1307
1308
1309
1310
1311 abbrev := DW_ABRV_INLINED_SUBROUTINE_RANGES
1312 if len(ic.Ranges) == 1 && !buildcfg.Experiment.Dwarf5 {
1313 abbrev = DW_ABRV_INLINED_SUBROUTINE
1314 }
1315 Uleb128put(ctxt, s.Info, int64(abbrev))
1316
1317 if logDwarf {
1318 ctxt.Logf("putInlinedFunc(callee=%v,abbrev=%d)\n", callee, abbrev)
1319 }
1320
1321
1322 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, callee)
1323
1324 if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES {
1325 putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Ranges), s.Ranges)
1326 s.PutRanges(ctxt, ic.Ranges)
1327 } else {
1328 st := ic.Ranges[0].Start
1329 en := ic.Ranges[0].End
1330 emitHiLoPc(ctxt, abbrev, s, st, en)
1331 }
1332
1333
1334 putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, dwarfFileIndex(ic.CallPos), nil)
1335 form := int(expandPseudoForm(DW_FORM_udata_pseudo))
1336 putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallPos.RelLine()), nil)
1337
1338
1339 vars := ic.InlVars
1340 slices.SortFunc(vars, byChildIndexCmp)
1341 inlIndex := ic.InlIndex
1342 var encbuf [20]byte
1343 for _, v := range vars {
1344 if !v.IsInAbstract {
1345 continue
1346 }
1347 putvar(ctxt, s, v, callee, abbrev, inlIndex, encbuf[:0])
1348 }
1349
1350
1351 for _, sib := range inlChildren(callIdx, &s.InlCalls) {
1352 err := putInlinedFunc(ctxt, s, sib)
1353 if err != nil {
1354 return err
1355 }
1356 }
1357
1358 Uleb128put(ctxt, s.Info, 0)
1359 return nil
1360 }
1361
1362 func emitHiLoPc(ctxt Context, abbrev int, fns *FnState, st int64, en int64) {
1363 if buildcfg.Experiment.Dwarf5 {
1364 putattr(ctxt, fns.Info, abbrev, DW_FORM_addrx, DW_CLS_CONSTANT, st, fns.StartPC)
1365 putattr(ctxt, fns.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, en, 0)
1366 } else {
1367 putattr(ctxt, fns.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, st, fns.StartPC)
1368 putattr(ctxt, fns.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, en, fns.StartPC)
1369 }
1370 }
1371
1372
1373
1374
1375
1376
1377
1378
1379 func PutConcreteFunc(ctxt Context, s *FnState, isWrapper bool, fncount int) error {
1380 if logDwarf {
1381 ctxt.Logf("PutConcreteFunc(%v)\n", s.Info)
1382 }
1383 abbrev := DW_ABRV_FUNCTION_CONCRETE
1384 if isWrapper {
1385 abbrev = DW_ABRV_WRAPPER_CONCRETE
1386 }
1387 Uleb128put(ctxt, s.Info, int64(abbrev))
1388
1389
1390 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, s.Absfn)
1391
1392
1393 emitHiLoPc(ctxt, abbrev, s, 0, s.Size)
1394
1395
1396 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
1397
1398 if isWrapper {
1399 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
1400 }
1401
1402
1403 if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
1404 return err
1405 }
1406
1407
1408 for _, sib := range inlChildren(-1, &s.InlCalls) {
1409 err := putInlinedFunc(ctxt, s, sib)
1410 if err != nil {
1411 return err
1412 }
1413 }
1414
1415 Uleb128put(ctxt, s.Info, 0)
1416 return nil
1417 }
1418
1419
1420
1421
1422
1423
1424 func PutDefaultFunc(ctxt Context, s *FnState, isWrapper bool) error {
1425 if logDwarf {
1426 ctxt.Logf("PutDefaultFunc(%v)\n", s.Info)
1427 }
1428 abbrev := DW_ABRV_FUNCTION
1429 if isWrapper {
1430 abbrev = DW_ABRV_WRAPPER
1431 }
1432 Uleb128put(ctxt, s.Info, int64(abbrev))
1433
1434 name := s.Name
1435 if strings.HasPrefix(name, `"".`) {
1436 return fmt.Errorf("unqualified symbol name: %v", name)
1437 }
1438
1439 putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1440 emitHiLoPc(ctxt, abbrev, s, 0, s.Size)
1441 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
1442 if isWrapper {
1443 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
1444 } else {
1445 putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, dwarfFileIndex(s.StartPos), nil)
1446 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
1447
1448 var ev int64
1449 if s.External {
1450 ev = 1
1451 }
1452 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
1453 }
1454
1455
1456 if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
1457 return err
1458 }
1459
1460
1461 for _, sib := range inlChildren(-1, &s.InlCalls) {
1462 err := putInlinedFunc(ctxt, s, sib)
1463 if err != nil {
1464 return err
1465 }
1466 }
1467
1468 Uleb128put(ctxt, s.Info, 0)
1469 return nil
1470 }
1471
1472
1473 func putparamtypes(ctxt Context, s *FnState, scopes []Scope, fnabbrev int) []int64 {
1474 if fnabbrev == DW_ABRV_FUNCTION_CONCRETE {
1475 return nil
1476 }
1477
1478 maxDictIndex := uint16(0)
1479
1480 for i := range scopes {
1481 for _, v := range scopes[i].Vars {
1482 if v.DictIndex > maxDictIndex {
1483 maxDictIndex = v.DictIndex
1484 }
1485 }
1486 }
1487
1488 if maxDictIndex == 0 {
1489 return nil
1490 }
1491
1492 dictIndexToOffset := make([]int64, maxDictIndex)
1493
1494 for i := range scopes {
1495 for _, v := range scopes[i].Vars {
1496 if v.DictIndex == 0 || dictIndexToOffset[v.DictIndex-1] != 0 {
1497 continue
1498 }
1499
1500 dictIndexToOffset[v.DictIndex-1] = ctxt.CurrentOffset(s.Info)
1501
1502 Uleb128put(ctxt, s.Info, int64(DW_ABRV_DICT_INDEX))
1503 n := fmt.Sprintf(".param%d", v.DictIndex-1)
1504 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
1505 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1506 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DictIndex-1), nil)
1507 }
1508 }
1509
1510 return dictIndexToOffset
1511 }
1512
1513 func putscope(ctxt Context, s *FnState, scopes []Scope, curscope int32, fnabbrev int, encbuf []byte) int32 {
1514
1515 if logDwarf {
1516 ctxt.Logf("putscope(%v,%d): vars:", s.Info, curscope)
1517 for i, v := range scopes[curscope].Vars {
1518 ctxt.Logf(" %d:%d:%s", i, v.ChildIndex, v.Name)
1519 }
1520 ctxt.Logf("\n")
1521 }
1522
1523 for _, v := range scopes[curscope].Vars {
1524 putvar(ctxt, s, v, s.Absfn, fnabbrev, -1, encbuf)
1525 }
1526 this := curscope
1527 curscope++
1528 for curscope < int32(len(scopes)) {
1529 scope := scopes[curscope]
1530 if scope.Parent != this {
1531 return curscope
1532 }
1533
1534 if len(scopes[curscope].Vars) == 0 {
1535 curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
1536 continue
1537 }
1538
1539
1540
1541
1542 if len(scope.Ranges) == 1 && !buildcfg.Experiment.Dwarf5 {
1543 Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
1544 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, s.StartPC)
1545 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, s.StartPC)
1546 } else {
1547 Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES)
1548 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Ranges), s.Ranges)
1549
1550 s.PutRanges(ctxt, scope.Ranges)
1551 }
1552
1553 curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
1554
1555 Uleb128put(ctxt, s.Info, 0)
1556 }
1557 return curscope
1558 }
1559
1560 func concreteVar(fnabbrev int, v *Var) bool {
1561 concrete := true
1562 switch fnabbrev {
1563 case DW_ABRV_FUNCTION, DW_ABRV_WRAPPER:
1564 concrete = false
1565 case DW_ABRV_FUNCTION_CONCRETE, DW_ABRV_WRAPPER_CONCRETE:
1566
1567
1568
1569 if !v.IsInAbstract {
1570 concrete = false
1571 }
1572 case DW_ABRV_INLINED_SUBROUTINE, DW_ABRV_INLINED_SUBROUTINE_RANGES:
1573 default:
1574 panic("should never happen")
1575 }
1576 return concrete
1577 }
1578
1579
1580 func putAbstractVar(ctxt Context, info Sym, v *Var) {
1581
1582 abbrev := putAbstractVarAbbrev(v)
1583 Uleb128put(ctxt, info, int64(abbrev))
1584 putattr(ctxt, info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(v.Name)), v.Name)
1585
1586
1587 if v.Tag == DW_TAG_formal_parameter {
1588 var isReturn int64
1589 if v.IsReturnValue {
1590 isReturn = 1
1591 }
1592 putattr(ctxt, info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
1593 }
1594
1595
1596 if v.Tag == DW_TAG_variable {
1597
1598 putattr(ctxt, info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
1599 }
1600
1601
1602 putattr(ctxt, info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1603
1604
1605 }
1606
1607 func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int, encbuf []byte) {
1608
1609 concrete := concreteVar(fnabbrev, v)
1610 hasParametricType := !concrete && (v.DictIndex > 0 && s.dictIndexToOffset != nil && s.dictIndexToOffset[v.DictIndex-1] != 0)
1611 withLoclist := v.WithLoclist && v.PutLocationList != nil
1612
1613 abbrev := putvarAbbrev(v, concrete, withLoclist)
1614 Uleb128put(ctxt, s.Info, int64(abbrev))
1615
1616
1617 if concrete {
1618
1619
1620
1621
1622 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, absfn)
1623 ctxt.RecordDclReference(s.Info, absfn, int(v.ChildIndex), inlIndex)
1624 } else {
1625
1626 n := v.Name
1627 putattr(ctxt, s.Info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
1628 if v.Tag == DW_TAG_formal_parameter {
1629 var isReturn int64
1630 if v.IsReturnValue {
1631 isReturn = 1
1632 }
1633 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
1634 }
1635 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
1636 if hasParametricType {
1637
1638 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, s.dictIndexToOffset[v.DictIndex-1], s.Info)
1639 } else {
1640 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1641 }
1642
1643 if v.ClosureOffset > 0 {
1644 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, v.ClosureOffset, nil)
1645 }
1646 }
1647
1648 if withLoclist {
1649 putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Loc), s.Loc)
1650 v.PutLocationList(s.Loc, s.StartPC)
1651 } else {
1652 loc := encbuf[:0]
1653 switch {
1654 case v.WithLoclist:
1655 break
1656 case v.StackOffset == 0:
1657 loc = append(loc, DW_OP_call_frame_cfa)
1658 default:
1659 loc = append(loc, DW_OP_fbreg)
1660 loc = AppendSleb128(loc, int64(v.StackOffset))
1661 }
1662 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
1663 }
1664
1665
1666 }
1667
1668
1669 func byChildIndexCmp(a, b *Var) int { return cmp.Compare(a.ChildIndex, b.ChildIndex) }
1670
1671
1672
1673
1674
1675 func IsDWARFEnabledOnAIXLd(extld []string) (bool, error) {
1676 name, args := extld[0], extld[1:]
1677 args = append(args, "-Wl,-V")
1678 out, err := exec.Command(name, args...).CombinedOutput()
1679 if err != nil {
1680
1681
1682
1683 if !bytes.Contains(out, []byte("0711-317")) {
1684 return false, fmt.Errorf("%s -Wl,-V failed: %v\n%s", extld, err, out)
1685 }
1686 }
1687
1688
1689
1690 out = bytes.TrimPrefix(out, []byte("/usr/bin/ld: LD "))
1691 vers := string(bytes.Split(out, []byte("("))[0])
1692 subvers := strings.Split(vers, ".")
1693 if len(subvers) != 3 {
1694 return false, fmt.Errorf("cannot parse %s -Wl,-V (%s): %v\n", extld, out, err)
1695 }
1696 if v, err := strconv.Atoi(subvers[0]); err != nil || v < 7 {
1697 return false, nil
1698 } else if v > 7 {
1699 return true, nil
1700 }
1701 if v, err := strconv.Atoi(subvers[1]); err != nil || v < 2 {
1702 return false, nil
1703 } else if v > 2 {
1704 return true, nil
1705 }
1706 if v, err := strconv.Atoi(subvers[2]); err != nil || v < 2 {
1707 return false, nil
1708 }
1709 return true, nil
1710 }
1711
View as plain text