From 22814bbf81e8952c6ee5d7ba2508a5f383f56777 Mon Sep 17 00:00:00 2001 From: etrickel Date: Tue, 9 Jan 2018 16:40:54 -0700 Subject: [PATCH] final version of changes, squashed commits --- docs/commands/context.md | 28 +++++++++ gef.py | 123 +++++++++++++++++++++------------------ 2 files changed, 94 insertions(+), 57 deletions(-) mode change 100755 => 100644 gef.py diff --git a/docs/commands/context.md b/docs/commands/context.md index 90906d155..44eaebf9e 100644 --- a/docs/commands/context.md +++ b/docs/commands/context.md @@ -62,6 +62,34 @@ hexdump version of 0x40 byte of the stack. This command makes it convenient for tracking the evolution of arbitrary locations in memory. Tracked locations can be removed one by one using `memory unwatch`, or altogether with `memory reset`. +To have the stack displayed with the largest stack addresses on top (i.e., grow the +stack downward), enable the following setting: +``` +gef➤ gef config context.grow_stack_down True +``` + +To always display the saved instruction pointer in the stack view, enable the following: +``` +gef➤ gef config context.show_saved_ip True +``` + +If the saved instruction pointer is not within the portion of the stack being displayed, +then a section is created that includes the saved ip and depending on the architecture +the frame pointer. Since not all the addresses can be displayed, the missing addresses +are squished into an ellipsis. +``` +0x00007fffffffc9e8│+0x00: 0x00007ffff7a2d830 → <__main+240> mov edi, eax ← savedip +0x00007fffffffc9e0│+0x00: 0x00000000004008c0 → <__init+0> push r15 ← $rbp +. . . (440 bytes skipped) +0x00007fffffffc7e8│+0x38: 0x0000000000000000 +0x00007fffffffc7e0│+0x30: 0x0000000000000026 ("&"?) +0x00007fffffffc7d8│+0x28: 0x0000000001958ac0 +0x00007fffffffc7d0│+0x20: 0x00007ffff7ffa2b0 → 0x5f6f7364765f5f00 +0x00007fffffffc7c8│+0x18: 0x00007fff00000000 +0x00007fffffffc7c0│+0x10: 0x00007fffffffc950 → 0x0000000000000000 +0x00007fffffffc7b8│+0x08: 0x0000000000000000 +0x00007fffffffc7b0│+0x00: 0x00007fffffffc7e4 → 0x0000000000000000 ← $rsp +``` ### Redirecting context output to another tty/file ### diff --git a/gef.py b/gef.py old mode 100755 new mode 100644 index b70458f83..1bdf9ecaa --- a/gef.py +++ b/gef.py @@ -1326,8 +1326,8 @@ def sp(self): return get_register("$sp") @property - def get_stack_top(self): - return get_register("$bp") + def fp(self): + return get_register("$fp") @property def ptrsize(self): @@ -1363,10 +1363,6 @@ def instruction_length(self): # Thumb instructions have variable-length (2 or 4-byte) return None if is_arm_thumb() else 4 - @property - def get_stack_top(self): - return 0 - def is_call(self, insn): mnemo = insn.mnemo call_mnemos = {"bl", "blx"} @@ -1441,14 +1437,6 @@ def is_call(self, insn): call_mnemos = {"bl", "blr"} return mnemo in call_mnemos - @property - def get_stack_top(self): - return 0 - - @property - def get_stack_address(self): - return 0 - def flag_register_to_human(self, val=None): # http://events.linuxfoundation.org/sites/events/files/slides/KoreaLinuxForum-2014.pdf reg = self.flag_register @@ -1699,10 +1687,6 @@ def flag_register_to_human(self, val=None): val = get_register(reg) return flags_to_human(val, self.flags_table) - @property - def get_stack_top(self): - return 0 - def is_call(self, insn): return False @@ -1785,10 +1769,6 @@ def flag_register_to_human(self, val=None): def is_call(self, insn): return False - @property - def get_stack_top(self): - return 0 - def is_conditional_branch(self, insn): mnemo = insn.mnemo # http://moss.csc.ncsu.edu/~mueller/codeopt/codeopt00/notes/condbranch.html @@ -1865,10 +1845,6 @@ class SPARC64(SPARC): 32: "carry", } - @property - def get_stack_top(self): - return 0 - class MIPS(Architecture): @@ -1895,10 +1871,6 @@ def flag_register_to_human(self, val=None): def is_call(self, insn): return False - @property - def get_stack_top(self): - return 0 - def is_conditional_branch(self, insn): mnemo = insn.mnemo branch_mnemos = {"beq", "bne", "beqz", "bnez", "bgtz", "bgez", "bltz", "blez"} @@ -2263,6 +2235,24 @@ def get_info_sections(): return +def get_saved_ip(): + """Retrieves the saved ip using the 'info frame' command.""" + + lines = gdb.execute("info frame", to_string=True).splitlines() + if lines: + saved_regs = lines[-1].split() + saved_ip_str = saved_regs[-1] + + try: + saved_ip = int(saved_ip_str, 16) + return saved_ip + except ValueError: + # ignore + pass + + return 0 + + def get_info_files(): """Retrieves all the files loaded by debuggee.""" lines = gdb.execute("info files", to_string=True).splitlines() @@ -6310,7 +6300,7 @@ def __init__(self): self.add_setting("peek_calls", True, "Peek into calls") self.add_setting("nb_lines_stack", 8, "Number of line in the stack pane") self.add_setting("show_saved_ip", False, "Show saved IP and EBP even if outside of nb_lines_stack") - self.add_setting("grow_stack_up", False, "Order of stack downward starts at largest down to stack pointer") + self.add_setting("grow_stack_down", False, "Order of stack downward starts at largest down to stack pointer") self.add_setting("nb_lines_backtrace", 10, "Number of line in the backtrace pane") self.add_setting("nb_lines_code", 5, "Number of instruction before and after $pc") self.add_setting("ignore_registers", "", "Space-separated list of registers not to display (e.g. '$cs $ds $gs')") @@ -7028,7 +7018,7 @@ def __init__(self): return def post_load(self): - GefAlias("stack", "dereference $sp ") + GefAlias("stack", "dereference $sp") GefAlias("dps", "dereference", completer_class=gdb.COMPLETE_LOCATION) return @@ -7038,8 +7028,8 @@ def pprint_dereferenced(self, addr, off): regs = [(k.strip(), get_register(k)) for k in current_arch.all_registers] - if (is_x86_32() or is_x86_64() ) and get_gef_setting("context.show_saved_ip"): - regs.append(("savedeip", (get_register("$bp") + (current_arch.ptrsize)))) + if get_gef_setting("context.show_saved_ip"): + regs.append(("savedip", get_saved_ip())) sep = " {:s} ".format(right_arrow) memalign = current_arch.ptrsize @@ -7068,16 +7058,17 @@ def pprint_dereferenced(self, addr, off): @only_if_gdb_running def do_invoke(self, argv): - grow_stack_up = get_gef_setting("context.grow_stack_up") + grow_stack_down = get_gef_setting("context.grow_stack_down") + if len(argv) < 1: err("Missing location.") return nb = 10 - if len(argv)==2 and argv[1][0] in ("l", "L") and argv[1][1:].isdigit(): + if len(argv) == 2 and argv[1][0] in ("l", "L") and argv[1][1:].isdigit(): nb = int(argv[1][1:]) - if len(argv) == 2 and argv[0] == "$sp" and argv[1].isdigit(): + elif len(argv) == 2 and argv[0] == "$sp" and argv[1].isdigit(): nb = int(argv[1]) start_address = align_address(long(gdb.parse_and_eval(argv[0]))) @@ -7086,30 +7077,48 @@ def do_invoke(self, argv): stackoffs = range(0, nb) # adjusts order of stack so that it grows downward - if grow_stack_up: - stackoffs = range(nb - 1, -1, -1) + if grow_stack_down: + stackoffs = reversed(stackoffs) + + stack_str = "" + for i in stackoffs: + stack_str += self.pprint_dereferenced(start_address, i) + "\n" + stack_str = stack_str[:-1] - # prints saved EBP at top of stack + # prints saved instruction pointer if get_gef_setting("context.show_saved_ip"): - # is saved EIP already shown in stack dereference? - - if current_arch.get_stack_top > largest_addresss_to_be_shown and start_address == current_arch.sp: - if grow_stack_up: - gdb.execute('dereference {} L1'.format(current_arch.get_stack_top + current_arch.ptrsize )) - gdb.execute('dereference {} L1'.format(current_arch.get_stack_top )) - print(". . . ({:d} bytes skipped)".format(current_arch.get_stack_top - largest_addresss_to_be_shown)) - for i in stackoffs: - print(self.pprint_dereferenced(start_address, i)) - else: - for i in stackoffs: - print(self.pprint_dereferenced(start_address, i)) - print(". . . ({:d} bytes skipped)".format(get_register("$bp") - get_register("$sp"))) - gdb.execute('dereference $bp L2') - return + frame_ptr = current_arch.fp + saved_ip = get_saved_ip() - for i in stackoffs: - print(self.pprint_dereferenced(start_address, i)) + # only add saved_ip if it isn't already shown and we are displaying the stack + if saved_ip > largest_addresss_to_be_shown and start_address == current_arch.sp: + bytes_skipped_label = Color.grayify(". . . ({:d} bytes skipped)".format(saved_ip - largest_addresss_to_be_shown)) + + saved_ip_str = self.pprint_dereferenced(saved_ip, 0) + out_info_str = saved_ip_str + if abs(frame_ptr - saved_ip) == current_arch.ptrsize: + frame_str = self.pprint_dereferenced(frame_ptr, 0) + if frame_str: + if (saved_ip > frame_ptr and grow_stack_down) or (saved_ip < frame_ptr and not grow_stack_down): + out_info_str += "\n" + frame_str + else: + out_info_str = frame_str + "\n" + out_info_str += saved_ip_str + + if grow_stack_down: + print(out_info_str) + print(bytes_skipped_label) + print(stack_str) + else: + print(stack_str) + print(bytes_skipped_label) + print(out_info_str) + + else: + print(stack_str) + else: + print(stack_str) return