
Implement basic api for figuring out, given a current PC value, where the function will return. Currently the API provides only a way to determine the offset from SP (the Canonical Frame Address). It is left up to the caller to grab the actual address from the traced program.
106 lines
1.8 KiB
Go
106 lines
1.8 KiB
Go
package frame
|
|
|
|
import (
|
|
"debug/elf"
|
|
"debug/gosym"
|
|
"encoding/binary"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"github.com/derekparker/dbg/_helper"
|
|
"github.com/derekparker/dbg/proctl"
|
|
)
|
|
|
|
var testfile string
|
|
|
|
func init() {
|
|
testfile, _ = filepath.Abs("../_fixtures/testprog")
|
|
}
|
|
|
|
func parseGoSym(t *testing.T, exe *elf.File) *gosym.Table {
|
|
symdat, err := exe.Section(".gosymtab").Data()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pclndat, err := exe.Section(".gopclntab").Data()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pcln := gosym.NewLineTable(pclndat, exe.Section(".text").Addr)
|
|
tab, err := gosym.NewTable(symdat, pcln)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return tab
|
|
}
|
|
|
|
func gosymData(t *testing.T) *gosym.Table {
|
|
f, err := os.Open(testfile)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
e, err := elf.NewFile(f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return parseGoSym(t, e)
|
|
}
|
|
|
|
func TestFindReturnAddress(t *testing.T) {
|
|
var (
|
|
dbframe = grabDebugFrameSection(testfile, t)
|
|
fdes = Parse(dbframe)
|
|
gsd = gosymData(t)
|
|
)
|
|
|
|
helper.WithTestProcess("testprog", t, func(p *proctl.DebuggedProcess) {
|
|
testsourcefile := testfile + ".go"
|
|
start, _, err := gsd.LineToPC(testsourcefile, 9)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = p.Break(uintptr(start))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = p.Continue()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
regs, err := p.Registers()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
end, _, err := gsd.LineToPC(testsourcefile, 19)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ret, err := fdes.FindReturnAddressOffset(start)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
addr := regs.Rsp + ret
|
|
data := make([]byte, 8)
|
|
|
|
syscall.PtracePeekText(p.Pid, uintptr(addr), data)
|
|
addr = binary.LittleEndian.Uint64(data)
|
|
|
|
if addr != end {
|
|
t.Fatalf("return address not found correctly, expected %#v got %#v", end, ret)
|
|
}
|
|
})
|
|
}
|