From 99b614a0282e8883eda4e53b8bda0efa91d79921 Mon Sep 17 00:00:00 2001 From: epipho Date: Mon, 19 Jan 2015 23:15:40 -0500 Subject: [PATCH] Adding support for reading function pointers and mapping them to function names --- _fixtures/testvariables.go | 3 ++- proctl/variables.go | 34 ++++++++++++++++++++++++++++++++++ proctl/variables_test.go | 8 +++++--- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/_fixtures/testvariables.go b/_fixtures/testvariables.go index fb27dae3..7f1ddd23 100644 --- a/_fixtures/testvariables.go +++ b/_fixtures/testvariables.go @@ -41,10 +41,11 @@ func foobar(baz string, bar FooBar) { up = uintptr(5) f32 = float32(1.2) i32 = [2]int32{1, 2} + f = barfoo ) barfoo() - fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, b1, b2, baz, neg, i8, u8, u16, u32, u64, up, f32, i32, bar) + fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, b1, b2, baz, neg, i8, u8, u16, u32, u64, up, f32, i32, bar, f) } func main() { diff --git a/proctl/variables.go b/proctl/variables.go index 1be8a191..71a15ac4 100644 --- a/proctl/variables.go +++ b/proctl/variables.go @@ -622,6 +622,10 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i return thread.readFloat(ptraddress, t.ByteSize) case *dwarf.BoolType: return thread.readBool(ptraddress) + case *dwarf.FuncType: + return thread.readFunctionPtr(ptraddress) + default: + fmt.Printf("Unknown type: %T\n", t) } return "", fmt.Errorf("could not find value for type %s", typ) @@ -774,6 +778,36 @@ func (thread *ThreadContext) readBool(addr uintptr) (string, error) { return "true", nil } +func (thread *ThreadContext) readFunctionPtr(addr uintptr) (string, error) { + val, err := thread.readMemory(addr, ptrsize) + if err != nil { + return "", err + } + + // dereference pointer to find function pc + addr = uintptr(binary.LittleEndian.Uint64(val)) + + val, err = thread.readMemory(addr, ptrsize) + if err != nil { + return "", err + } + + funcAddr := binary.LittleEndian.Uint64(val) + reader := thread.Process.DwarfReader() + + entry, err := reader.SeekToFunction(funcAddr) + if err != nil { + return "", err + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + return "", fmt.Errorf("Unable to retrieve function name") + } + + return n, nil +} + func (thread *ThreadContext) readMemory(addr uintptr, size uintptr) ([]byte, error) { buf := make([]byte, size) diff --git a/proctl/variables_test.go b/proctl/variables_test.go index ab1d1202..1d8517ed 100644 --- a/proctl/variables_test.go +++ b/proctl/variables_test.go @@ -64,11 +64,12 @@ func TestVariableEvaluation(t *testing.T) { {"u64", "18446744073709551615", "uint64", nil}, {"u8", "255", "uint8", nil}, {"up", "5", "uintptr", nil}, + {"f", "main.barfoo", "func()", nil}, {"NonExistent", "", "", errors.New("could not find symbol value for NonExistent")}, } withTestProcess(executablePath, t, func(p *DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 46) + pc, _, _ := p.GoSymTable.LineToPC(fp, 47) _, err := p.Break(pc) assertNoError(err, t, "Break() returned an error") @@ -99,7 +100,7 @@ func TestVariableFunctionScoping(t *testing.T) { } withTestProcess(executablePath, t, func(p *DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 46) + pc, _, _ := p.GoSymTable.LineToPC(fp, 47) _, err := p.Break(pc) assertNoError(err, t, "Break() returned an error") @@ -175,6 +176,7 @@ func TestLocalVariables(t *testing.T) { {"a9", "*main.FooBar nil", "*main.FooBar", nil}, {"b1", "true", "bool", nil}, {"b2", "false", "bool", nil}, + {"f", "main.barfoo", "func()", nil}, {"f32", "1.2", "float32", nil}, {"i32", "[2]int32 [1 2]", "[2]int32", nil}, {"i8", "1", "int8", nil}, @@ -191,7 +193,7 @@ func TestLocalVariables(t *testing.T) { } withTestProcess(executablePath, t, func(p *DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 46) + pc, _, _ := p.GoSymTable.LineToPC(fp, 47) _, err := p.Break(pc) assertNoError(err, t, "Break() returned an error")