You've already forked go-profiler-notes
mirror of
https://github.com/DataDog/go-profiler-notes.git
synced 2025-07-15 23:54:16 +02:00
add stackannotate.star
This commit is contained in:
152
delve/stackannotate.star
Normal file
152
delve/stackannotate.star
Normal file
@ -0,0 +1,152 @@
|
||||
# TODO
|
||||
# Get stack lo from goroutine
|
||||
# Use the stacktrace API to unwind the stack and get annotations
|
||||
|
||||
word_size = 8 # 64bit
|
||||
|
||||
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))
|
||||
|
||||
#g = getg()
|
||||
#for f in stacktrace(g.goid, 128, True).Locations:
|
||||
#print(f)
|
||||
#break
|
||||
|
||||
def main():
|
||||
dlv_command("config alias stackannotate sa")
|
Reference in New Issue
Block a user