diff --git a/.gdbinit b/.gdbinit index f970dda..dcdc16b 100644 --- a/.gdbinit +++ b/.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 + diff --git a/.gitmodules b/.gitmodules index dfb87e4..9021180 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/gdb/commands.py b/gdb/commands.py new file mode 100644 index 0000000..9c69e2d --- /dev/null +++ b/gdb/commands.py @@ -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) diff --git a/gdb/commands2.py b/gdb/commands2.py new file mode 100644 index 0000000..d1f54d2 --- /dev/null +++ b/gdb/commands2.py @@ -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() diff --git a/gdb/gdb_gef b/gdb/gdb_gef new file mode 160000 index 0000000..5d5efae --- /dev/null +++ b/gdb/gdb_gef @@ -0,0 +1 @@ +Subproject commit 5d5efae0732c4f74919f22ba6acc833c4d474adf