forked from lizrice/debugger-from-scratch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
output.go
66 lines (54 loc) · 1.41 KB
/
output.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package main
import (
"debug/gosym"
"encoding/binary"
"fmt"
"syscall"
)
func outputStack(symTable *gosym.Table, pid int, ip uint64, sp uint64, bp uint64) {
_, _, fn = symTable.PCToLine(ip)
var i uint64
var nextbp uint64
for {
i = 0
frameSize := bp - sp + 8
// If we look at bp / sp while they are being updated we can
// get some odd results
if frameSize > 1000 || bp == 0 {
fmt.Printf("Strange frame size: SP: %X | BP : %X \n", sp, bp)
frameSize = 32
bp = sp + frameSize - 8
}
// Read the next stack frame
b := make([]byte, frameSize)
_, err := syscall.PtracePeekData(pid, uintptr(sp), b)
if err != nil {
panic(err)
}
// The address to return to is at the top of the frame
content := binary.LittleEndian.Uint64(b[i : i+8])
_, lineno, nextfn := symTable.PCToLine(content)
if nextfn != nil {
fn = nextfn
fmt.Printf(" called by %s line %d\n", fn.Name, lineno)
}
// Rest of the frame
for i = 8; sp+i <= bp; i += 8 {
content := binary.LittleEndian.Uint64(b[i : i+8])
if sp+i == bp {
nextbp = content
}
// fmt.Printf(" %X %X \n", sp+i, content)
}
// We want to stop the stack trace at main.main.
// At the point where bp & sp are being updated we may
// miss main.main, so we backstop with runtime.main.
if fn.Name == "main.main" || fn.Name == "runtime.main" {
break
}
// Move to the next frame
sp = sp + i
bp = nextbp
}
fmt.Println()
}