Add more gdb modules and tools
This commit is contained in:
parent
01fe1ff04a
commit
28ce478821
5
.gdbinit
5
.gdbinit
@ -1,2 +1,7 @@
|
||||
#source ~/config/gdb/peda/peda.py
|
||||
#source ~/config/gdb/gdb-dashboard/.gdbinit
|
||||
#source ~/config/gdb/gdb_gef/gef.py
|
||||
|
||||
source ~/config/gdb/commands.py
|
||||
source ~/config/gdb/commands2.py
|
||||
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -13,3 +13,6 @@
|
||||
[submodule "gdb/gdbundle"]
|
||||
path = gdb/gdbundle
|
||||
url = https://github.com/memfault/gdbundle
|
||||
[submodule "gdb/gdb_gef"]
|
||||
path = gdb/gdb_gef
|
||||
url = https://github.com/hugsy/gef
|
||||
|
268
gdb/commands.py
Normal file
268
gdb/commands.py
Normal file
@ -0,0 +1,268 @@
|
||||
#from https://www.pythonsheets.com/appendix/python-gdb.html
|
||||
# try help user-defined from gdb for desc
|
||||
|
||||
import gdb
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
class DumpMemory(gdb.Command):
|
||||
"""Dump memory info into a file."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("dm", gdb.COMMAND_USER)
|
||||
|
||||
def get_addr(self, p, tty):
|
||||
"""Get memory addresses."""
|
||||
cmd = "info proc mappings"
|
||||
out = gdb.execute(cmd, tty, True)
|
||||
addrs = []
|
||||
for l in out.split("\n"):
|
||||
if re.match(f".*{p}*", l):
|
||||
s, e, *_ = l.split()
|
||||
addrs.append((s, e))
|
||||
return addrs
|
||||
|
||||
def dump(self, addrs):
|
||||
"""Dump memory result."""
|
||||
if not addrs:
|
||||
return
|
||||
|
||||
for s, e in addrs:
|
||||
f = int(time.time() * 1000)
|
||||
gdb.execute(f"dump memory {f}.bin {s} {e}")
|
||||
|
||||
def invoke(self, args, tty):
|
||||
try:
|
||||
# cat /proc/self/maps
|
||||
addrs = self.get_addr(args, tty)
|
||||
# dump memory
|
||||
self.dump(addrs)
|
||||
except Exception as e:
|
||||
print("Usage: dm [pattern]\n\twhith pattern : heap, stack or any value in /proc/self/maps")
|
||||
|
||||
DumpMemory()
|
||||
|
||||
class DumpJson(gdb.Command):
|
||||
"""Dump std::string as a styled JSON."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("dj", gdb.COMMAND_USER)
|
||||
|
||||
def get_json(self, args):
|
||||
"""Parse std::string to JSON string."""
|
||||
ret = gdb.parse_and_eval(args)
|
||||
typ = str(ret.type)
|
||||
if re.match("^std::.*::string", typ):
|
||||
return json.loads(str(ret))
|
||||
return None
|
||||
|
||||
def invoke(self, args, tty):
|
||||
try:
|
||||
# string to json string
|
||||
s = self.get_json(args)
|
||||
# json string to object
|
||||
o = json.loads(s)
|
||||
print(json.dumps(o, indent=2))
|
||||
except Exception as e:
|
||||
print(f"Parse json error! {args}")
|
||||
|
||||
DumpJson()
|
||||
|
||||
tp = {}
|
||||
|
||||
class Tracepoint(gdb.Breakpoint):
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
self.silent = True
|
||||
self.count = 0
|
||||
|
||||
def stop(self):
|
||||
self.count += 1
|
||||
frame = gdb.newest_frame()
|
||||
block = frame.block()
|
||||
sym_and_line = frame.find_sal()
|
||||
framename = frame.name()
|
||||
filename = sym_and_line.symtab.filename
|
||||
line = sym_and_line.line
|
||||
# show tracepoint info
|
||||
print(f"{framename} @ {filename}:{line}")
|
||||
# show args and vars
|
||||
for s in block:
|
||||
if not s.is_argument and not s.is_variable:
|
||||
continue
|
||||
typ = s.type
|
||||
val = s.value(frame)
|
||||
size = typ.sizeof
|
||||
name = s.name
|
||||
print(f"\t{name}({typ}: {val}) [{size}]")
|
||||
# do not stop at tracepoint
|
||||
return False
|
||||
|
||||
class SetTracepoint(gdb.Command):
|
||||
def __init__(self):
|
||||
super().__init__("tp", gdb.COMMAND_USER)
|
||||
|
||||
def invoke(self, args, tty):
|
||||
try:
|
||||
global tp
|
||||
tp[args] = Tracepoint(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def finish(event):
|
||||
for t, p in tp.items():
|
||||
c = p.count
|
||||
print(f"Tracepoint '{t}' Count: {c}")
|
||||
|
||||
gdb.events.exited.connect(finish)
|
||||
SetTracepoint()
|
||||
|
||||
|
||||
class EndPoint(gdb.FinishBreakpoint):
|
||||
def __init__(self, breakpoint, *a, **kw):
|
||||
super().__init__(*a, **kw)
|
||||
self.silent = True
|
||||
self.breakpoint = breakpoint
|
||||
|
||||
def stop(self):
|
||||
# normal finish
|
||||
end = time.time()
|
||||
start, out = self.breakpoint.stack.pop()
|
||||
diff = end - start
|
||||
print(out.strip())
|
||||
print(f"\tCost: {diff}")
|
||||
return False
|
||||
|
||||
class StartPoint(gdb.Breakpoint):
|
||||
def __init__(self, *a, **kw):
|
||||
super().__init__(*a, **kw)
|
||||
self.silent = True
|
||||
self.stack = []
|
||||
|
||||
def stop(self):
|
||||
start = time.time()
|
||||
# start, end, diff
|
||||
frame = gdb.newest_frame()
|
||||
sym_and_line = frame.find_sal()
|
||||
func = frame.function().name
|
||||
filename = sym_and_line.symtab.filename
|
||||
line = sym_and_line.line
|
||||
block = frame.block()
|
||||
|
||||
args = []
|
||||
for s in block:
|
||||
if not s.is_argument:
|
||||
continue
|
||||
name = s.name
|
||||
typ = s.type
|
||||
val = s.value(frame)
|
||||
args.append(f"{name}: {val} [{typ}]")
|
||||
|
||||
# format
|
||||
out = ""
|
||||
out += f"{func} @ {filename}:{line}\n"
|
||||
for a in args:
|
||||
out += f"\t{a}\n"
|
||||
|
||||
# append current status to a breakpoint stack
|
||||
self.stack.append((start, out))
|
||||
EndPoint(self, internal=True)
|
||||
return False
|
||||
|
||||
class Profile(gdb.Command):
|
||||
def __init__(self):
|
||||
super().__init__("prof", gdb.COMMAND_USER)
|
||||
|
||||
def invoke(self, args, tty):
|
||||
try:
|
||||
StartPoint(args)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
Profile()
|
||||
|
||||
|
||||
|
||||
|
||||
import pwd
|
||||
import grp
|
||||
import stat
|
||||
import time
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class StatPrint:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def get_filetype(self, st_mode):
|
||||
if stat.S_ISDIR(st_mode):
|
||||
return "directory"
|
||||
if stat.S_ISCHR(st_mode):
|
||||
return "character device"
|
||||
if stat.S_ISBLK(st_mode):
|
||||
return "block device"
|
||||
if stat.S_ISREG:
|
||||
return "regular file"
|
||||
if stat.S_ISFIFO(st_mode):
|
||||
return "FIFO"
|
||||
if stat.S_ISLNK(st_mode):
|
||||
return "symbolic link"
|
||||
if stat.S_ISSOCK(st_mode):
|
||||
return "socket"
|
||||
return "unknown"
|
||||
|
||||
def get_access(self, st_mode):
|
||||
out = "-"
|
||||
info = ("r", "w", "x")
|
||||
perm = [
|
||||
(stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR),
|
||||
(stat.S_IRGRP, stat.S_IRWXG, stat.S_IXGRP),
|
||||
(stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH),
|
||||
]
|
||||
for pm in perm:
|
||||
for c, p in zip(pm, info):
|
||||
out += p if st_mode & c else "-"
|
||||
return out
|
||||
|
||||
def get_time(self, st_time):
|
||||
tv_sec = int(st_time["tv_sec"])
|
||||
return datetime.fromtimestamp(tv_sec).isoformat()
|
||||
|
||||
def to_string(self):
|
||||
st = self.val
|
||||
st_ino = int(st["st_ino"])
|
||||
st_mode = int(st["st_mode"])
|
||||
st_uid = int(st["st_uid"])
|
||||
st_gid = int(st["st_gid"])
|
||||
st_size = int(st["st_size"])
|
||||
st_blksize = int(st["st_blksize"])
|
||||
st_blocks = int(st["st_blocks"])
|
||||
st_atim = st["st_atim"]
|
||||
st_mtim = st["st_mtim"]
|
||||
st_ctim = st["st_ctim"]
|
||||
|
||||
out = "{\n"
|
||||
out += f"Size: {st_size}\n"
|
||||
out += f"Blocks: {st_blocks}\n"
|
||||
out += f"IO Block: {st_blksize}\n"
|
||||
out += f"Inode: {st_ino}\n"
|
||||
out += f"Access: {self.get_access(st_mode)}\n"
|
||||
out += f"File Type: {self.get_filetype(st_mode)}\n"
|
||||
out += f"Uid: ({st_uid}/{pwd.getpwuid(st_uid).pw_name})\n"
|
||||
out += f"Gid: ({st_gid}/{grp.getgrgid(st_gid).gr_name})\n"
|
||||
out += f"Access: {self.get_time(st_atim)}\n"
|
||||
out += f"Modify: {self.get_time(st_mtim)}\n"
|
||||
out += f"Change: {self.get_time(st_ctim)}\n"
|
||||
out += "}"
|
||||
return out
|
||||
# Could be disabled at runtime with:
|
||||
# disable pretty-print global sp
|
||||
# then check "info pretty-print"
|
||||
p = gdb.printing.RegexpCollectionPrettyPrinter("sp")
|
||||
p.add_printer("stat", "^stat$", StatPrint)
|
||||
|
||||
o = gdb.current_objfile()
|
||||
gdb.printing.register_pretty_printer(o, p)
|
22
gdb/commands2.py
Normal file
22
gdb/commands2.py
Normal file
@ -0,0 +1,22 @@
|
||||
import gdb
|
||||
|
||||
from pygments import highlight
|
||||
from pygments.lexers import CLexer
|
||||
from pygments.formatters import TerminalFormatter
|
||||
|
||||
class PrettyList(gdb.Command):
|
||||
"""Print source code with color."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("pl", gdb.COMMAND_USER)
|
||||
self.lex = CLexer()
|
||||
self.fmt = TerminalFormatter()
|
||||
|
||||
def invoke(self, args, tty):
|
||||
try:
|
||||
out = gdb.execute(f"l {args}", tty, True)
|
||||
print(highlight(out, self.lex, self.fmt))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
PrettyList()
|
1
gdb/gdb_gef
Submodule
1
gdb/gdb_gef
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 5d5efae0732c4f74919f22ba6acc833c4d474adf
|
Loading…
Reference in New Issue
Block a user