@@ -14,6 +14,7 @@ import (
14
14
"golang.org/x/debug/dwtest"
15
15
"golang.org/x/debug/internal/core"
16
16
17
+ "golang.org/x/debug/third_party/delve/dwarf/godwarf"
17
18
"golang.org/x/debug/third_party/delve/dwarf/loclist"
18
19
"golang.org/x/debug/third_party/delve/dwarf/op"
19
20
"golang.org/x/debug/third_party/delve/dwarf/regnum"
@@ -386,15 +387,40 @@ func readDWARFVars(p *core.Process, fns *funcTab, dwarfTypeMap map[dwarf.Type]*T
386
387
if err != nil {
387
388
return nil , fmt .Errorf ("failed to read DWARF: %v" , err )
388
389
}
390
+ dLocListsSec , derr := p .DWARFLocLists ()
391
+ if derr != nil {
392
+ return nil , fmt .Errorf ("failed to read DWARF: %v" , derr )
393
+ }
394
+ dAddrSec , daerr := p .DWARFAddr ()
395
+ if daerr != nil {
396
+ return nil , fmt .Errorf ("failed to read DWARF: %v" , daerr )
397
+ }
398
+ debugAddrSec := godwarf .ParseAddr (dAddrSec )
389
399
vars := make (map [* Func ][]dwarfVar )
390
400
var curfn * Func
391
401
r := d .Reader ()
402
+ addrBase := uint64 (0 )
403
+ unitVersion := 4
392
404
for e , err := r .Next (); e != nil && err == nil ; e , err = r .Next () {
393
405
if isNonGoCU (e ) {
394
406
r .SkipChildren ()
395
407
continue
396
408
}
397
-
409
+ if e .Tag == dwarf .TagCompileUnit {
410
+ // Determine whether we're looking at DWARF version 5 or
411
+ // some version prior to 5. At the moment the DWARF
412
+ // reading machinery in debug/dwarf keeps track of DWARF
413
+ // version for each unit but doesn't expose this info to
414
+ // clients, so we need to do the detection indirectly,
415
+ // here by looking for an attribute that only gets generated
416
+ // if DWARF 5 is being used.
417
+ if f := e .AttrField (dwarf .AttrAddrBase ); f != nil {
418
+ addrBase = uint64 (f .Val .(int64 ))
419
+ unitVersion = 5
420
+ } else {
421
+ unitVersion = 4
422
+ }
423
+ }
398
424
if e .Tag == dwarf .TagSubprogram {
399
425
if e .AttrField (dwarf .AttrLowpc ) == nil ||
400
426
e .AttrField (dwarf .AttrHighpc ) == nil {
@@ -459,30 +485,74 @@ func readDWARFVars(p *core.Process, fns *funcTab, dwarfTypeMap map[dwarf.Type]*T
459
485
}
460
486
name := nf .Val .(string )
461
487
462
- // No .debug_loc section, can't make progress.
463
- if len (dLocSec ) == 0 {
464
- continue
465
- }
488
+ // FIXME A note on the code above: we're screening out
489
+ // variables that don't have a specific name and type, which
490
+ // on the surface seems workable, however this also rejects
491
+ // vars corresponding to "concrete" instances of vars that
492
+ // have been inlined, which is almost certainly a mistake. For
493
+ // more on concrete/abstract variables see
494
+ // https://github.com/golang/proposal/blob/master/design/22080-dwarf-inlining.md#how-the-generated-dwarf-should-look,
495
+ // which has examples. Instead what the code above should be
496
+ // doing is caching any abstract variables it encounters in a
497
+ // map (indexed by DWARF offset), then when it encounters a
498
+ // concrete var, pick the name and type up from the abstract
499
+ // variable.
500
+
501
+ switch unitVersion {
502
+ case 5 :
503
+ {
504
+ // No .debug_loclists section, can't make progress.
505
+ if len (dLocListsSec ) == 0 {
506
+ continue
507
+ }
466
508
467
- // Read the location list.
468
- locListOff := aloc .Val .(int64 )
469
- dr := loclist .NewDwarf2Reader (dLocSec , int (p .PtrSize ()))
470
- dr .Seek (int (locListOff ))
471
- var base uint64
472
- var e loclist.Entry
473
- for dr .Next (& e ) {
474
- if e .BaseAddressSelection () {
475
- base = e .HighPC + p .StaticBase ()
476
- continue
509
+ debugAddr := debugAddrSec .GetSubsection (addrBase )
510
+ // Read the location lists.
511
+ locListOff := aloc .Val .(int64 )
512
+ dr := loclist .NewDwarf5Reader (dLocListsSec )
513
+ elist , err := dr .Enumerate (locListOff , p .StaticBase (), debugAddr )
514
+ if err != nil {
515
+ return nil , err
516
+ }
517
+ for _ , e := range elist {
518
+ vars [curfn ] = append (vars [curfn ], dwarfVar {
519
+ lowPC : core .Address (e .LowPC ),
520
+ highPC : core .Address (e .HighPC ),
521
+ kind : kind ,
522
+ instr : e .Instr ,
523
+ name : name ,
524
+ typ : dwarfTypeMap [dt ],
525
+ })
526
+ }
527
+ }
528
+ default :
529
+ {
530
+ // No .debug_loc section, can't make progress.
531
+ if len (dLocSec ) == 0 {
532
+ continue
533
+ }
534
+
535
+ // Read the location list.
536
+ locListOff := aloc .Val .(int64 )
537
+ dr := loclist .NewDwarf2Reader (dLocSec , int (p .PtrSize ()))
538
+ dr .Seek (int (locListOff ))
539
+ var base uint64
540
+ var e loclist.Entry
541
+ for dr .Next (& e ) {
542
+ if e .BaseAddressSelection () {
543
+ base = e .HighPC + p .StaticBase ()
544
+ continue
545
+ }
546
+ vars [curfn ] = append (vars [curfn ], dwarfVar {
547
+ lowPC : core .Address (e .LowPC + base ),
548
+ highPC : core .Address (e .HighPC + base ),
549
+ kind : kind ,
550
+ instr : e .Instr ,
551
+ name : name ,
552
+ typ : dwarfTypeMap [dt ],
553
+ })
554
+ }
477
555
}
478
- vars [curfn ] = append (vars [curfn ], dwarfVar {
479
- lowPC : core .Address (e .LowPC + base ),
480
- highPC : core .Address (e .HighPC + base ),
481
- kind : kind ,
482
- instr : e .Instr ,
483
- name : name ,
484
- typ : dwarfTypeMap [dt ],
485
- })
486
556
}
487
557
}
488
558
return vars , nil
0 commit comments