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 interface {
44 }
45
46
47 type Var struct {
48 Name string
49 Tag int
50 WithLoclist bool
51 IsReturnValue bool
52 IsInlFormal bool
53 DictIndex uint16
54 StackOffset int32
55
56
57 PutLocationList func(listSym, startPC Sym)
58 Scope int32
59 Type Sym
60 DeclFile string
61 DeclLine uint
62 DeclCol uint
63 InlIndex int32
64 ChildIndex int32
65 IsInAbstract bool
66 ClosureOffset int64
67 }
68
69
70
71
72
73
74
75 type Scope struct {
76 Parent int32
77 Ranges []Range
78 Vars []*Var
79 }
80
81
82 type Range struct {
83 Start, End int64
84 }
85
86
87
88 type FnState struct {
89 Name string
90 Info Sym
91 Loc Sym
92 Ranges Sym
93 Absfn Sym
94 StartPC Sym
95 StartPos src.Pos
96 Size int64
97 External bool
98 Scopes []Scope
99 InlCalls InlCalls
100 UseBASEntries bool
101
102 dictIndexToOffset []int64
103 }
104
105 func EnableLogging(doit bool) {
106 logDwarf = doit
107 }
108
109
110
111 func MergeRanges(in1, in2 []Range) []Range {
112 out := make([]Range, 0, len(in1)+len(in2))
113 i, j := 0, 0
114 for {
115 var cur Range
116 if i < len(in2) && j < len(in1) {
117 if in2[i].Start < in1[j].Start {
118 cur = in2[i]
119 i++
120 } else {
121 cur = in1[j]
122 j++
123 }
124 } else if i < len(in2) {
125 cur = in2[i]
126 i++
127 } else if j < len(in1) {
128 cur = in1[j]
129 j++
130 } else {
131 break
132 }
133
134 if n := len(out); n > 0 && cur.Start <= out[n-1].End {
135 out[n-1].End = cur.End
136 } else {
137 out = append(out, cur)
138 }
139 }
140
141 return out
142 }
143
144
145 func (s *Scope) UnifyRanges(c *Scope) {
146 s.Ranges = MergeRanges(s.Ranges, c.Ranges)
147 }
148
149
150
151 func (s *Scope) AppendRange(r Range) {
152 if r.End <= r.Start {
153 return
154 }
155 i := len(s.Ranges)
156 if i > 0 && s.Ranges[i-1].End == r.Start {
157 s.Ranges[i-1].End = r.End
158 return
159 }
160 s.Ranges = append(s.Ranges, r)
161 }
162
163 type InlCalls struct {
164 Calls []InlCall
165 }
166
167 type InlCall struct {
168
169 InlIndex int
170
171
172 CallPos src.Pos
173
174
175 AbsFunSym Sym
176
177
178 Children []int
179
180
181
182 InlVars []*Var
183
184
185 Ranges []Range
186
187
188 Root bool
189 }
190
191
192 type Context interface {
193 PtrSize() int
194 Size(s Sym) int64
195 AddInt(s Sym, size int, i int64)
196 AddBytes(s Sym, b []byte)
197 AddAddress(s Sym, t interface{}, ofs int64)
198 AddCURelativeAddress(s Sym, t interface{}, ofs int64)
199 AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
200 AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64)
201 AddIndirectTextRef(s Sym, t interface{})
202 CurrentOffset(s Sym) int64
203 RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int)
204 RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32)
205 AddString(s Sym, v string)
206 Logf(format string, args ...interface{})
207 }
208
209
210 func AppendUleb128(b []byte, v uint64) []byte {
211 for {
212 c := uint8(v & 0x7f)
213 v >>= 7
214 if v != 0 {
215 c |= 0x80
216 }
217 b = append(b, c)
218 if c&0x80 == 0 {
219 break
220 }
221 }
222 return b
223 }
224
225
226 func AppendSleb128(b []byte, v int64) []byte {
227 for {
228 c := uint8(v & 0x7f)
229 s := uint8(v & 0x40)
230 v >>= 7
231 if (v != -1 || s == 0) && (v != 0 || s != 0) {
232 c |= 0x80
233 }
234 b = append(b, c)
235 if c&0x80 == 0 {
236 break
237 }
238 }
239 return b
240 }
241
242
243 var sevenbits = [...]byte{
244 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
245 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
246 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
247 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
248 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
249 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
250 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
251 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
252 }
253
254
255
256 func sevenBitU(v int64) []byte {
257 if uint64(v) < uint64(len(sevenbits)) {
258 return sevenbits[v : v+1]
259 }
260 return nil
261 }
262
263
264
265 func sevenBitS(v int64) []byte {
266 if uint64(v) <= 63 {
267 return sevenbits[v : v+1]
268 }
269 if uint64(-v) <= 64 {
270 return sevenbits[128+v : 128+v+1]
271 }
272 return nil
273 }
274
275
276 func Uleb128put(ctxt Context, s Sym, v int64) {
277 b := sevenBitU(v)
278 if b == nil {
279 var encbuf [20]byte
280 b = AppendUleb128(encbuf[:0], uint64(v))
281 }
282 ctxt.AddBytes(s, b)
283 }
284
285
286 func Sleb128put(ctxt Context, s Sym, v int64) {
287 b := sevenBitS(v)
288 if b == nil {
289 var encbuf [20]byte
290 b = AppendSleb128(encbuf[:0], v)
291 }
292 ctxt.AddBytes(s, b)
293 }
294
295
303 type dwAttrForm struct {
304 attr uint16
305 form uint8
306 }
307
308
309 const (
310 DW_AT_go_kind = 0x2900
311 DW_AT_go_key = 0x2901
312 DW_AT_go_elem = 0x2902
313
314
315 DW_AT_go_embedded_field = 0x2903
316 DW_AT_go_runtime_type = 0x2904
317
318 DW_AT_go_package_name = 0x2905
319 DW_AT_go_dict_index = 0x2906
320 DW_AT_go_closure_offset = 0x2907
321
322 DW_AT_internal_location = 253
323 )
324
325
326 const (
327 DW_ABRV_NULL = iota
328 DW_ABRV_COMPUNIT
329 DW_ABRV_COMPUNIT_TEXTLESS
330 DW_ABRV_FUNCTION
331 DW_ABRV_WRAPPER
332 DW_ABRV_FUNCTION_ABSTRACT
333 DW_ABRV_FUNCTION_CONCRETE
334 DW_ABRV_WRAPPER_CONCRETE
335 DW_ABRV_INLINED_SUBROUTINE
336 DW_ABRV_INLINED_SUBROUTINE_RANGES
337 DW_ABRV_VARIABLE
338 DW_ABRV_INT_CONSTANT
339 DW_ABRV_LEXICAL_BLOCK_RANGES
340 DW_ABRV_LEXICAL_BLOCK_SIMPLE
341 DW_ABRV_STRUCTFIELD
342 DW_ABRV_FUNCTYPEPARAM
343 DW_ABRV_FUNCTYPEOUTPARAM
344 DW_ABRV_DOTDOTDOT
345 DW_ABRV_ARRAYRANGE
346 DW_ABRV_NULLTYPE
347 DW_ABRV_BASETYPE
348 DW_ABRV_ARRAYTYPE
349 DW_ABRV_CHANTYPE
350 DW_ABRV_FUNCTYPE
351 DW_ABRV_IFACETYPE
352 DW_ABRV_MAPTYPE
353 DW_ABRV_PTRTYPE
354 DW_ABRV_BARE_PTRTYPE
355 DW_ABRV_SLICETYPE
356 DW_ABRV_STRINGTYPE
357 DW_ABRV_STRUCTTYPE
358 DW_ABRV_TYPEDECL
359 DW_ABRV_DICT_INDEX
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 func GetAbbrev() []byte {
846 abbrevs := Abbrevs()
847 var buf []byte
848 for i := 1; i < len(abbrevs); i++ {
849
850 buf = AppendUleb128(buf, uint64(i))
851 buf = AppendUleb128(buf, uint64(abbrevs[i].tag))
852 buf = append(buf, abbrevs[i].children)
853 for _, f := range abbrevs[i].attr {
854 buf = AppendUleb128(buf, uint64(f.attr))
855 buf = AppendUleb128(buf, uint64(f.form))
856 }
857 buf = append(buf, 0, 0)
858 }
859 return append(buf, 0)
860 }
861
862
865
866
867
868
869
870
871
872 type DWAttr struct {
873 Link *DWAttr
874 Atr uint16
875 Cls uint8
876 Value int64
877 Data interface{}
878 }
879
880
881 type DWDie struct {
882 Abbrev int
883 Link *DWDie
884 Child *DWDie
885 Attr *DWAttr
886 Sym Sym
887 }
888
889 func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data interface{}) error {
890 switch form {
891 case DW_FORM_addr:
892
893 if data == nil && value == 0 {
894 ctxt.AddInt(s, ctxt.PtrSize(), 0)
895 break
896 }
897 if cls == DW_CLS_GO_TYPEREF {
898 ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, value)
899 break
900 }
901 ctxt.AddAddress(s, data, value)
902
903 case DW_FORM_block1:
904 if cls == DW_CLS_ADDRESS {
905 ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize()))
906 ctxt.AddInt(s, 1, DW_OP_addr)
907 ctxt.AddAddress(s, data, 0)
908 break
909 }
910
911 value &= 0xff
912 ctxt.AddInt(s, 1, value)
913 p := data.([]byte)[:value]
914 ctxt.AddBytes(s, p)
915
916 case DW_FORM_block2:
917 value &= 0xffff
918
919 ctxt.AddInt(s, 2, value)
920 p := data.([]byte)[:value]
921 ctxt.AddBytes(s, p)
922
923 case DW_FORM_block4:
924 value &= 0xffffffff
925
926 ctxt.AddInt(s, 4, value)
927 p := data.([]byte)[:value]
928 ctxt.AddBytes(s, p)
929
930 case DW_FORM_block:
931 Uleb128put(ctxt, s, value)
932
933 p := data.([]byte)[:value]
934 ctxt.AddBytes(s, p)
935
936 case DW_FORM_data1:
937 ctxt.AddInt(s, 1, value)
938
939 case DW_FORM_data2:
940 ctxt.AddInt(s, 2, value)
941
942 case DW_FORM_data4:
943 if cls == DW_CLS_PTR {
944 ctxt.AddDWARFAddrSectionOffset(s, data, value)
945 break
946 }
947 ctxt.AddInt(s, 4, value)
948
949 case DW_FORM_data8:
950 ctxt.AddInt(s, 8, value)
951
952 case DW_FORM_sdata:
953 Sleb128put(ctxt, s, value)
954
955 case DW_FORM_udata:
956 Uleb128put(ctxt, s, value)
957
958 case DW_FORM_string:
959 str := data.(string)
960 ctxt.AddString(s, str)
961
962 for i := int64(len(str)); i < value; i++ {
963 ctxt.AddInt(s, 1, 0)
964 }
965
966 case DW_FORM_flag:
967 if value != 0 {
968 ctxt.AddInt(s, 1, 1)
969 } else {
970 ctxt.AddInt(s, 1, 0)
971 }
972
973
974
975 case DW_FORM_ref_addr:
976 fallthrough
977 case DW_FORM_sec_offset:
978 if data == nil {
979 return fmt.Errorf("dwarf: null reference in %d", abbrev)
980 }
981 ctxt.AddDWARFAddrSectionOffset(s, data, value)
982
983 case DW_FORM_addrx:
984 ctxt.AddIndirectTextRef(s, data)
985
986 case DW_FORM_ref1,
987 DW_FORM_ref2,
988 DW_FORM_ref4,
989 DW_FORM_ref8,
990 DW_FORM_ref_udata,
991
992 DW_FORM_strp,
993 DW_FORM_indirect:
994 fallthrough
995 default:
996 return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls)
997 }
998 return nil
999 }
1000
1001
1002
1003
1004
1005 func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) {
1006 abbrevs := Abbrevs()
1007 Outer:
1008 for _, f := range abbrevs[abbrev].attr {
1009 for ap := attr; ap != nil; ap = ap.Link {
1010 if ap.Atr == f.attr {
1011 putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data)
1012 continue Outer
1013 }
1014 }
1015
1016 putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil)
1017 }
1018 }
1019
1020
1021 func HasChildren(die *DWDie) bool {
1022 abbrevs := Abbrevs()
1023 return abbrevs[die.Abbrev].children != 0
1024 }
1025
1026
1027 func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
1028 Uleb128put(ctxt, info, DW_ABRV_INT_CONSTANT)
1029 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1030 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1031 putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
1032 }
1033
1034
1035 func PutGlobal(ctxt Context, info, typ, gvar Sym, name string) {
1036 Uleb128put(ctxt, info, DW_ABRV_VARIABLE)
1037 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1038 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_block1, DW_CLS_ADDRESS, 0, gvar)
1039 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1040 putattr(ctxt, info, DW_ABRV_VARIABLE, DW_FORM_flag, DW_CLS_FLAG, 1, nil)
1041 }
1042
1043
1044
1045
1046 func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) {
1047 ps := ctxt.PtrSize()
1048
1049 for _, r := range ranges {
1050 ctxt.AddInt(sym, ps, r.Start)
1051 ctxt.AddInt(sym, ps, r.End)
1052 }
1053
1054 ctxt.AddInt(sym, ps, 0)
1055 ctxt.AddInt(sym, ps, 0)
1056 }
1057
1058
1059
1060 func PutRngListRanges(ctxt Context, sym Sym, base Sym, ranges []Range) {
1061 addULEB128 := func(v int64) {
1062 b := sevenBitU(v)
1063 if b == nil {
1064 var encbuf [20]byte
1065 b = AppendUleb128(encbuf[:0], uint64(v))
1066 }
1067 ctxt.AddBytes(sym, b)
1068 }
1069
1070 ctxt.AddInt(sym, 1, DW_RLE_base_addressx)
1071 ctxt.AddIndirectTextRef(sym, base)
1072
1073 for _, r := range ranges {
1074 ctxt.AddInt(sym, 1, DW_RLE_offset_pair)
1075 addULEB128(r.Start)
1076 addULEB128(r.End)
1077 }
1078
1079 ctxt.AddInt(sym, 1, DW_RLE_end_of_list)
1080 }
1081
1082
1083
1084 func (s *FnState) PutRanges(ctxt Context, ranges []Range) {
1085 ps := ctxt.PtrSize()
1086 sym, base := s.Ranges, s.StartPC
1087
1088 if buildcfg.Experiment.Dwarf5 {
1089 PutRngListRanges(ctxt, sym, base, ranges)
1090 return
1091 }
1092
1093 if s.UseBASEntries {
1094
1095
1096 ctxt.AddInt(sym, ps, -1)
1097 ctxt.AddAddress(sym, base, 0)
1098 PutBasedRanges(ctxt, sym, ranges)
1099 return
1100 }
1101
1102
1103 for _, r := range ranges {
1104 ctxt.AddCURelativeAddress(sym, base, r.Start)
1105 ctxt.AddCURelativeAddress(sym, base, r.End)
1106 }
1107
1108 ctxt.AddInt(sym, ps, 0)
1109 ctxt.AddInt(sym, ps, 0)
1110 }
1111
1112
1113
1114
1115 func isEmptyInlinedCall(slot int, calls *InlCalls) bool {
1116 ic := &calls.Calls[slot]
1117 if ic.InlIndex == -2 {
1118 return true
1119 }
1120 live := false
1121 for _, k := range ic.Children {
1122 if !isEmptyInlinedCall(k, calls) {
1123 live = true
1124 }
1125 }
1126 if len(ic.Ranges) > 0 {
1127 live = true
1128 }
1129 if !live {
1130 ic.InlIndex = -2
1131 }
1132 return !live
1133 }
1134
1135
1136
1137 func inlChildren(slot int, calls *InlCalls) []int {
1138 var kids []int
1139 if slot != -1 {
1140 for _, k := range calls.Calls[slot].Children {
1141 if !isEmptyInlinedCall(k, calls) {
1142 kids = append(kids, k)
1143 }
1144 }
1145 } else {
1146 for k := 0; k < len(calls.Calls); k += 1 {
1147 if calls.Calls[k].Root && !isEmptyInlinedCall(k, calls) {
1148 kids = append(kids, k)
1149 }
1150 }
1151 }
1152 return kids
1153 }
1154
1155 func inlinedVarTable(inlcalls *InlCalls) map[*Var]bool {
1156 vars := make(map[*Var]bool)
1157 for _, ic := range inlcalls.Calls {
1158 for _, v := range ic.InlVars {
1159 vars[v] = true
1160 }
1161 }
1162 return vars
1163 }
1164
1165
1166
1167
1168
1169
1170
1171 func putPrunedScopes(ctxt Context, s *FnState, fnabbrev int) error {
1172 if len(s.Scopes) == 0 {
1173 return nil
1174 }
1175 scopes := make([]Scope, len(s.Scopes), len(s.Scopes))
1176 pvars := inlinedVarTable(&s.InlCalls)
1177 for k, s := range s.Scopes {
1178 var pruned Scope = Scope{Parent: s.Parent, Ranges: s.Ranges}
1179 for i := 0; i < len(s.Vars); i++ {
1180 _, found := pvars[s.Vars[i]]
1181 if !found {
1182 pruned.Vars = append(pruned.Vars, s.Vars[i])
1183 }
1184 }
1185 slices.SortFunc(pruned.Vars, byChildIndexCmp)
1186 scopes[k] = pruned
1187 }
1188
1189 s.dictIndexToOffset = putparamtypes(ctxt, s, scopes, fnabbrev)
1190
1191 var encbuf [20]byte
1192 if putscope(ctxt, s, scopes, 0, fnabbrev, encbuf[:0]) < int32(len(scopes)) {
1193 return errors.New("multiple toplevel scopes")
1194 }
1195 return nil
1196 }
1197
1198
1199
1200
1201
1202
1203
1204
1205 func PutAbstractFunc(ctxt Context, s *FnState) error {
1206 if logDwarf {
1207 ctxt.Logf("PutAbstractFunc(%v)\n", s.Absfn)
1208 }
1209
1210 abbrev := DW_ABRV_FUNCTION_ABSTRACT
1211 Uleb128put(ctxt, s.Absfn, int64(abbrev))
1212
1213 fullname := s.Name
1214 if strings.HasPrefix(s.Name, `"".`) {
1215 return fmt.Errorf("unqualified symbol name: %v", s.Name)
1216 }
1217 putattr(ctxt, s.Absfn, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(fullname)), fullname)
1218
1219
1220 putattr(ctxt, s.Absfn, abbrev, DW_FORM_data1, DW_CLS_CONSTANT, int64(DW_INL_inlined), nil)
1221
1222
1223 putattr(ctxt, s.Absfn, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
1224
1225 var ev int64
1226 if s.External {
1227 ev = 1
1228 }
1229 putattr(ctxt, s.Absfn, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
1230
1231
1232 var flattened []*Var
1233
1234
1235
1236 var offsets []int32
1237
1238
1239 if len(s.Scopes) > 0 {
1240
1241
1242
1243 pvars := inlinedVarTable(&s.InlCalls)
1244 for _, scope := range s.Scopes {
1245 for i := 0; i < len(scope.Vars); i++ {
1246 _, found := pvars[scope.Vars[i]]
1247 if found || !scope.Vars[i].IsInAbstract {
1248 continue
1249 }
1250 flattened = append(flattened, scope.Vars[i])
1251 }
1252 }
1253 if len(flattened) > 0 {
1254 slices.SortFunc(flattened, byChildIndexCmp)
1255
1256 if logDwarf {
1257 ctxt.Logf("putAbstractScope(%v): vars:", s.Info)
1258 for i, v := range flattened {
1259 ctxt.Logf(" %d:%s", i, v.Name)
1260 }
1261 ctxt.Logf("\n")
1262 }
1263
1264
1265
1266
1267 for _, v := range flattened {
1268 offsets = append(offsets, int32(ctxt.CurrentOffset(s.Absfn)))
1269 putAbstractVar(ctxt, s.Absfn, v)
1270 }
1271 }
1272 }
1273 ctxt.RecordChildDieOffsets(s.Absfn, flattened, offsets)
1274
1275 Uleb128put(ctxt, s.Absfn, 0)
1276 return nil
1277 }
1278
1279
1280
1281 func dwarfFileIndex(pos src.Pos) int64 {
1282 return int64(1 + pos.FileIndex())
1283 }
1284
1285
1286
1287
1288
1289
1290 func putInlinedFunc(ctxt Context, s *FnState, callIdx int) error {
1291 ic := s.InlCalls.Calls[callIdx]
1292 callee := ic.AbsFunSym
1293
1294
1295
1296
1297 abbrev := DW_ABRV_INLINED_SUBROUTINE_RANGES
1298 if len(ic.Ranges) == 1 && !buildcfg.Experiment.Dwarf5 {
1299 abbrev = DW_ABRV_INLINED_SUBROUTINE
1300 }
1301 Uleb128put(ctxt, s.Info, int64(abbrev))
1302
1303 if logDwarf {
1304 ctxt.Logf("putInlinedFunc(callee=%v,abbrev=%d)\n", callee, abbrev)
1305 }
1306
1307
1308 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, callee)
1309
1310 if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES {
1311 putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Ranges), s.Ranges)
1312 s.PutRanges(ctxt, ic.Ranges)
1313 } else {
1314 st := ic.Ranges[0].Start
1315 en := ic.Ranges[0].End
1316 emitHiLoPc(ctxt, abbrev, s, st, en)
1317 }
1318
1319
1320 putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, dwarfFileIndex(ic.CallPos), nil)
1321 form := int(expandPseudoForm(DW_FORM_udata_pseudo))
1322 putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallPos.RelLine()), nil)
1323
1324
1325 vars := ic.InlVars
1326 slices.SortFunc(vars, byChildIndexCmp)
1327 inlIndex := ic.InlIndex
1328 var encbuf [20]byte
1329 for _, v := range vars {
1330 if !v.IsInAbstract {
1331 continue
1332 }
1333 putvar(ctxt, s, v, callee, abbrev, inlIndex, encbuf[:0])
1334 }
1335
1336
1337 for _, sib := range inlChildren(callIdx, &s.InlCalls) {
1338 err := putInlinedFunc(ctxt, s, sib)
1339 if err != nil {
1340 return err
1341 }
1342 }
1343
1344 Uleb128put(ctxt, s.Info, 0)
1345 return nil
1346 }
1347
1348 func emitHiLoPc(ctxt Context, abbrev int, fns *FnState, st int64, en int64) {
1349 if buildcfg.Experiment.Dwarf5 {
1350 putattr(ctxt, fns.Info, abbrev, DW_FORM_addrx, DW_CLS_CONSTANT, st, fns.StartPC)
1351 putattr(ctxt, fns.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, en, 0)
1352 } else {
1353 putattr(ctxt, fns.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, st, fns.StartPC)
1354 putattr(ctxt, fns.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, en, fns.StartPC)
1355 }
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365 func PutConcreteFunc(ctxt Context, s *FnState, isWrapper bool, fncount int) error {
1366 if logDwarf {
1367 ctxt.Logf("PutConcreteFunc(%v)\n", s.Info)
1368 }
1369 abbrev := DW_ABRV_FUNCTION_CONCRETE
1370 if isWrapper {
1371 abbrev = DW_ABRV_WRAPPER_CONCRETE
1372 }
1373 Uleb128put(ctxt, s.Info, int64(abbrev))
1374
1375
1376 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, s.Absfn)
1377
1378
1379 emitHiLoPc(ctxt, abbrev, s, 0, s.Size)
1380
1381
1382 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
1383
1384 if isWrapper {
1385 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
1386 }
1387
1388
1389 if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
1390 return err
1391 }
1392
1393
1394 for _, sib := range inlChildren(-1, &s.InlCalls) {
1395 err := putInlinedFunc(ctxt, s, sib)
1396 if err != nil {
1397 return err
1398 }
1399 }
1400
1401 Uleb128put(ctxt, s.Info, 0)
1402 return nil
1403 }
1404
1405
1406
1407
1408
1409
1410 func PutDefaultFunc(ctxt Context, s *FnState, isWrapper bool) error {
1411 if logDwarf {
1412 ctxt.Logf("PutDefaultFunc(%v)\n", s.Info)
1413 }
1414 abbrev := DW_ABRV_FUNCTION
1415 if isWrapper {
1416 abbrev = DW_ABRV_WRAPPER
1417 }
1418 Uleb128put(ctxt, s.Info, int64(abbrev))
1419
1420 name := s.Name
1421 if strings.HasPrefix(name, `"".`) {
1422 return fmt.Errorf("unqualified symbol name: %v", name)
1423 }
1424
1425 putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1426 emitHiLoPc(ctxt, abbrev, s, 0, s.Size)
1427 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
1428 if isWrapper {
1429 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
1430 } else {
1431 putattr(ctxt, s.Info, abbrev, DW_FORM_data4, DW_CLS_CONSTANT, dwarfFileIndex(s.StartPos), nil)
1432 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(s.StartPos.RelLine()), nil)
1433
1434 var ev int64
1435 if s.External {
1436 ev = 1
1437 }
1438 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
1439 }
1440
1441
1442 if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
1443 return err
1444 }
1445
1446
1447 for _, sib := range inlChildren(-1, &s.InlCalls) {
1448 err := putInlinedFunc(ctxt, s, sib)
1449 if err != nil {
1450 return err
1451 }
1452 }
1453
1454 Uleb128put(ctxt, s.Info, 0)
1455 return nil
1456 }
1457
1458
1459 func putparamtypes(ctxt Context, s *FnState, scopes []Scope, fnabbrev int) []int64 {
1460 if fnabbrev == DW_ABRV_FUNCTION_CONCRETE {
1461 return nil
1462 }
1463
1464 maxDictIndex := uint16(0)
1465
1466 for i := range scopes {
1467 for _, v := range scopes[i].Vars {
1468 if v.DictIndex > maxDictIndex {
1469 maxDictIndex = v.DictIndex
1470 }
1471 }
1472 }
1473
1474 if maxDictIndex == 0 {
1475 return nil
1476 }
1477
1478 dictIndexToOffset := make([]int64, maxDictIndex)
1479
1480 for i := range scopes {
1481 for _, v := range scopes[i].Vars {
1482 if v.DictIndex == 0 || dictIndexToOffset[v.DictIndex-1] != 0 {
1483 continue
1484 }
1485
1486 dictIndexToOffset[v.DictIndex-1] = ctxt.CurrentOffset(s.Info)
1487
1488 Uleb128put(ctxt, s.Info, int64(DW_ABRV_DICT_INDEX))
1489 n := fmt.Sprintf(".param%d", v.DictIndex-1)
1490 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
1491 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1492 putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DictIndex-1), nil)
1493 }
1494 }
1495
1496 return dictIndexToOffset
1497 }
1498
1499 func putscope(ctxt Context, s *FnState, scopes []Scope, curscope int32, fnabbrev int, encbuf []byte) int32 {
1500
1501 if logDwarf {
1502 ctxt.Logf("putscope(%v,%d): vars:", s.Info, curscope)
1503 for i, v := range scopes[curscope].Vars {
1504 ctxt.Logf(" %d:%d:%s", i, v.ChildIndex, v.Name)
1505 }
1506 ctxt.Logf("\n")
1507 }
1508
1509 for _, v := range scopes[curscope].Vars {
1510 putvar(ctxt, s, v, s.Absfn, fnabbrev, -1, encbuf)
1511 }
1512 this := curscope
1513 curscope++
1514 for curscope < int32(len(scopes)) {
1515 scope := scopes[curscope]
1516 if scope.Parent != this {
1517 return curscope
1518 }
1519
1520 if len(scopes[curscope].Vars) == 0 {
1521 curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
1522 continue
1523 }
1524
1525
1526
1527
1528 if len(scope.Ranges) == 1 && !buildcfg.Experiment.Dwarf5 {
1529 Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
1530 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, s.StartPC)
1531 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, s.StartPC)
1532 } else {
1533 Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES)
1534 putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Ranges), s.Ranges)
1535
1536 s.PutRanges(ctxt, scope.Ranges)
1537 }
1538
1539 curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf)
1540
1541 Uleb128put(ctxt, s.Info, 0)
1542 }
1543 return curscope
1544 }
1545
1546 func concreteVar(fnabbrev int, v *Var) bool {
1547 concrete := true
1548 switch fnabbrev {
1549 case DW_ABRV_FUNCTION, DW_ABRV_WRAPPER:
1550 concrete = false
1551 case DW_ABRV_FUNCTION_CONCRETE, DW_ABRV_WRAPPER_CONCRETE:
1552
1553
1554
1555 if !v.IsInAbstract {
1556 concrete = false
1557 }
1558 case DW_ABRV_INLINED_SUBROUTINE, DW_ABRV_INLINED_SUBROUTINE_RANGES:
1559 default:
1560 panic("should never happen")
1561 }
1562 return concrete
1563 }
1564
1565
1566 func putAbstractVar(ctxt Context, info Sym, v *Var) {
1567
1568 abbrev := putAbstractVarAbbrev(v)
1569 Uleb128put(ctxt, info, int64(abbrev))
1570 putattr(ctxt, info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(v.Name)), v.Name)
1571
1572
1573 if v.Tag == DW_TAG_formal_parameter {
1574 var isReturn int64
1575 if v.IsReturnValue {
1576 isReturn = 1
1577 }
1578 putattr(ctxt, info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
1579 }
1580
1581
1582 if v.Tag == DW_TAG_variable {
1583
1584 putattr(ctxt, info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
1585 }
1586
1587
1588 putattr(ctxt, info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1589
1590
1591 }
1592
1593 func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int, encbuf []byte) {
1594
1595 concrete := concreteVar(fnabbrev, v)
1596 hasParametricType := !concrete && (v.DictIndex > 0 && s.dictIndexToOffset != nil && s.dictIndexToOffset[v.DictIndex-1] != 0)
1597 withLoclist := v.WithLoclist && v.PutLocationList != nil
1598
1599 abbrev := putvarAbbrev(v, concrete, withLoclist)
1600 Uleb128put(ctxt, s.Info, int64(abbrev))
1601
1602
1603 if concrete {
1604
1605
1606
1607
1608 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, absfn)
1609 ctxt.RecordDclReference(s.Info, absfn, int(v.ChildIndex), inlIndex)
1610 } else {
1611
1612 n := v.Name
1613 putattr(ctxt, s.Info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
1614 if v.Tag == DW_TAG_formal_parameter {
1615 var isReturn int64
1616 if v.IsReturnValue {
1617 isReturn = 1
1618 }
1619 putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
1620 }
1621 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
1622 if hasParametricType {
1623
1624 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, s.dictIndexToOffset[v.DictIndex-1], s.Info)
1625 } else {
1626 putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
1627 }
1628
1629 if v.ClosureOffset > 0 {
1630 putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, v.ClosureOffset, nil)
1631 }
1632 }
1633
1634 if withLoclist {
1635 putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, ctxt.Size(s.Loc), s.Loc)
1636 v.PutLocationList(s.Loc, s.StartPC)
1637 } else {
1638 loc := encbuf[:0]
1639 switch {
1640 case v.WithLoclist:
1641 break
1642 case v.StackOffset == 0:
1643 loc = append(loc, DW_OP_call_frame_cfa)
1644 default:
1645 loc = append(loc, DW_OP_fbreg)
1646 loc = AppendSleb128(loc, int64(v.StackOffset))
1647 }
1648 putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
1649 }
1650
1651
1652 }
1653
1654
1655 func byChildIndexCmp(a, b *Var) int { return cmp.Compare(a.ChildIndex, b.ChildIndex) }
1656
1657
1658
1659
1660
1661 func IsDWARFEnabledOnAIXLd(extld []string) (bool, error) {
1662 name, args := extld[0], extld[1:]
1663 args = append(args, "-Wl,-V")
1664 out, err := exec.Command(name, args...).CombinedOutput()
1665 if err != nil {
1666
1667
1668
1669 if !bytes.Contains(out, []byte("0711-317")) {
1670 return false, fmt.Errorf("%s -Wl,-V failed: %v\n%s", extld, err, out)
1671 }
1672 }
1673
1674
1675
1676 out = bytes.TrimPrefix(out, []byte("/usr/bin/ld: LD "))
1677 vers := string(bytes.Split(out, []byte("("))[0])
1678 subvers := strings.Split(vers, ".")
1679 if len(subvers) != 3 {
1680 return false, fmt.Errorf("cannot parse %s -Wl,-V (%s): %v\n", extld, out, err)
1681 }
1682 if v, err := strconv.Atoi(subvers[0]); err != nil || v < 7 {
1683 return false, nil
1684 } else if v > 7 {
1685 return true, nil
1686 }
1687 if v, err := strconv.Atoi(subvers[1]); err != nil || v < 2 {
1688 return false, nil
1689 } else if v > 2 {
1690 return true, nil
1691 }
1692 if v, err := strconv.Atoi(subvers[2]); err != nil || v < 2 {
1693 return false, nil
1694 }
1695 return true, nil
1696 }
1697
View as plain text