@@ -33,7 +33,6 @@ import (
3333 "github.com/go-delve/delve/pkg/internal/gosym"
3434 "github.com/go-delve/delve/pkg/logflags"
3535 "github.com/go-delve/delve/pkg/proc/debuginfod"
36- "github.com/go-delve/gore"
3736 "github.com/hashicorp/golang-lru/simplelru"
3837)
3938
@@ -1458,25 +1457,30 @@ func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, w
14581457 }
14591458 cu := & compileUnit {}
14601459 cu .image = image
1461- symTable , _ , err := readPcLnTableElf (elfFile , path )
1460+ symTable , symTabAddr , err := readPcLnTableElf (elfFile , path )
14621461 if err != nil {
14631462 return fmt .Errorf ("could not read debug info (%v) and could not read go symbol table (%v)" , dwerr , err )
14641463 }
14651464 image .symTable = symTable
1466- gorefile , err := gore . Open ( path )
1465+ noPtrSectionData , err := elfFile . Section ( ".noptrdata" ). Data ( )
14671466 if err != nil {
14681467 return err
14691468 }
1470- md , err := gorefile . Moduledata ( )
1469+ md , err := parseModuleData ( noPtrSectionData , symTabAddr )
14711470 if err != nil {
14721471 return err
14731472 }
1474- prog := gosym .ProgContaining (elfFile , md .GoFuncValue ())
1473+ roDataAddr := elfFile .Section (".rodata" ).Addr
1474+ goFuncVal , err := findGoFuncVal (md , roDataAddr , bi .Arch .ptrSize )
1475+ if err != nil {
1476+ return err
1477+ }
1478+ prog := gosym .ProgContaining (elfFile , goFuncVal )
14751479 inlFuncs := make (map [string ]* Function )
14761480 for _ , f := range image .symTable .Funcs {
14771481 fnEntry := f .Entry + image .StaticBase
14781482 if prog != nil {
1479- inlCalls , err := image .symTable .GetInlineTree (& f , md . GoFuncValue () , prog .Vaddr , prog .ReaderAt )
1483+ inlCalls , err := image .symTable .GetInlineTree (& f , goFuncVal , prog .Vaddr , prog .ReaderAt )
14801484 if err != nil {
14811485 return err
14821486 }
@@ -1549,6 +1553,53 @@ func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, w
15491553 return nil
15501554}
15511555
1556+ func findGoFuncVal (moduleData []byte , roDataAddr uint64 , ptrsize int ) (uint64 , error ) {
1557+ buf := new (bytes.Buffer )
1558+ err := binary .Write (buf , binary .LittleEndian , & roDataAddr )
1559+ if err != nil {
1560+ return 0 , err
1561+ }
1562+ // Here we search for the value of `go.func.*` by searching through the raw bytes of the
1563+ // runtime.moduledata structure. Since we don't know the value that we are looking for,
1564+ // we use a known value, in this case the address of the .rodata section.
1565+ // This is because in the layout of the struct, the rodata member is right next to
1566+ // the value we need, making the math trivial once we find that member.
1567+ // We use `bytes.LastIndex` specifically because the `types` struct member can also
1568+ // contain the address of the .rodata section, so this pointer can appear multiple times
1569+ // in the raw bytes.
1570+ // Yes, this is very ill-advised low-level hackery but it works fine until
1571+ // https://github.com/golang/go/issues/58474#issuecomment-1785681472 happens.
1572+ // This code path also only runs in stripped binaries, so the whole implementation is
1573+ // best effort anyways.
1574+ rodata := bytes .LastIndex (moduleData , buf .Bytes ()[:ptrsize ])
1575+ if rodata == - 1 {
1576+ return 0 , errors .New ("could not find rodata struct member" )
1577+ }
1578+ // Layout of struct members is:
1579+ // type moduledata struct {
1580+ // ...
1581+ // rodata uintptr
1582+ // gofunc uintptr
1583+ // ...
1584+ // }
1585+ // So do some pointer arithmetic to get the value we need.
1586+ gofuncval := binary .LittleEndian .Uint64 (moduleData [rodata + (1 * ptrsize ) : rodata + (2 * ptrsize )])
1587+ return gofuncval , nil
1588+ }
1589+
1590+ func parseModuleData (dataSection []byte , tableAddr uint64 ) ([]byte , error ) {
1591+ buf := new (bytes.Buffer )
1592+ err := binary .Write (buf , binary .LittleEndian , & tableAddr )
1593+ if err != nil {
1594+ return nil , err
1595+ }
1596+ off := bytes .Index (dataSection , buf .Bytes ()[:4 ])
1597+ if off == - 1 {
1598+ return nil , errors .New ("could not find moduledata" )
1599+ }
1600+ return dataSection [off : off + 0x300 ], nil
1601+ }
1602+
15521603// _STT_FUNC is a code object, see /usr/include/elf.h for a full definition.
15531604const _STT_FUNC = 2
15541605
@@ -1866,27 +1917,32 @@ func loadBinaryInfoMacho(bi *BinaryInfo, image *Image, path string, entryPoint u
18661917 if len (bi .Images ) <= 1 {
18671918 fmt .Fprintln (os .Stderr , "Warning: no debug info found, some functionality will be missing such as stack traces and variable evaluation." )
18681919 }
1869- symTable , err := readPcLnTableMacho (exe , path )
1920+ symTable , symTabAddr , err := readPcLnTableMacho (exe , path )
18701921 if err != nil {
18711922 return fmt .Errorf ("could not read debug info (%v) and could not read go symbol table (%v)" , dwerr , err )
18721923 }
18731924 image .symTable = symTable
18741925 cu := & compileUnit {}
18751926 cu .image = image
1876- gorefile , err := gore .Open (path )
1927+ noPtrSectionData , err := exe .Section ("__noptrdata" ).Data ()
1928+ if err != nil {
1929+ return err
1930+ }
1931+ md , err := parseModuleData (noPtrSectionData , symTabAddr )
18771932 if err != nil {
18781933 return err
18791934 }
1880- md , err := gorefile .Moduledata ()
1935+ roDataAddr := exe .Section ("__rodata" ).Addr
1936+ goFuncVal , err := findGoFuncVal (md , roDataAddr , bi .Arch .ptrSize )
18811937 if err != nil {
18821938 return err
18831939 }
1884- seg := gosym .SegmentContaining (exe , md . GoFuncValue () )
1940+ seg := gosym .SegmentContaining (exe , goFuncVal )
18851941 inlFuncs := make (map [string ]* Function )
18861942 for _ , f := range image .symTable .Funcs {
18871943 fnEntry := f .Entry + image .StaticBase
18881944 if seg != nil {
1889- inlCalls , err := image .symTable .GetInlineTree (& f , md . GoFuncValue () , seg .Addr , seg .ReaderAt )
1945+ inlCalls , err := image .symTable .GetInlineTree (& f , goFuncVal , seg .Addr , seg .ReaderAt )
18901946 if err != nil {
18911947 return err
18921948 }
0 commit comments