From 692c4b82f69448eb885d705ad149f125786648b7 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Mon, 5 Sep 2022 10:58:57 -0700 Subject: [PATCH] GDB Refactor [4/N]: Split abi into lib/ and gdblib/ (#1120) * Remove tips.py * Split android.py into lib/ and gdb/ * Split abi.py into lib/ and gdblib/ --- pwndbg/arguments.py | 14 ++++----- pwndbg/argv.py | 4 +-- pwndbg/auxv.py | 4 +-- pwndbg/chain.py | 4 +-- pwndbg/elf.py | 4 +-- pwndbg/gdblib/abi.py | 67 +++++++++++++++++++++++++++++++++++++++++ pwndbg/{ => lib}/abi.py | 62 -------------------------------------- pwndbg/stack.py | 2 +- pwndbg/vmmap.py | 4 +-- 9 files changed, 85 insertions(+), 80 deletions(-) create mode 100644 pwndbg/gdblib/abi.py rename pwndbg/{ => lib}/abi.py (67%) diff --git a/pwndbg/arguments.py b/pwndbg/arguments.py index 7b338b81..67969869 100644 --- a/pwndbg/arguments.py +++ b/pwndbg/arguments.py @@ -6,7 +6,6 @@ import gdb from capstone import CS_GRP_CALL from capstone import CS_GRP_INT -import pwndbg.abi import pwndbg.chain import pwndbg.color.nearpc as N import pwndbg.constants @@ -14,6 +13,7 @@ import pwndbg.disasm import pwndbg.gdblib.arch import pwndbg.gdblib.typeinfo import pwndbg.ida +import pwndbg.lib.abi import pwndbg.lib.funcparser import pwndbg.lib.functions import pwndbg.memory @@ -52,7 +52,7 @@ def get_syscall_name(instruction): if CS_GRP_INT not in instruction.groups: return None - syscall_register = pwndbg.abi.ABI.syscall().syscall_register + syscall_register = pwndbg.lib.abi.ABI.syscall().syscall_register # If we are on x86/x64, return no syscall name for other instructions than syscall and int 0x80 if syscall_register in ("eax", "rax"): @@ -81,7 +81,7 @@ def get(instruction): if CS_GRP_CALL in instruction.groups: try: - abi = pwndbg.abi.ABI.default() + abi = pwndbg.lib.abi.ABI.default() except KeyError: return [] @@ -100,7 +100,7 @@ def get(instruction): elif CS_GRP_INT in instruction.groups: # Get the syscall number and name name = get_syscall_name(instruction) - abi = pwndbg.abi.ABI.syscall() + abi = pwndbg.lib.abi.ABI.syscall() target = None if name is None: @@ -162,7 +162,7 @@ def get(instruction): def argname(n, abi=None): - abi = abi or pwndbg.abi.ABI.default() + abi = abi or pwndbg.lib.abi.ABI.default() regs = abi.register_arguments if n < len(regs): @@ -177,7 +177,7 @@ def argument(n, abi=None): instruction. Works only for ABIs that use registers for arguments. """ - abi = abi or pwndbg.abi.ABI.default() + abi = abi or pwndbg.lib.abi.ABI.default() regs = abi.register_arguments if n < len(regs): @@ -195,7 +195,7 @@ def arguments(abi=None): Yields (arg_name, arg_value) tuples for arguments from a given ABI. Works only for ABIs that use registers for arguments. """ - abi = abi or pwndbg.abi.ABI.default() + abi = abi or pwndbg.lib.abi.ABI.default() regs = abi.register_arguments for i in range(len(regs)): diff --git a/pwndbg/argv.py b/pwndbg/argv.py index bda78b6c..3998d5e7 100644 --- a/pwndbg/argv.py +++ b/pwndbg/argv.py @@ -1,8 +1,8 @@ import gdb -import pwndbg.abi import pwndbg.gdblib.arch import pwndbg.gdblib.events +import pwndbg.lib.abi import pwndbg.memory import pwndbg.regs @@ -20,7 +20,7 @@ envc = None @pwndbg.gdblib.events.start -@pwndbg.abi.LinuxOnly() +@pwndbg.gdblib.abi.LinuxOnly() def update(): global argc global argv diff --git a/pwndbg/auxv.py b/pwndbg/auxv.py index 42e606f2..91201a85 100644 --- a/pwndbg/auxv.py +++ b/pwndbg/auxv.py @@ -4,7 +4,7 @@ import sys import gdb -import pwndbg.abi +import pwndbg.gdblib.abi import pwndbg.gdblib.arch import pwndbg.gdblib.events import pwndbg.gdblib.typeinfo @@ -146,7 +146,7 @@ def find_stack_boundary(addr): def walk_stack(): - if not pwndbg.abi.linux: + if not pwndbg.gdblib.abi.linux: return None if pwndbg.qemu.is_qemu_kernel(): return None diff --git a/pwndbg/chain.py b/pwndbg/chain.py index 1e800e80..b3d26923 100755 --- a/pwndbg/chain.py +++ b/pwndbg/chain.py @@ -1,10 +1,10 @@ import gdb -import pwndbg.abi import pwndbg.color.chain as C import pwndbg.color.memory as M import pwndbg.color.theme as theme import pwndbg.enhance +import pwndbg.gdblib.abi import pwndbg.gdblib.typeinfo import pwndbg.memory import pwndbg.symbol @@ -56,7 +56,7 @@ def get( # Avoid redundant dereferences in bare metal mode by checking # if address is in any of vmmap pages - if not pwndbg.abi.linux and not pwndbg.vmmap.find(address): + if not pwndbg.gdblib.abi.linux and not pwndbg.vmmap.find(address): break next_address = int(pwndbg.memory.poi(pwndbg.gdblib.typeinfo.ppvoid, address)) diff --git a/pwndbg/elf.py b/pwndbg/elf.py index 9cb01cc9..b99220b9 100644 --- a/pwndbg/elf.py +++ b/pwndbg/elf.py @@ -15,9 +15,9 @@ import gdb from elftools.elf.constants import SH_FLAGS from elftools.elf.elffile import ELFFile -import pwndbg.abi import pwndbg.auxv import pwndbg.elftypes +import pwndbg.gdblib.abi import pwndbg.gdblib.arch import pwndbg.gdblib.events import pwndbg.info @@ -266,7 +266,7 @@ def get_ehdr(pointer): if base is None: # For non linux ABI, the ELF header may not exist at all - if pwndbg.abi.linux: + if pwndbg.gdblib.abi.linux: print("ERROR: Could not find ELF base!") return None, None diff --git a/pwndbg/gdblib/abi.py b/pwndbg/gdblib/abi.py new file mode 100644 index 00000000..f79c8711 --- /dev/null +++ b/pwndbg/gdblib/abi.py @@ -0,0 +1,67 @@ +import functools + +import gdb + +import pwndbg.color.message as M +import pwndbg.gdblib.events + +abi = None +linux = False + + +# TODO: Maybe move this to hooks.py? +@pwndbg.gdblib.events.start +def update(): + global abi + global linux + + # Detect current ABI of client side by 'show osabi' + # + # Examples of strings returned by `show osabi`: + # 'The current OS ABI is "auto" (currently "GNU/Linux").\nThe default OS ABI is "GNU/Linux".\n' + # 'The current OS ABI is "GNU/Linux".\nThe default OS ABI is "GNU/Linux".\n' + # 'El actual SO ABI es «auto» (actualmente «GNU/Linux»).\nEl SO ABI predeterminado es «GNU/Linux».\n' + # 'The current OS ABI is "auto" (currently "none")' + # + # As you can see, there might be GDBs with different language versions + # and so we have to support it there too. + # Lets assume and hope that `current osabi` is returned in first line in all languages... + abi = gdb.execute("show osabi", to_string=True).split("\n")[0] + + # Currently we support those osabis: + # 'GNU/Linux': linux + # 'none': bare metal + + linux = "GNU/Linux" in abi + + if not linux: + msg = M.warn( + "The bare metal debugging is enabled since gdb's osabi is '%s' which is not 'GNU/Linux'.\n" + "Ex. the page resolving and memory de-referencing ONLY works on known pages.\n" + "This option is based on gdb client compile arguments (by default) and will be corrected if you load an ELF with a '.note.ABI-tag' section.\n" + "If you are debugging a program that runs on the Linux ABI, please select the correct gdb client." + % abi + ) + print(msg) + + +def LinuxOnly(default=None): + """Create a decorator that the function will be called when ABI is Linux. + Otherwise, return `default`. + """ + + def decorator(func): + @functools.wraps(func) + def caller(*args, **kwargs): + if linux: + return func(*args, **kwargs) + else: + return default + + return caller + + return decorator + + +# Update when starting the gdb to show warning message for non-Linux ABI user. +update() diff --git a/pwndbg/abi.py b/pwndbg/lib/abi.py similarity index 67% rename from pwndbg/abi.py rename to pwndbg/lib/abi.py index 2db9198e..fb76d699 100644 --- a/pwndbg/abi.py +++ b/pwndbg/lib/abi.py @@ -1,8 +1,3 @@ -import functools - -import gdb - -import pwndbg.color.message as M import pwndbg.gdblib.arch @@ -114,60 +109,3 @@ linux_arm_sigreturn = SigreturnABI(["r7"], 4, 0) linux_i386_srop = ABI(["eax"], 4, 0) linux_amd64_srop = ABI(["rax"], 4, 0) linux_arm_srop = ABI(["r7"], 4, 0) - - -@pwndbg.gdblib.events.start -def update(): - global abi - global linux - - # Detect current ABI of client side by 'show osabi' - # - # Examples of strings returned by `show osabi`: - # 'The current OS ABI is "auto" (currently "GNU/Linux").\nThe default OS ABI is "GNU/Linux".\n' - # 'The current OS ABI is "GNU/Linux".\nThe default OS ABI is "GNU/Linux".\n' - # 'El actual SO ABI es «auto» (actualmente «GNU/Linux»).\nEl SO ABI predeterminado es «GNU/Linux».\n' - # 'The current OS ABI is "auto" (currently "none")' - # - # As you can see, there might be GDBs with different language versions - # and so we have to support it there too. - # Lets assume and hope that `current osabi` is returned in first line in all languages... - abi = gdb.execute("show osabi", to_string=True).split("\n")[0] - - # Currently we support those osabis: - # 'GNU/Linux': linux - # 'none': bare metal - - linux = "GNU/Linux" in abi - - if not linux: - msg = M.warn( - "The bare metal debugging is enabled since gdb's osabi is '%s' which is not 'GNU/Linux'.\n" - "Ex. the page resolving and memory de-referencing ONLY works on known pages.\n" - "This option is based on gdb client compile arguments (by default) and will be corrected if you load an ELF with a '.note.ABI-tag' section.\n" - "If you are debugging a program that runs on the Linux ABI, please select the correct gdb client." - % abi - ) - print(msg) - - -def LinuxOnly(default=None): - """Create a decorator that the function will be called when ABI is Linux. - Otherwise, return `default`. - """ - - def decorator(func): - @functools.wraps(func) - def caller(*args, **kwargs): - if linux: - return func(*args, **kwargs) - else: - return default - - return caller - - return decorator - - -# Update when starting the gdb to show warning message for non-Linux ABI user. -update() diff --git a/pwndbg/stack.py b/pwndbg/stack.py index 0967d35e..6762f74f 100644 --- a/pwndbg/stack.py +++ b/pwndbg/stack.py @@ -41,7 +41,7 @@ def find_upper_stack_boundary(stack_ptr, max_pages=1024): # We can't get the stack size from stack layout and page fault on bare metal mode, # so we return current page as a walkaround. - if not pwndbg.abi.linux: + if not pwndbg.gdblib.abi.linux: return stack_ptr + pwndbg.memory.PAGE_SIZE return pwndbg.memory.find_upper_boundary(stack_ptr, max_pages) diff --git a/pwndbg/vmmap.py b/pwndbg/vmmap.py index 75082ba1..253ce4cb 100644 --- a/pwndbg/vmmap.py +++ b/pwndbg/vmmap.py @@ -11,9 +11,9 @@ import sys import gdb -import pwndbg.abi import pwndbg.elf import pwndbg.file +import pwndbg.gdblib.abi import pwndbg.gdblib.events import pwndbg.gdblib.typeinfo import pwndbg.lib.memoize @@ -107,7 +107,7 @@ def find(address): return explore(address) -@pwndbg.abi.LinuxOnly() +@pwndbg.gdblib.abi.LinuxOnly() def explore(address_maybe): """ Given a potential address, check to see what permissions it has.