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_PUTVAR_START
360 )
361
362 type dwAbbrev struct {
363 tag uint8
364 children uint8
365 attr []dwAttrForm
366 }
367
368 var abbrevsFinalized bool
369
370
371
372
373
374
375
376
377
378
379 func expandPseudoForm(form uint8) uint8 {
380 switch form {
381 case DW_FORM_udata_pseudo:
382 expandedForm := DW_FORM_udata
383 if buildcfg.GOOS == "darwin" || buildcfg.GOOS == "ios" {
384 expandedForm = DW_FORM_data4
385 }
386 return uint8(expandedForm)
387 case DW_FORM_lo_pc_pseudo:
388 if buildcfg.Experiment.Dwarf5 {
389 return DW_FORM_addrx
390 }
391 return DW_FORM_addr
392 case DW_FORM_hi_pc_pseudo:
393 if buildcfg.Experiment.Dwarf5 {
394 return DW_FORM_udata
395 }
396 return DW_FORM_addr
397 default:
398 return form
399 }
400 }
401
402
403
404 func Abbrevs() []dwAbbrev {
405 if abbrevsFinalized {
406 return abbrevs
407 }
408 abbrevs = append(abbrevs, putvarAbbrevs...)
409 for i := 1; i < len(abbrevs); i++ {
410 for j := 0; j < len(abbrevs[i].attr); j++ {
411 abbrevs[i].attr[j].form = expandPseudoForm(abbrevs[i].attr[j].form)
412 }
413 }
414 if buildcfg.Experiment.Dwarf5 {
415
416
417
418
419 for i := 1; i < len(abbrevs); i++ {
420 haveLo := false
421 for j := 0; j < len(abbrevs[i].attr); j++ {
422 if abbrevs[i].attr[j].attr == DW_AT_low_pc {
423 haveLo = true
424 }
425 }
426 if abbrevs[i].tag == DW_TAG_compile_unit && haveLo {
427 abbrevs[i].attr = append(abbrevs[i].attr,
428 dwAttrForm{DW_AT_addr_base, DW_FORM_sec_offset})
429 }
430 }
431 }
432
433 abbrevsFinalized = true
434 return abbrevs
435 }
436
437
438
439
440
441 var abbrevs = []dwAbbrev{
442
443 {0, 0, []dwAttrForm{}},
444
445
446 {
447 DW_TAG_compile_unit,
448 DW_CHILDREN_yes,
449 []dwAttrForm{
450 {DW_AT_name, DW_FORM_string},
451 {DW_AT_language, DW_FORM_data1},
452 {DW_AT_stmt_list, DW_FORM_sec_offset},
453 {DW_AT_low_pc, DW_FORM_addr},
454 {DW_AT_ranges, DW_FORM_sec_offset},
455 {DW_AT_comp_dir, DW_FORM_string},
456 {DW_AT_producer, DW_FORM_string},
457 {DW_AT_go_package_name, DW_FORM_string},
458
459 },
460 },
461
462
463 {
464 DW_TAG_compile_unit,
465 DW_CHILDREN_yes,
466 []dwAttrForm{
467 {DW_AT_name, DW_FORM_string},
468 {DW_AT_language, DW_FORM_data1},
469 {DW_AT_comp_dir, DW_FORM_string},
470 {DW_AT_producer, DW_FORM_string},
471 {DW_AT_go_package_name, DW_FORM_string},
472 },
473 },
474
475
476 {
477 DW_TAG_subprogram,
478 DW_CHILDREN_yes,
479 []dwAttrForm{
480 {DW_AT_name, DW_FORM_string},
481 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
482 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
483 {DW_AT_frame_base, DW_FORM_block1},
484 {DW_AT_decl_file, DW_FORM_data4},
485 {DW_AT_decl_line, DW_FORM_udata},
486 {DW_AT_external, DW_FORM_flag},
487 },
488 },
489
490
491 {
492 DW_TAG_subprogram,
493 DW_CHILDREN_yes,
494 []dwAttrForm{
495 {DW_AT_name, DW_FORM_string},
496 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
497 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
498 {DW_AT_frame_base, DW_FORM_block1},
499 {DW_AT_trampoline, DW_FORM_flag},
500 },
501 },
502
503
504 {
505 DW_TAG_subprogram,
506 DW_CHILDREN_yes,
507 []dwAttrForm{
508 {DW_AT_name, DW_FORM_string},
509 {DW_AT_inline, DW_FORM_data1},
510 {DW_AT_decl_line, DW_FORM_udata},
511 {DW_AT_external, DW_FORM_flag},
512 },
513 },
514
515
516 {
517 DW_TAG_subprogram,
518 DW_CHILDREN_yes,
519 []dwAttrForm{
520 {DW_AT_abstract_origin, DW_FORM_ref_addr},
521 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
522 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
523 {DW_AT_frame_base, DW_FORM_block1},
524 },
525 },
526
527
528 {
529 DW_TAG_subprogram,
530 DW_CHILDREN_yes,
531 []dwAttrForm{
532 {DW_AT_abstract_origin, DW_FORM_ref_addr},
533 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
534 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
535 {DW_AT_frame_base, DW_FORM_block1},
536 {DW_AT_trampoline, DW_FORM_flag},
537 },
538 },
539
540
541 {
542 DW_TAG_inlined_subroutine,
543 DW_CHILDREN_yes,
544 []dwAttrForm{
545 {DW_AT_abstract_origin, DW_FORM_ref_addr},
546 {DW_AT_low_pc, DW_FORM_lo_pc_pseudo},
547 {DW_AT_high_pc, DW_FORM_hi_pc_pseudo},
548 {DW_AT_call_file, DW_FORM_data4},
549 {DW_AT_call_line, DW_FORM_udata_pseudo},
550 },
551 },
552
553
554 {
555 DW_TAG_inlined_subroutine,
556 DW_CHILDREN_yes,
557 []dwAttrForm{
558 {DW_AT_abstract_origin, DW_FORM_ref_addr},
559 {DW_AT_ranges, DW_FORM_sec_offset},
560 {DW_AT_call_file, DW_FORM_data4},
561 {DW_AT_call_line, DW_FORM_udata_pseudo},
562 },
563 },
564
565
566 {
567 DW_TAG_variable,
568 DW_CHILDREN_no,
569 []dwAttrForm{
570 {DW_AT_name, DW_FORM_string},
571 {DW_AT_location, DW_FORM_block1},
572 {DW_AT_type, DW_FORM_ref_addr},
573 {DW_AT_external, DW_FORM_flag},
574 },
575 },
576
577
578 {
579 DW_TAG_constant,
580 DW_CHILDREN_no,
581 []dwAttrForm{
582 {DW_AT_name, DW_FORM_string},
583 {DW_AT_type, DW_FORM_ref_addr},
584 {DW_AT_const_value, DW_FORM_sdata},
585 },
586 },
587
588
589 {
590 DW_TAG_lexical_block,
591 DW_CHILDREN_yes,
592 []dwAttrForm{
593 {DW_AT_ranges, DW_FORM_sec_offset},
594 },
595 },
596
597
598 {
599 DW_TAG_lexical_block,
600 DW_CHILDREN_yes,
601 []dwAttrForm{
602
603
604 {DW_AT_low_pc, DW_FORM_addr},
605 {DW_AT_high_pc, DW_FORM_addr},
606 },
607 },
608
609
610 {
611 DW_TAG_member,
612 DW_CHILDREN_no,
613
614
615 []dwAttrForm{
616 {DW_AT_name, DW_FORM_string},
617 {DW_AT_data_member_location, DW_FORM_udata},
618 {DW_AT_type, DW_FORM_ref_addr},
619 {DW_AT_go_embedded_field, DW_FORM_flag},
620 },
621 },
622
623
624 {
625 DW_TAG_formal_parameter,
626 DW_CHILDREN_no,
627
628
629
630
631 []dwAttrForm{
632 {DW_AT_type, DW_FORM_ref_addr},
633 },
634 },
635
636
637 {
638 DW_TAG_formal_parameter,
639 DW_CHILDREN_no,
640
641
642
643
644 []dwAttrForm{
645 {DW_AT_variable_parameter, DW_FORM_flag},
646 {DW_AT_type, DW_FORM_ref_addr},
647 },
648 },
649
650
651 {
652 DW_TAG_unspecified_parameters,
653 DW_CHILDREN_no,
654
655
656
657 []dwAttrForm{},
658 },
659
660
661 {
662 DW_TAG_subrange_type,
663 DW_CHILDREN_no,
664
665
666
667
668 []dwAttrForm{
669 {DW_AT_type, DW_FORM_ref_addr},
670 {DW_AT_count, DW_FORM_udata},
671 },
672 },
673
674
675
676 {
677 DW_TAG_unspecified_type,
678 DW_CHILDREN_no,
679 []dwAttrForm{
680 {DW_AT_name, DW_FORM_string},
681 },
682 },
683
684
685 {
686 DW_TAG_base_type,
687 DW_CHILDREN_no,
688 []dwAttrForm{
689 {DW_AT_name, DW_FORM_string},
690 {DW_AT_encoding, DW_FORM_data1},
691 {DW_AT_byte_size, DW_FORM_data1},
692 {DW_AT_go_kind, DW_FORM_data1},
693 {DW_AT_go_runtime_type, DW_FORM_addr},
694 },
695 },
696
697
698
699 {
700 DW_TAG_array_type,
701 DW_CHILDREN_yes,
702 []dwAttrForm{
703 {DW_AT_name, DW_FORM_string},
704 {DW_AT_type, DW_FORM_ref_addr},
705 {DW_AT_byte_size, DW_FORM_udata},
706 {DW_AT_go_kind, DW_FORM_data1},
707 {DW_AT_go_runtime_type, DW_FORM_addr},
708 },
709 },
710
711
712 {
713 DW_TAG_typedef,
714 DW_CHILDREN_no,
715 []dwAttrForm{
716 {DW_AT_name, DW_FORM_string},
717 {DW_AT_type, DW_FORM_ref_addr},
718 {DW_AT_go_kind, DW_FORM_data1},
719 {DW_AT_go_runtime_type, DW_FORM_addr},
720 {DW_AT_go_elem, DW_FORM_ref_addr},
721 },
722 },
723
724
725 {
726 DW_TAG_subroutine_type,
727 DW_CHILDREN_yes,
728 []dwAttrForm{
729 {DW_AT_name, DW_FORM_string},
730 {DW_AT_byte_size, DW_FORM_udata},
731 {DW_AT_go_kind, DW_FORM_data1},
732 {DW_AT_go_runtime_type, DW_FORM_addr},
733 },
734 },
735
736
737 {
738 DW_TAG_typedef,
739 DW_CHILDREN_yes,
740 []dwAttrForm{
741 {DW_AT_name, DW_FORM_string},
742 {DW_AT_type, DW_FORM_ref_addr},
743 {DW_AT_go_kind, DW_FORM_data1},
744 {DW_AT_go_runtime_type, DW_FORM_addr},
745 },
746 },
747
748
749 {
750 DW_TAG_typedef,
751 DW_CHILDREN_no,
752 []dwAttrForm{
753 {DW_AT_name, DW_FORM_string},
754 {DW_AT_type, DW_FORM_ref_addr},
755 {DW_AT_go_kind, DW_FORM_data1},
756 {DW_AT_go_runtime_type, DW_FORM_addr},
757 {DW_AT_go_key, DW_FORM_ref_addr},
758 {DW_AT_go_elem, DW_FORM_ref_addr},
759 },
760 },
761
762
763 {
764 DW_TAG_pointer_type,
765 DW_CHILDREN_no,
766 []dwAttrForm{
767 {DW_AT_name, DW_FORM_string},
768 {DW_AT_type, DW_FORM_ref_addr},
769 {DW_AT_go_kind, DW_FORM_data1},
770 {DW_AT_go_runtime_type, DW_FORM_addr},
771 },
772 },
773
774
775 {
776 DW_TAG_pointer_type,
777 DW_CHILDREN_no,
778 []dwAttrForm{
779 {DW_AT_name, DW_FORM_string},
780 {DW_AT_go_runtime_type, DW_FORM_addr},
781 },
782 },
783
784
785 {
786 DW_TAG_structure_type,
787 DW_CHILDREN_yes,
788 []dwAttrForm{
789 {DW_AT_name, DW_FORM_string},
790 {DW_AT_byte_size, DW_FORM_udata},
791 {DW_AT_go_kind, DW_FORM_data1},
792 {DW_AT_go_runtime_type, DW_FORM_addr},
793 {DW_AT_go_elem, DW_FORM_ref_addr},
794 },
795 },
796
797
798 {
799 DW_TAG_structure_type,
800 DW_CHILDREN_yes,
801 []dwAttrForm{
802 {DW_AT_name, DW_FORM_string},
803 {DW_AT_byte_size, DW_FORM_udata},
804 {DW_AT_go_kind, DW_FORM_data1},
805 {DW_AT_go_runtime_type, DW_FORM_addr},
806 },
807 },
808
809
810 {
811 DW_TAG_structure_type,
812 DW_CHILDREN_yes,
813 []dwAttrForm{
814 {DW_AT_name, DW_FORM_string},
815 {DW_AT_byte_size, DW_FORM_udata},
816 {DW_AT_go_kind, DW_FORM_data1},
817 {DW_AT_go_runtime_type, DW_FORM_addr},
818 },
819 },
820
821
822 {
823 DW_TAG_typedef,
824 DW_CHILDREN_no,
825 []dwAttrForm{
826 {DW_AT_name, DW_FORM_string},
827 {DW_AT_type, DW_FORM_ref_addr},
828 },
829 },
830
831
832 {
833 DW_TAG_typedef,
834 DW_CHILDREN_no,
835 []dwAttrForm{
836 {DW_AT_name, DW_FORM_string},
837 {DW_AT_type, DW_FORM_ref_addr},
838 {DW_AT_go_dict_index, DW_FORM_udata},
839 },
840 },
841 }
842
843
844 func GetAbbrev() []byte {
845 abbrevs := Abbrevs()
846 var buf []byte
847 for i := 1; i < len(abbrevs); i++ {
848
849 buf = AppendUleb128(buf, uint64(i))
850 buf = AppendUleb128(buf, uint64(abbrevs[i].tag))
851 buf = append(buf, abbrevs[i].children)
852 for _, f := range abbrevs[i].attr {
853 buf = AppendUleb128(buf, uint64(f.attr))
854 buf = AppendUleb128(buf, uint64(f.form))
855 }
856 buf = append(buf, 0, 0)
857 }
858 return append(buf, 0)
859 }
860
861
864
865
866
867
868
869
870
871 type DWAttr struct {
872 Link *DWAttr
873 Atr uint16
874 Cls uint8
875 Value int64
876 Data any
877 }
878
879
880 type DWDie struct {
881 Abbrev int
882 Link *DWDie
883 Child *DWDie
884 Attr *DWAttr
885 Sym Sym
886 }
887
888 func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data any) error {
889 switch form {
890 case DW_FORM_addr:
891
892 if data == nil && value == 0 {
893 ctxt.AddInt(s, ctxt.PtrSize(), 0)
894 break
895 }
896 if cls == DW_CLS_GO_TYPEREF {
897 ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, value)
898 break
899 }
900 ctxt.AddAddress(s, data, value)
901
902 case DW_FORM_block1:
903 if cls == DW_CLS_ADDRESS {
904 ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize()))
905 ctxt.AddInt(s, 1, DW_OP_addr)
906 ctxt.AddAddress(s, data, 0)
907 break
908 }
909
910 value &= 0xff
911 ctxt.AddInt(s, 1, value)
912 p := data.([]byte)[:value]
913 ctxt.AddBytes(s, p)
914
915 case DW_FORM_block2:
916 value &= 0xffff
917
918 ctxt.AddInt(s, 2, value)
919 p := data.([]byte)[:value]
920 ctxt.AddBytes(s, p)
921
922 case DW_FORM_block4:
923 value &= 0xffffffff
924
925 ctxt.AddInt(s, 4, value)
926 p := data.([]byte)[:value]
927 ctxt.AddBytes(s, p)
928
929 case DW_FORM_block:
930 Uleb128put(ctxt, s, value)
931
932 p := data.([]byte)[:value]
933 ctxt.AddBytes(s, p)
934
935 case DW_FORM_data1:
936 ctxt.AddInt(s, 1, value)
937
938 case DW_FORM_data2:
939 ctxt.AddInt(s, 2, value)
940
941 case DW_FORM_data4:
942 if cls == DW_CLS_PTR {
943 ctxt.AddDWARFAddrSectionOffset(s, data, value)
944 break
945 }
946 ctxt.AddInt(s, 4, value)
947
948 case DW_FORM_data8:
949 ctxt.AddInt(s, 8, value)
950
951 case DW_FORM_sdata:
952 Sleb128put(ctxt, s, value)
953
954 case DW_FORM_udata:
955 Uleb128put(ctxt, s, value)
956
957 case DW_FORM_string:
958 str := data.(string)
959 ctxt.AddString(s, str)
960
961 for i := int64(len(str)); i < value; i++ {
962 ctxt.AddInt(s, 1, 0)
963 }
964
965 case DW_FORM_flag:
966 if value != 0 {
967 ctxt.AddInt(s, 1, 1)
968 } else {
969 ctxt.AddInt(s, 1, 0)
970 }
971
972
973
974 case DW_FORM_ref_addr:
975 fallthrough
976 case DW_FORM_sec_offset:
977 if data == nil {
978 return fmt.Errorf("dwarf: null reference in %d", abbrev)
979 }
980 ctxt.AddDWARFAddrSectionOffset(s, data, value)
981
982 case DW_FORM_addrx:
983 ctxt.AddIndirectTextRef(s, data)
984
985 case DW_FORM_ref1,
986 DW_FORM_ref2,
987 DW_FORM_ref4,
988 DW_FORM_ref8,
989 DW_FORM_ref_udata,
990
991 DW_FORM_strp,
992 DW_FORM_indirect:
993 fallthrough
994 default:
995 return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls)
996 }
997 return nil
998 }
999
1000
1001
1002
1003
1004 func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) {
1005 abbrevs := Abbrevs()
1006 Outer:
1007 for _, f := range abbrevs[abbrev].attr {
1008 for ap := attr; ap != nil; ap = ap.Link {
1009 if ap.Atr == f.attr {
1010 putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data)
1011 continue Outer
1012 }
1013 }
1014
1015 putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil)
1016 }
1017 }
1018
1019
1020 func HasChildren(die *DWDie) bool {
1021 abbrevs := Abbrevs()
1022 return abbrevs[die.Abbrev].children != 0
1023 }
1024
1025
1026 func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
1027 Uleb128put(ctxt, info, DW_ABRV_INT_CONSTANT)
1028 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1029 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1030 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
1031 }
1032
1033
1034 func PutGlobal(ctxt Context, info, typ, gvar Sym, name string) {
1035 Uleb128put(ctxt, info, DW_ABRV_VARIABLE)
1036 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1037 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_block1, DW_CLS_ADDRESS, 0, gvar)
1038 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1039 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_flag, DW_CLS_FLAG, 1, nil)
1040 }
1041
1042
1043
1044
1045 func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) {
1046 ps := ctxt.PtrSize()
1047
1048 for _, r := range ranges {
1049 ctxt.AddInt(sym, ps, r.Start)
1050 ctxt.AddInt(sym, ps, r.End)
1051 }
1052
1053 ctxt.AddInt(sym, ps, 0)
1054 ctxt.AddInt(sym, ps, 0)
1055 }
1056
1057
1058
1059 func PutRngListRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
1060 addULEB128 := func(v int64) {
1061 b := sevenBitU(v)
1062 if b == nil {
1063 var encbuf [20]byte
1064 b = AppendUleb128(encbuf[:0], uint64(v))
1065 }
1066 ctxt.AddBytes(sym, b)
1067 }
1068
1069 ctxt.AddInt(sym, 1, DW_RLE_base_addressx)
1070 ctxt.AddIndirectTextRef(sym, base)
1071
1072 for _, r := range ranges {
1073 ctxt.AddInt(sym, 1, DW_RLE_offset_pair)
1074 addULEB128(r.Start)
1075 addULEB128(r.End)
1076 }
1077
1078 ctxt.AddInt(sym, 1, DW_RLE_end_of_list)
1079 }
1080
1081
1082
1083 func (s *FnState) PutRanges(ctxt Context, ranges []Range) {
1084 ps := ctxt.PtrSize()
1085 sym, base := s.Ranges, s.StartPC
1086
1087 if buildcfg.Experiment.Dwarf5 {
1088 PutRngListRanges(ctxt, sym, base, ranges)
1089 return
1090 }
1091
1092 if s.UseBASEntries {
1093
1094
1095 ctxt.AddInt(sym, ps, -1)
1096 ctxt.AddAddress(sym, base, 0)
1097 PutBasedRanges(ctxt, sym, ranges)
1098 return
1099 }
1100
1101
1102 for _, r := range ranges {
1103 ctxt.AddCURelativeAddress(sym, base, r.Start)
1104 ctxt.AddCURelativeAddress(sym, base, r.End)
1105 }
1106
1107 ctxt.AddInt(sym, ps, 0)
1108 ctxt.AddInt(sym, ps, 0)
1109 }
1110
1111
1112
1113
1114 func isEmptyInlinedCall(slot int, calls *InlCalls) bool {
1115 ic := &calls.Calls[slot]
1116 if ic.InlIndex == -2 {
1117 return true
1118 }
1119 live := false
1120 for _, k := range ic.Children {
1121 if !isEmptyInlinedCall(k, calls) {
1122 live = true
1123 }
1124 }
1125 if len(ic.Ranges) > 0 {
1126 live = true
1127 }
1128 if !live {
1129 ic.InlIndex = -2
1130 }
1131 return !live
1132 }
1133
1134
1135
1136 func inlChildren(slot int, calls *InlCalls) []int {
1137 var kids []int
1138 if slot != -1 {
1139 for _, k := range calls.Calls[slot].Children {
1140 if !isEmptyInlinedCall(k, calls) {
1141 kids = append(kids, k)
1142 }
1143 }
1144 } else {
1145 for k := 0; k < len(calls.Calls); k += 1 {
1146 if calls.Calls[k].Root && !isEmptyInlinedCall(k, calls) {
1147 kids = append(kids, k)
1148 }
1149 }
1150 }
1151 return kids
1152 }
1153
1154 func inlinedVarTable(inlcalls *InlCalls) map[*Var]bool {
1155 vars := make(map[*Var]bool)
1156 for _, ic := range inlcalls.Calls {
1157 for _, v := range ic.InlVars {
1158 vars[v] = true
1159 }
1160 }
1161 return vars
1162 }
1163
1164
1165
1166
1167
1168
1169
1170 func putPrunedScopes(ctxt Context, s *FnState, fnabbrev int) error {
1171 if len(s.Scopes) == 0 {
1172 return nil
1173 }
1174 scopes := make([]Scope, len(s.Scopes), len(s.Scopes))
1175 pvars := inlinedVarTable(&s.InlCalls)
1176 for k, s := range s.Scopes {
1177 var pruned Scope = Scope{Parent: s.Parent, Ranges: s.Ranges}
1178 for i := 0; i < len(s.Vars); i++ {
1179 _, found := pvars[s.Vars[i]]
1180 if !found {
1181 pruned.Vars = append(pruned.Vars, s.Vars[i])
1182 }
1183 }
1184 slices.SortFunc(pruned.Vars, byChildIndexCmp)
1185 scopes[k] = pruned
1186 }
1187
1188 s.dictIndexToOffset = putparamtypes(ctxt, s, scopes, fnabbrev)
1189
1190 var encbuf [20]byte
1191 if putscope(ctxt, s, scopes, 0, fnabbrev, encbuf[:0]) < int32(len(scopes)) {
1192 return errors.New("multiple toplevel scopes")
1193 }
1194 return nil
1195 }
1196
1197
1198
1199
1200
1201
1202
1203
1204 func PutAbstractFunc(ctxt Context, s *FnState) error {
1205 if logDwarf {
1206 ctxt.Logf("PutAbstractFunc(%v)\n", s.Absfn)
1207 }
1208
1209 abbrev := DW_ABRV_FUNCTION_ABSTRACT
1210 Uleb128put(ctxt, s.Absfn, int64(abbrev))
1211
1212 fullname := s.Name
1213 if strings.HasPrefix(s.Name, `"".`) {
1214 return fmt.Errorf("unqualified symbol name: %v", s.Name)
1215 }
1216 putattr(ctxt, s.Absfn, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(fullname)), fullname)
1217
1218
1219 putattr(ctxt, s.Absfn, abbrev, DW_FORM_data1, DW_CLS_CONSTANT, int64(DW_INL_inlined), nil)
1220
1221
1222 putattr(ctxt, s.Absfn, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
1223
1224 var ev int64
1225 if s.External {
1226 ev = 1
1227 }
1228 putattr(ctxt, s.Absfn, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
1229
1230
1231 var flattened []*Var
1232
1233
1234
1235 var offsets []int32
1236
1237
1238 if len(s.Scopes) > 0 {
1239
1240
1241
1242 pvars := inlinedVarTable(&s.InlCalls)
1243 for _, scope := range s.Scopes {
1244 for i := 0; i < len(scope.Vars); i++ {
1245 _, found := pvars[scope.Vars[i]]
1246 if found || !scope.Vars[i].IsInAbstract {
1247 continue
1248 }
1249 flattened = append(flattened, scope.Vars[i])
1250 }
1251 }
1252 if len(flattened) > 0 {
1253 slices.SortFunc(flattened, byChildIndexCmp)
1254
1255 if logDwarf {
1256 ctxt.Logf("putAbstractScope(%v): vars:", s.Info)
1257 for i, v := range flattened {
1258 ctxt.Logf(" %d:%s", i, v.Name)
1259 }
1260 ctxt.Logf("\n")
1261 }
1262
1263
1264
1265
1266 for _, v := range flattened {
1267 offsets = append(offsets, int32(ctxt.CurrentOffset(s.Absfn)))
1268 putAbstractVar(ctxt, s.Absfn, v)
1269 }
1270 }
1271 }
1272 ctxt.RecordChildDieOffsets(s.Absfn, flattened, offsets)
1273
1274 Uleb128put(ctxt, s.Absfn, 0)
1275 return nil
1276 }
1277
1278
1279
1280 func dwarfFileIndex(pos src.Pos) int64 {
1281 return int64(1 + pos.FileIndex())
1282 }
1283
1284
1285
1286
1287
1288
1289 func putInlinedFunc(ctxt Context, s *FnState, callIdx int) error {
1290 ic := s.InlCalls.Calls[callIdx]
1291 callee := ic.AbsFunSym
1292
1293
1294
1295
1296 abbrev := DW_ABRV_INLINED_SUBROUTINE_RANGES
1297 if len(ic.Ranges) == 1 && !buildcfg.Experiment.Dwarf5 {
1298 abbrev = DW_ABRV_INLINED_SUBROUTINE
1299 }
1300 Uleb128put(ctxt, s.Info, int64(abbrev))
1301
1302 if logDwarf {
1303 ctxt.Logf("putInlinedFunc(callee=%v,abbrev=%d)\n", callee, abbrev)
1304 }
1305
1306
1307 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, callee)
1308
1309 if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES {
1310 putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Ranges), s.Ranges)
1311 s.PutRanges(ctxt, ic.Ranges)
1312 } else {
1313 st := ic.Ranges[0].Start
1314 en := ic.Ranges[0].End
1315 emitHiLoPc(ctxt, abbrev, s, st, en)
1316 }
1317
1318
1319 putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, dwarfFileIndex(ic.CallPos), nil)
1320 form := int(expandPseudoForm(DW_FORM_udata_pseudo))
1321 putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallPos.RelLine()), nil)
1322
1323
1324 vars := ic.InlVars
1325 slices.SortFunc(vars, byChildIndexCmp)
1326 inlIndex := ic.InlIndex
1327 var encbuf [20]byte
1328 for _, v := range vars {
1329 if !v.IsInAbstract {
1330 continue
1331 }
1332 putvar(ctxt, s, v, callee, abbrev, inlIndex, encbuf[:0])
1333 }
1334
1335
1336 for _, sib := range inlChildren(callIdx, &s.InlCalls) {
1337 err := putInlinedFunc(ctxt, s, sib)
1338 if err != nil {
1339 return err
1340 }
1341 }
1342
1343 Uleb128put(ctxt, s.Info, 0)
1344 return nil
1345 }
1346
1347 func emitHiLoPc(ctxt Context, abbrev int, fns *FnState, st int64, en int64) {
1348 if buildcfg.Experiment.Dwarf5 {
1349 putattr(ctxt, fns.Info, abbrev, DW_FORM_addrx, DW_CLS_CONSTANT, st, fns.StartPC)
1350 putattr(ctxt, fns.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, en, 0)
1351 } else {
1352 putattr(ctxt, fns.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, st, fns.StartPC)
1353 putattr(ctxt, fns.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, en, fns.StartPC)
1354 }
1355 }
1356
1357
1358
1359
1360
1361
1362
1363
1364 func PutConcreteFunc(ctxt Context, s *FnState, isWrapper bool, fncount int) error {
1365 if logDwarf {
1366 ctxt.Logf("PutConcreteFunc(%v)\n", s.Info)
1367 }
1368 abbrev := DW_ABRV_FUNCTION_CONCRETE
1369 if isWrapper {
1370 abbrev = DW_ABRV_WRAPPER_CONCRETE
1371 }
1372 Uleb128put(ctxt, s.Info, int64(abbrev))
1373
1374
1375 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, s.Absfn)
1376
1377
1378 emitHiLoPc(ctxt, abbrev, s, 0, s.Size)
1379
1380
1381 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
1382
1383 if isWrapper {
1384 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
1385 }
1386
1387
1388 if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
1389 return err
1390 }
1391
1392
1393 for _, sib := range inlChildren(-1, &s.InlCalls) {
1394 err := putInlinedFunc(ctxt, s, sib)
1395 if err != nil {
1396 return err
1397 }
1398 }
1399
1400 Uleb128put(ctxt, s.Info, 0)
1401 return nil
1402 }
1403
1404
1405
1406
1407
1408
1409 func PutDefaultFunc(ctxt Context, s *FnState, isWrapper bool) error {
1410 if logDwarf {
1411 ctxt.Logf("PutDefaultFunc(%v)\n", s.Info)
1412 }
1413 abbrev := DW_ABRV_FUNCTION
1414 if isWrapper {
1415 abbrev = DW_ABRV_WRAPPER
1416 }
1417 Uleb128put(ctxt, s.Info, int64(abbrev))
1418
1419 name := s.Name
1420 if strings.HasPrefix(name, `"".`) {
1421 return fmt.Errorf("unqualified symbol name: %v", name)
1422 }
1423
1424 putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1425 emitHiLoPc(ctxt, abbrev, s, 0, s.Size)
1426 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
1427 if isWrapper {
1428 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
1429 } else {
1430 putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, dwarfFileIndex(s.StartPos), nil)
1431 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
1432
1433 var ev int64
1434 if s.External {
1435 ev = 1
1436 }
1437 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
1438 }
1439
1440
1441 if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
1442 return err
1443 }
1444
1445
1446 for _, sib := range inlChildren(-1, &s.InlCalls) {
1447 err := putInlinedFunc(ctxt, s, sib)
1448 if err != nil {
1449 return err
1450 }
1451 }
1452
1453 Uleb128put(ctxt, s.Info, 0)
1454 return nil
1455 }
1456
1457
1458 func putparamtypes(ctxt Context, s *FnState, scopes []Scope, fnabbrev int) []int64 {
1459 if fnabbrev == DW_ABRV_FUNCTION_CONCRETE {
1460 return nil
1461 }
1462
1463 maxDictIndex := uint16(0)
1464
1465 for i := range scopes {
1466 for _, v := range scopes[i].Vars {
1467 if v.DictIndex > maxDictIndex {
1468 maxDictIndex = v.DictIndex
1469 }
1470 }
1471 }
1472
1473 if maxDictIndex == 0 {
1474 return nil
1475 }
1476
1477 dictIndexToOffset := make([]int64, maxDictIndex)
1478
1479 for i := range scopes {
1480 for _, v := range scopes[i].Vars {
1481 if v.DictIndex == 0 || dictIndexToOffset[v.DictIndex-1] != 0 {
1482 continue
1483 }
1484
1485 dictIndexToOffset[v.DictIndex-1] = ctxt.CurrentOffset(s.Info)
1486
1487 Uleb128put(ctxt, s.Info, int64(DW_ABRV_DICT_INDEX))
1488 n := fmt.Sprintf(".param%d", v.DictIndex-1)
1489 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
1490 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1491 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DictIndex-1), nil)
1492 }
1493 }
1494
1495 return dictIndexToOffset
1496 }
1497
1498 func putscope(ctxt Context, s *FnState, scopes []Scope, curscope int32, fnabbrev int, encbuf []byte) int32 {
1499
1500 if logDwarf {
1501 ctxt.Logf("putscope(%v,%d): vars:", s.Info, curscope)
1502 for i, v := range scopes[curscope].Vars {
1503 ctxt.Logf(" %d:%d:%s", i, v.ChildIndex, v.Name)
1504 }
1505 ctxt.Logf("\n")
1506 }
1507
1508 for _, v := range scopes[curscope].Vars {
1509 putvar(ctxt, s, v, s.Absfn, fnabbrev, -1, encbuf)
1510 }
1511 this := curscope
1512 curscope++
1513 for curscope < int32(len(scopes)) {
1514 scope := scopes[curscope]
1515 if scope.Parent != this {
1516 return curscope
1517 }
1518
1519 if len(scopes[curscope].Vars) == 0 {
1520 curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
1521 continue
1522 }
1523
1524
1525
1526
1527 if len(scope.Ranges) == 1 && !buildcfg.Experiment.Dwarf5 {
1528 Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
1529 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, s.StartPC)
1530 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, s.StartPC)
1531 } else {
1532 Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES)
1533 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Ranges), s.Ranges)
1534
1535 s.PutRanges(ctxt, scope.Ranges)
1536 }
1537
1538 curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
1539
1540 Uleb128put(ctxt, s.Info, 0)
1541 }
1542 return curscope
1543 }
1544
1545 func concreteVar(fnabbrev int, v *Var) bool {
1546 concrete := true
1547 switch fnabbrev {
1548 case DW_ABRV_FUNCTION, DW_ABRV_WRAPPER:
1549 concrete = false
1550 case DW_ABRV_FUNCTION_CONCRETE, DW_ABRV_WRAPPER_CONCRETE:
1551
1552
1553
1554 if !v.IsInAbstract {
1555 concrete = false
1556 }
1557 case DW_ABRV_INLINED_SUBROUTINE, DW_ABRV_INLINED_SUBROUTINE_RANGES:
1558 default:
1559 panic("should never happen")
1560 }
1561 return concrete
1562 }
1563
1564
1565 func putAbstractVar(ctxt Context, info Sym, v *Var) {
1566
1567 abbrev := putAbstractVarAbbrev(v)
1568 Uleb128put(ctxt, info, int64(abbrev))
1569 putattr(ctxt, info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(v.Name)), v.Name)
1570
1571
1572 if v.Tag == DW_TAG_formal_parameter {
1573 var isReturn int64
1574 if v.IsReturnValue {
1575 isReturn = 1
1576 }
1577 putattr(ctxt, info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
1578 }
1579
1580
1581 if v.Tag == DW_TAG_variable {
1582
1583 putattr(ctxt, info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
1584 }
1585
1586
1587 putattr(ctxt, info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1588
1589
1590 }
1591
1592 func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int, encbuf []byte) {
1593
1594 concrete := concreteVar(fnabbrev, v)
1595 hasParametricType := !concrete && (v.DictIndex > 0 && s.dictIndexToOffset != nil && s.dictIndexToOffset[v.DictIndex-1] != 0)
1596 withLoclist := v.WithLoclist && v.PutLocationList != nil
1597
1598 abbrev := putvarAbbrev(v, concrete, withLoclist)
1599 Uleb128put(ctxt, s.Info, int64(abbrev))
1600
1601
1602 if concrete {
1603
1604
1605
1606
1607 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, absfn)
1608 ctxt.RecordDclReference(s.Info, absfn, int(v.ChildIndex), inlIndex)
1609 } else {
1610
1611 n := v.Name
1612 putattr(ctxt, s.Info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
1613 if v.Tag == DW_TAG_formal_parameter {
1614 var isReturn int64
1615 if v.IsReturnValue {
1616 isReturn = 1
1617 }
1618 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
1619 }
1620 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
1621 if hasParametricType {
1622
1623 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, s.dictIndexToOffset[v.DictIndex-1], s.Info)
1624 } else {
1625 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1626 }
1627
1628 if v.ClosureOffset > 0 {
1629 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, v.ClosureOffset, nil)
1630 }
1631 }
1632
1633 if withLoclist {
1634 putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Loc), s.Loc)
1635 v.PutLocationList(s.Loc, s.StartPC)
1636 } else {
1637 loc := encbuf[:0]
1638 switch {
1639 case v.WithLoclist:
1640 break
1641 case v.StackOffset == 0:
1642 loc = append(loc, DW_OP_call_frame_cfa)
1643 default:
1644 loc = append(loc, DW_OP_fbreg)
1645 loc = AppendSleb128(loc, int64(v.StackOffset))
1646 }
1647 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
1648 }
1649
1650
1651 }
1652
1653
1654 func byChildIndexCmp(a, b *Var) int { return cmp.Compare(a.ChildIndex, b.ChildIndex) }
1655
1656
1657
1658
1659
1660 func IsDWARFEnabledOnAIXLd(extld []string) (bool, error) {
1661 name, args := extld[0], extld[1:]
1662 args = append(args, "-Wl,-V")
1663 out, err := exec.Command(name, args...).CombinedOutput()
1664 if err != nil {
1665
1666
1667
1668 if !bytes.Contains(out, []byte("0711-317")) {
1669 return false, fmt.Errorf("%s -Wl,-V failed: %v\n%s", extld, err, out)
1670 }
1671 }
1672
1673
1674
1675 out = bytes.TrimPrefix(out, []byte("/usr/bin/ld: LD "))
1676 vers := string(bytes.Split(out, []byte("("))[0])
1677 subvers := strings.Split(vers, ".")
1678 if len(subvers) != 3 {
1679 return false, fmt.Errorf("cannot parse %s -Wl,-V (%s): %v\n", extld, out, err)
1680 }
1681 if v, err := strconv.Atoi(subvers[0]); err != nil || v < 7 {
1682 return false, nil
1683 } else if v > 7 {
1684 return true, nil
1685 }
1686 if v, err := strconv.Atoi(subvers[1]); err != nil || v < 2 {
1687 return false, nil
1688 } else if v > 2 {
1689 return true, nil
1690 }
1691 if v, err := strconv.Atoi(subvers[2]); err != nil || v < 2 {
1692 return false, nil
1693 }
1694 return true, nil
1695 }
1696
View as plain text