pkg/proc: enable basic debug functionality for stripped ELF binaries (#3408)
We used to parse the .gopclntab section but removed support in favor of simply using DWARF debug information, due to lack of C symbols among other reasons. This makes it impossible to debug stripped binaries, which some distrubutions ship by default. Add back in basic support for .gopclntab which survives if the binary is stripped, allowing for rudimentary debugging such as basic program navigation, tracing, etc...
This commit is contained in:
parent
7d8f47674b
commit
ccf17a6f42
@ -26,7 +26,6 @@ import (
|
||||
"github.com/go-delve/delve/pkg/terminal"
|
||||
"github.com/go-delve/delve/service/dap"
|
||||
"github.com/go-delve/delve/service/dap/daptest"
|
||||
"github.com/go-delve/delve/service/debugger"
|
||||
"github.com/go-delve/delve/service/rpc2"
|
||||
godap "github.com/google/go-dap"
|
||||
"golang.org/x/tools/go/packages"
|
||||
@ -282,57 +281,6 @@ func TestContinue(t *testing.T) {
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
// TestChildProcessExitWhenNoDebugInfo verifies that the child process exits when dlv launch the binary without debug info
|
||||
func TestChildProcessExitWhenNoDebugInfo(t *testing.T) {
|
||||
noDebugFlags := protest.LinkStrip
|
||||
// -s doesn't strip symbols on Mac, use -w instead
|
||||
if runtime.GOOS == "darwin" {
|
||||
noDebugFlags = protest.LinkDisableDWARF
|
||||
}
|
||||
|
||||
if _, err := exec.LookPath("ps"); err != nil {
|
||||
t.Skip("test skipped, `ps` not found")
|
||||
}
|
||||
|
||||
dlvbin := getDlvBin(t)
|
||||
|
||||
fix := protest.BuildFixture("http_server", noDebugFlags)
|
||||
|
||||
// dlv exec the binary file and expect error.
|
||||
out, err := exec.Command(dlvbin, "exec", "--headless", "--log", fix.Path).CombinedOutput()
|
||||
t.Log(string(out))
|
||||
if err == nil {
|
||||
t.Fatalf("Expected err when launching the binary without debug info, but got nil")
|
||||
}
|
||||
// Test only for dlv's prefix of the error like "could not launch process: could not open debug info"
|
||||
if !strings.Contains(string(out), "could not launch process") || !strings.Contains(string(out), debugger.NoDebugWarning) {
|
||||
t.Fatalf("Expected logged error 'could not launch process: ... - %s'", debugger.NoDebugWarning)
|
||||
}
|
||||
|
||||
// search the running process named fix.Name
|
||||
cmd := exec.Command("ps", "-aux")
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
assertNoError(err, t, "stdout pipe")
|
||||
defer stdout.Close()
|
||||
|
||||
assertNoError(cmd.Start(), t, "start `ps -aux`")
|
||||
|
||||
var foundFlag bool
|
||||
scan := bufio.NewScanner(stdout)
|
||||
for scan.Scan() {
|
||||
t.Log(scan.Text())
|
||||
if strings.Contains(scan.Text(), fix.Name) {
|
||||
foundFlag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
cmd.Wait()
|
||||
|
||||
if foundFlag {
|
||||
t.Fatalf("Expected child process exited, but found it running")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRedirect verifies that redirecting stdin works
|
||||
func TestRedirect(t *testing.T) {
|
||||
const listenAddr = "127.0.0.1:40573"
|
||||
@ -711,57 +659,6 @@ func TestDAPCmd(t *testing.T) {
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
func TestDAPCmdWithNoDebugBinary(t *testing.T) {
|
||||
const listenAddr = "127.0.0.1:40579"
|
||||
|
||||
dlvbin := getDlvBin(t)
|
||||
|
||||
cmd := exec.Command(dlvbin, "dap", "--log", "--listen", listenAddr)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
assertNoError(err, t, "stdout pipe")
|
||||
defer stdout.Close()
|
||||
stderr, err := cmd.StderrPipe()
|
||||
assertNoError(err, t, "stderr pipe")
|
||||
defer stderr.Close()
|
||||
assertNoError(cmd.Start(), t, "start dap instance")
|
||||
|
||||
scanOut := bufio.NewScanner(stdout)
|
||||
scanErr := bufio.NewScanner(stderr)
|
||||
// Wait for the debug server to start
|
||||
scanOut.Scan()
|
||||
listening := "DAP server listening at: " + listenAddr
|
||||
if scanOut.Text() != listening {
|
||||
cmd.Process.Kill() // release the port
|
||||
t.Fatalf("Unexpected stdout:\ngot %q\nwant %q", scanOut.Text(), listening)
|
||||
}
|
||||
go func() { // Capture logging
|
||||
for scanErr.Scan() {
|
||||
t.Log(scanErr.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
// Exec the stripped debuggee and expect things to fail
|
||||
noDebugFlags := protest.LinkStrip
|
||||
// -s doesn't strip symbols on Mac, use -w instead
|
||||
if runtime.GOOS == "darwin" {
|
||||
noDebugFlags = protest.LinkDisableDWARF
|
||||
}
|
||||
fixture := protest.BuildFixture("increment", noDebugFlags)
|
||||
go func() {
|
||||
for scanOut.Scan() {
|
||||
t.Errorf("Unexpected stdout: %s", scanOut.Text())
|
||||
}
|
||||
}()
|
||||
client := daptest.NewClient(listenAddr)
|
||||
client.LaunchRequest("exec", fixture.Path, false)
|
||||
client.ExpectErrorResponse(t)
|
||||
client.DisconnectRequest()
|
||||
client.ExpectDisconnectResponse(t)
|
||||
client.ExpectTerminatedEvent(t)
|
||||
client.Close()
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
func newDAPRemoteClient(t *testing.T, addr string, isDlvAttach bool, isMulti bool) *daptest.Client {
|
||||
c := daptest.NewClient(addr)
|
||||
c.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"debug/dwarf"
|
||||
"debug/elf"
|
||||
"debug/gosym"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
@ -332,7 +333,7 @@ func FindFunctionLocation(p Process, funcName string, lineOffset int) ([]uint64,
|
||||
|
||||
if lineOffset > 0 {
|
||||
fn := origfns[0]
|
||||
filename, lineno := fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry)
|
||||
filename, lineno := bi.EntryLineForFunc(fn)
|
||||
return FindFileLocation(p, filename, lineno+lineOffset)
|
||||
}
|
||||
|
||||
@ -364,14 +365,16 @@ func FindFunctionLocation(p Process, funcName string, lineOffset int) ([]uint64,
|
||||
// If sameline is set FirstPCAfterPrologue will always return an
|
||||
// address associated with the same line as fn.Entry.
|
||||
func FirstPCAfterPrologue(p Process, fn *Function, sameline bool) (uint64, error) {
|
||||
pc, _, line, ok := fn.cu.lineInfo.PrologueEndPC(fn.Entry, fn.End)
|
||||
if ok {
|
||||
if !sameline {
|
||||
return pc, nil
|
||||
}
|
||||
_, entryLine := fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry)
|
||||
if entryLine == line {
|
||||
return pc, nil
|
||||
if fn.cu.lineInfo != nil {
|
||||
pc, _, line, ok := fn.cu.lineInfo.PrologueEndPC(fn.Entry, fn.End)
|
||||
if ok {
|
||||
if !sameline {
|
||||
return pc, nil
|
||||
}
|
||||
_, entryLine := p.BinInfo().EntryLineForFunc(fn)
|
||||
if entryLine == line {
|
||||
return pc, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,7 +383,7 @@ func FirstPCAfterPrologue(p Process, fn *Function, sameline bool) (uint64, error
|
||||
return fn.Entry, err
|
||||
}
|
||||
|
||||
if pc == fn.Entry {
|
||||
if pc == fn.Entry && fn.cu.lineInfo != nil {
|
||||
// Look for the first instruction with the stmt flag set, so that setting a
|
||||
// breakpoint with file:line and with the function name always result on
|
||||
// the same instruction being selected.
|
||||
@ -601,6 +604,25 @@ func (fn *Function) PrologueEndPC() uint64 {
|
||||
return pc
|
||||
}
|
||||
|
||||
func (fn *Function) AllPCs(excludeFile string, excludeLine int) ([]uint64, error) {
|
||||
if !fn.cu.image.Stripped() {
|
||||
return fn.cu.lineInfo.AllPCsBetween(fn.Entry, fn.End-1, excludeFile, excludeLine)
|
||||
}
|
||||
var pcs []uint64
|
||||
fnFile, lastLine, _ := fn.cu.image.symTable.PCToLine(fn.Entry)
|
||||
for pc := fn.Entry; pc < fn.End; pc++ {
|
||||
f, line, pcfn := fn.cu.image.symTable.PCToLine(pc)
|
||||
if pcfn == nil {
|
||||
continue
|
||||
}
|
||||
if f == fnFile && line > lastLine {
|
||||
lastLine = line
|
||||
pcs = append(pcs, pc)
|
||||
}
|
||||
}
|
||||
return pcs, nil
|
||||
}
|
||||
|
||||
// From $GOROOT/src/runtime/traceback.go:597
|
||||
// exportedRuntime reports whether the function is an exported runtime function.
|
||||
// It is only for runtime functions, so ASCII A-Z is fine.
|
||||
@ -719,6 +741,9 @@ func (bi *BinaryInfo) LastModified() time.Time {
|
||||
|
||||
// DwarfReader returns a reader for the dwarf data
|
||||
func (so *Image) DwarfReader() *reader.Reader {
|
||||
if so.dwarf == nil {
|
||||
return nil
|
||||
}
|
||||
return reader.New(so.dwarf)
|
||||
}
|
||||
|
||||
@ -731,13 +756,26 @@ func (bi *BinaryInfo) Types() ([]string, error) {
|
||||
return types, nil
|
||||
}
|
||||
|
||||
func (bi *BinaryInfo) EntryLineForFunc(fn *Function) (string, int) {
|
||||
return bi.pcToLine(fn, fn.Entry)
|
||||
}
|
||||
|
||||
func (bi *BinaryInfo) pcToLine(fn *Function, pc uint64) (string, int) {
|
||||
if fn.cu.lineInfo == nil {
|
||||
f, l, _ := fn.cu.image.symTable.PCToLine(pc)
|
||||
return f, l
|
||||
}
|
||||
f, l := fn.cu.lineInfo.PCToLine(fn.Entry, pc)
|
||||
return f, l
|
||||
}
|
||||
|
||||
// PCToLine converts an instruction address to a file/line/function.
|
||||
func (bi *BinaryInfo) PCToLine(pc uint64) (string, int, *Function) {
|
||||
fn := bi.PCToFunc(pc)
|
||||
if fn == nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
f, ln := fn.cu.lineInfo.PCToLine(fn.Entry, pc)
|
||||
f, ln := bi.pcToLine(fn, pc)
|
||||
return f, ln, fn
|
||||
}
|
||||
|
||||
@ -810,6 +848,8 @@ type Image struct {
|
||||
debugAddr *godwarf.DebugAddrSection
|
||||
debugLineStr []byte
|
||||
|
||||
symTable *gosym.Table
|
||||
|
||||
typeCache map[dwarf.Offset]godwarf.Type
|
||||
|
||||
compileUnits []*compileUnit // compileUnits is sorted by increasing DWARF offset
|
||||
@ -835,6 +875,10 @@ func (image *Image) registerRuntimeTypeToDIE(entry *dwarf.Entry, ardr *reader.Re
|
||||
}
|
||||
}
|
||||
|
||||
func (image *Image) Stripped() bool {
|
||||
return image.dwarf == nil
|
||||
}
|
||||
|
||||
// AddImage adds the specified image to bi, loading data asynchronously.
|
||||
// Addr is the relocated entry point for the executable and staticBase (i.e.
|
||||
// the relocation offset) for all other images.
|
||||
@ -1405,7 +1449,22 @@ func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, w
|
||||
var serr error
|
||||
sepFile, dwarfFile, serr = bi.openSeparateDebugInfo(image, elfFile, bi.DebugInfoDirectories)
|
||||
if serr != nil {
|
||||
return serr
|
||||
fmt.Fprintln(os.Stderr, "Warning: no debug info found, some functionality will be missing such as stack traces and variable evaluation.")
|
||||
symTable, err := readPcLnTableElf(elfFile, path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create symbol table from %s ", path)
|
||||
}
|
||||
image.symTable = symTable
|
||||
for _, f := range image.symTable.Funcs {
|
||||
cu := &compileUnit{}
|
||||
cu.image = image
|
||||
fn := Function{Name: f.Name, Entry: f.Entry, End: f.End, cu: cu}
|
||||
bi.Functions = append(bi.Functions, fn)
|
||||
}
|
||||
for f := range image.symTable.Files {
|
||||
bi.Sources = append(bi.Sources, f)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
image.sepDebugCloser = sepFile
|
||||
image.dwarf, err = dwarfFile.DWARF()
|
||||
|
@ -554,7 +554,7 @@ func (t *Target) setEBPFTracepointOnFunc(fn *Function, goidOffset int64) error {
|
||||
if t.BinInfo().Producer() != "" && goversion.ProducerAfterOrEqual(t.BinInfo().Producer(), 1, 15) {
|
||||
variablesFlags |= reader.VariablesTrustDeclLine
|
||||
}
|
||||
_, l, _ := t.BinInfo().PCToLine(fn.Entry)
|
||||
_, l := t.BinInfo().EntryLineForFunc(fn)
|
||||
|
||||
var args []ebpf.UProbeArgMap
|
||||
varEntries := reader.Variables(dwarfTree, fn.Entry, l, variablesFlags)
|
||||
|
@ -1053,7 +1053,7 @@ func readStackVariable(t *Target, thread Thread, regs Registers, off uint64, typ
|
||||
func fakeFunctionEntryScope(scope *EvalScope, fn *Function, cfa int64, sp uint64) error {
|
||||
scope.PC = fn.Entry
|
||||
scope.Fn = fn
|
||||
scope.File, scope.Line, _ = scope.BinInfo.PCToLine(fn.Entry)
|
||||
scope.File, scope.Line = scope.BinInfo.EntryLineForFunc(fn)
|
||||
|
||||
scope.Regs.CFA = cfa
|
||||
scope.Regs.Reg(scope.Regs.SPRegNum).Uint64Val = sp
|
||||
|
@ -12,6 +12,9 @@ func (gcache *goroutineCache) init(bi *BinaryInfo) {
|
||||
|
||||
exeimage := bi.Images[0]
|
||||
rdr := exeimage.DwarfReader()
|
||||
if rdr == nil {
|
||||
return
|
||||
}
|
||||
|
||||
gcache.allglenAddr, _ = rdr.AddrFor("runtime.allglen", exeimage.StaticBase, bi.Arch.PtrSize())
|
||||
|
||||
|
75
pkg/proc/pclntab.go
Normal file
75
pkg/proc/pclntab.go
Normal file
@ -0,0 +1,75 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/buildinfo"
|
||||
"debug/elf"
|
||||
"debug/gosym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// From go/src/debug/gosym/pclntab.go
|
||||
const (
|
||||
go12magic = 0xfffffffb
|
||||
go116magic = 0xfffffffa
|
||||
go118magic = 0xfffffff0
|
||||
go120magic = 0xfffffff1
|
||||
)
|
||||
|
||||
// Select the magic number based on the Go version
|
||||
func magicNumber(goVersion string) []byte {
|
||||
bs := make([]byte, 4)
|
||||
var magic uint32
|
||||
if strings.Compare(goVersion, "go1.20") >= 0 {
|
||||
magic = go120magic
|
||||
} else if strings.Compare(goVersion, "go1.18") >= 0 {
|
||||
magic = go118magic
|
||||
} else if strings.Compare(goVersion, "go1.16") >= 0 {
|
||||
magic = go116magic
|
||||
} else {
|
||||
magic = go12magic
|
||||
}
|
||||
binary.LittleEndian.PutUint32(bs, magic)
|
||||
return bs
|
||||
}
|
||||
|
||||
func readPcLnTableElf(exe *elf.File, path string) (*gosym.Table, error) {
|
||||
// Default section label is .gopclntab
|
||||
sectionLabel := ".gopclntab"
|
||||
|
||||
section := exe.Section(sectionLabel)
|
||||
if section == nil {
|
||||
// binary may be built with -pie
|
||||
sectionLabel = ".data.rel.ro"
|
||||
section = exe.Section(sectionLabel)
|
||||
if section == nil {
|
||||
return nil, fmt.Errorf("could not read section .gopclntab")
|
||||
}
|
||||
}
|
||||
tableData, err := section.Data()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("found section but could not read .gopclntab")
|
||||
}
|
||||
|
||||
bi, err := buildinfo.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Find .gopclntab by magic number even if there is no section label
|
||||
magic := magicNumber(bi.GoVersion)
|
||||
pclntabIndex := bytes.Index(tableData, magic)
|
||||
if pclntabIndex < 0 {
|
||||
return nil, fmt.Errorf("could not find magic number in %s ", path)
|
||||
}
|
||||
tableData = tableData[pclntabIndex:]
|
||||
addr := exe.Section(".text").Addr
|
||||
lineTable := gosym.NewLineTable(tableData, addr)
|
||||
symTable, err := gosym.NewTable([]byte{}, lineTable)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create symbol table from %s ", path)
|
||||
}
|
||||
return symTable, nil
|
||||
}
|
@ -3165,69 +3165,18 @@ func TestShadowedFlag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestAttachStripped(t *testing.T) {
|
||||
if testBackend == "lldb" && runtime.GOOS == "linux" {
|
||||
bs, _ := ioutil.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
|
||||
if bs == nil || strings.TrimSpace(string(bs)) != "0" {
|
||||
t.Logf("can not run TestAttachStripped: %v\n", bs)
|
||||
return
|
||||
}
|
||||
}
|
||||
if testBackend == "rr" {
|
||||
return
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Log("-s does not produce stripped executables on macOS")
|
||||
return
|
||||
}
|
||||
if buildMode != "" {
|
||||
t.Skip("not enabled with buildmode=PIE")
|
||||
}
|
||||
fixture := protest.BuildFixture("testnextnethttp", protest.LinkStrip)
|
||||
cmd := exec.Command(fixture.Path)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
assertNoError(cmd.Start(), t, "starting fixture")
|
||||
|
||||
// wait for testnextnethttp to start listening
|
||||
t0 := time.Now()
|
||||
for {
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:9191")
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if time.Since(t0) > 10*time.Second {
|
||||
t.Fatal("fixture did not start")
|
||||
}
|
||||
}
|
||||
|
||||
var p *proc.TargetGroup
|
||||
var err error
|
||||
|
||||
switch testBackend {
|
||||
case "native":
|
||||
p, err = native.Attach(cmd.Process.Pid, []string{})
|
||||
case "lldb":
|
||||
path := ""
|
||||
if runtime.GOOS == "darwin" {
|
||||
path = fixture.Path
|
||||
}
|
||||
p, err = gdbserial.LLDBAttach(cmd.Process.Pid, path, []string{})
|
||||
default:
|
||||
t.Fatalf("unknown backend %q", testBackend)
|
||||
}
|
||||
|
||||
t.Logf("error is %v", err)
|
||||
|
||||
if err == nil {
|
||||
p.Detach(true)
|
||||
t.Fatalf("expected error after attach, got nothing")
|
||||
} else {
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
os.Remove(fixture.Path)
|
||||
func TestDebugStripped(t *testing.T) {
|
||||
// Currently only implemented for Linux ELF executables.
|
||||
// TODO(derekparker): Add support for Mach-O and PE.
|
||||
skipUnlessOn(t, "linux only", "linux")
|
||||
withTestProcessArgs("testnextprog", t, "", []string{}, protest.LinkStrip, func(p *proc.Target, grp *proc.TargetGroup, f protest.Fixture) {
|
||||
setFunctionBreakpoint(p, t, "main.main")
|
||||
assertNoError(grp.Continue(), t, "Continue")
|
||||
assertCurrentLocationFunction(p, t, "main.main")
|
||||
assertLineNumber(p, t, 37, "first continue")
|
||||
assertNoError(grp.Next(), t, "Next")
|
||||
assertLineNumber(p, t, 38, "after next")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIssue844(t *testing.T) {
|
||||
|
@ -253,6 +253,9 @@ func (it *stackIterator) Err() error {
|
||||
// frameBase calculates the frame base pseudo-register for DWARF for fn and
|
||||
// the current frame.
|
||||
func (it *stackIterator) frameBase(fn *Function) int64 {
|
||||
if fn.cu.image.Stripped() {
|
||||
return 0
|
||||
}
|
||||
dwarfTree, err := fn.cu.image.getDwarfTree(fn.offset)
|
||||
if err != nil {
|
||||
return 0
|
||||
@ -695,6 +698,6 @@ func (d *Defer) DeferredFunc(p *Target) (file string, line int, fn *Function) {
|
||||
if fn == nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
file, line = fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry)
|
||||
file, line = bi.EntryLineForFunc(fn)
|
||||
return file, line, fn
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ func stepInstructionOut(dbp *Target, curthread Thread, fnname1, fnname2 string)
|
||||
}
|
||||
loc, err := curthread.Location()
|
||||
var locFnName string
|
||||
if loc.Fn != nil {
|
||||
if loc.Fn != nil && !loc.Fn.cu.image.Stripped() {
|
||||
locFnName = loc.Fn.Name
|
||||
// Calls to runtime.Breakpoint are inlined in some versions of Go when
|
||||
// inlining is enabled. Here we attempt to resolve any inlining.
|
||||
@ -677,7 +677,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
if !backward {
|
||||
if !backward && !topframe.Current.Fn.cu.image.Stripped() {
|
||||
_, err = setDeferBreakpoint(dbp, text, topframe, sameGCond, stepInto)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -685,7 +685,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
|
||||
}
|
||||
|
||||
// Add breakpoints on all the lines in the current function
|
||||
pcs, err := topframe.Current.Fn.cu.lineInfo.AllPCsBetween(topframe.Current.Fn.Entry, topframe.Current.Fn.End-1, topframe.Current.File, topframe.Current.Line)
|
||||
pcs, err := topframe.Current.Fn.AllPCs(topframe.Current.File, topframe.Current.Line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -865,6 +865,11 @@ func FindDeferReturnCalls(text []AsmInstruction) []uint64 {
|
||||
// If includeCurrentFn is true it will also remove all instructions
|
||||
// belonging to the current function.
|
||||
func removeInlinedCalls(pcs []uint64, topframe Stackframe) ([]uint64, error) {
|
||||
// TODO(derekparker) it should be possible to still use some internal
|
||||
// runtime information to do this.
|
||||
if topframe.Call.Fn == nil || topframe.Call.Fn.cu.image.Stripped() {
|
||||
return pcs, nil
|
||||
}
|
||||
dwarfTree, err := topframe.Call.Fn.cu.image.getDwarfTree(topframe.Call.Fn.offset)
|
||||
if err != nil {
|
||||
return pcs, err
|
||||
@ -1061,7 +1066,7 @@ func skipAutogeneratedWrappersOut(g *G, thread Thread, startTopframe, startRetfr
|
||||
if frame.Current.Fn == nil {
|
||||
return
|
||||
}
|
||||
file, line := frame.Current.Fn.cu.lineInfo.PCToLine(frame.Current.Fn.Entry, frame.Current.Fn.Entry)
|
||||
file, line := g.Thread.BinInfo().EntryLineForFunc(frame.Current.Fn)
|
||||
if !isAutogeneratedOrDeferReturn(Location{File: file, Line: line, Fn: frame.Current.Fn}) {
|
||||
return &frames[i-1], &frames[i]
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ func (g *G) StartLoc(tgt *Target) Location {
|
||||
if fn == nil {
|
||||
return Location{PC: g.StartPC}
|
||||
}
|
||||
f, l := fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry)
|
||||
f, l := tgt.BinInfo().EntryLineForFunc(fn)
|
||||
return Location{PC: fn.Entry, File: f, Line: l, Fn: fn}
|
||||
}
|
||||
|
||||
|
@ -1315,6 +1315,13 @@ func (d *Debugger) collectBreakpointInformation(apiThread *api.Thread, thread pr
|
||||
|
||||
tgt := d.target.TargetForThread(thread.ThreadID())
|
||||
|
||||
// If we're dealing with a stripped binary don't attempt to load more
|
||||
// information, we won't be able to.
|
||||
img := tgt.BinInfo().PCToImage(bp.Addr)
|
||||
if img != nil && img.Stripped() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if bp.Goroutine {
|
||||
g, err := proc.GetG(thread)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user