-
Notifications
You must be signed in to change notification settings - Fork 209
/
stackannotate.star
143 lines (124 loc) · 3.35 KB
/
stackannotate.star
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
word_size = 8 # 64bit only for now
def get_reg(name):
for req in registers().Regs:
if req.Name == name:
return int(req.Value, 16)
def read_word(addr):
v = 0
m = examine_memory(addr, word_size)
s = 1
for b in m.Mem:
v += b * s
s = s * 256
return v
def hex(d, n = 0):
if d == 0:
return lpad("0", n, "0")
lookup = {10: "a", 11: "b", 12: "c", 13: "d", 14: "e", 15: "e", 16: "f"}
s = ""
while d > 0:
r = d % 16
d = d // 16
if r >= 10:
r = lookup[r]
else:
r = str(r)
s = r + s
return lpad(s, n, "0")
def lpad(s, n, c = " "):
while len(s) < n:
s = c + s
return s
def rpad(s, n, c = " "):
while len(s) < n:
s = s + c
return s
def ascii_table(rows, align_right = {}):
widths = []
for row in rows:
for i, col in enumerate(row):
if len(widths) < i+1:
widths.append(0)
widths[i] = max(widths[i], len(col))
s = ""
for row in rows:
for i, col in enumerate(row):
width = widths[i]
if align_right.get(i, False):
col = lpad(col, width)
else:
col = rpad(col, width)
s += col + " "
s += "\n"
return s
def getg():
# TODO(fg) there is probably a better way to implement this.
g = raw_command("goroutine").State.SelectedGoroutine
for gp in eval(None, "runtime.allgs").Variable.Value:
if gp.goid == g.ID:
return gp
def stack():
g = getg()
bp = get_reg("Rbp")
ip = get_reg("Rip")
sp = get_reg("Rsp")
regs = {"sp": sp, "bp": bp, "ip": ip}
addr_list = []
addr_dict = {}
offset = 0
while True:
addr = g.stack.hi+offset-word_size
addr_info = {
"addr": addr,
"val": read_word(addr),
"offset": offset,
"regs": [],
"note": [],
"func": None,
"arg": None,
"local": None,
"fp": False,
}
for (name, val) in regs.items():
if addr == val:
addr_info["regs"].append(name)
addr_list.append(addr_info)
addr_dict[addr] = addr_info
offset -= word_size
if addr <= sp:
break
for f in stacktrace(g.goid, 128, True).Locations:
fp_addr = g.stack.hi+f.FramePointerOffset
if fp_addr > 0 and len(addr_dict[fp_addr]["note"]) == 0:
addr_dict[fp_addr]["note"].append("frame pointer for "+f.Function.Name_)
pc_addr = fp_addr+word_size
pc = read_word(pc_addr)
ins = disassemble(None, pc, pc+1).Disassemble[0]
addr_dict[pc_addr]["note"].append("return addr to "+ins.Loc.Function.Name_)
for arg in f.Arguments:
addr_dict[arg.Addr]["note"].append("arg "+arg.Name+" "+arg.Type)
for local in f.Locals:
addr = local.Addr // 8 * 8
if addr_dict.get(addr):
addr_dict[addr]["note"].append("var "+local.Name+" "+local.Type)
return addr_list
# stackannotate (alias sa) will print an annotated stack dump.
def command_stackannotate():
rows = [["regs", "addr", "offset", "value", "explanation"]]
for addr_info in stack():
regs = ""
if len(addr_info["regs"]) > 0:
regs = ",".join(addr_info["regs"])+" -->"
note = "?"
if len(addr_info["note"]) > 0:
note = ", ".join(addr_info["note"])
rows.append([
regs,
hex(addr_info["addr"]),
lpad(str(addr_info["offset"]), 6),
lpad(hex(addr_info["val"]), word_size*2+2),
note,
])
print(ascii_table(rows))
def main():
dlv_command("config alias stackannotate sa")