Move GDB initialization and basic startup functionality to a new Debugger-agnostic API (#2243)

pull/2252/head
Matt 1 year ago committed by GitHub
parent 2ecdce4ea8
commit 7dbc5472d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -150,6 +150,11 @@ def main() -> None:
os.environ["PWNLIB_NOTERM"] = "1"
import pwndbg # noqa: F811
import pwndbg.dbg.gdb
pwndbg.dbg = pwndbg.dbg_mod.gdb.GDB()
pwndbg.dbg.setup()
import pwndbg.profiling
pwndbg.profiling.init(profiler, start_time)

@ -1,9 +1,5 @@
from __future__ import annotations
import signal
import gdb
# isort: off
import pwndbg.lib.config
@ -11,86 +7,11 @@ config: pwndbg.lib.config.Config = pwndbg.lib.config.Config()
# isort: on
import pwndbg.color
import pwndbg.commands
import pwndbg.gdblib
from pwndbg.commands import load_commands
from pwndbg.gdblib import load_gdblib
load_commands()
load_gdblib()
# TODO: Convert these to gdblib modules and remove this
try:
import pwndbg.gdblib.disasm
import pwndbg.gdblib.disasm.aarch64
import pwndbg.gdblib.disasm.arm
import pwndbg.gdblib.disasm.jump
import pwndbg.gdblib.disasm.mips
import pwndbg.gdblib.disasm.ppc
import pwndbg.gdblib.disasm.riscv
import pwndbg.gdblib.disasm.sparc
import pwndbg.gdblib.disasm.x86
import pwndbg.gdblib.heap
except ModuleNotFoundError:
pass
import pwndbg.exception
import pwndbg.lib.version
import pwndbg.ui
from pwndbg import dbg as dbg_mod
from pwndbg.dbg import dbg as dbg
__version__ = pwndbg.lib.version.__version__
version = __version__
from pwndbg.gdblib import gdb_version
from pwndbg.gdblib import prompt
prompt.set_prompt()
pre_commands = f"""
set confirm off
set verbose off
set pagination off
set height 0
set history save on
set follow-fork-mode child
set backtrace past-main on
set step-mode on
set print pretty on
set width {pwndbg.ui.get_window_size()[1]}
handle SIGALRM nostop print nopass
handle SIGBUS stop print nopass
handle SIGPIPE nostop print nopass
handle SIGSEGV stop print nopass
""".strip()
# See https://github.com/pwndbg/pwndbg/issues/808
if gdb_version[0] <= 9:
pre_commands += "\nset remote search-memory-packet off"
for line in pre_commands.strip().splitlines():
gdb.execute(line)
# This may throw an exception, see pwndbg/pwndbg#27
try:
gdb.execute("set disassembly-flavor intel")
except gdb.error:
pass
# handle resize event to align width and completion
signal.signal(
signal.SIGWINCH,
lambda signum, frame: gdb.execute("set width %i" % pwndbg.ui.get_window_size()[1]),
)
# Reading Comment file
from pwndbg.commands import comments
comments.init()
from pwndbg.gdblib import config_mod as gdblib_config_mod
gdblib_config_mod.init_params()
from pwndbg.gdblib.prompt import show_hint
show_hint()

@ -0,0 +1,56 @@
"""
The abstracted debugger interface.
"""
from __future__ import annotations
from typing import Any
from typing import Tuple
dbg: Debugger = None
class Debugger:
"""
The base class
"""
def setup(self, *args: Any) -> None:
"""
Perform debugger-specific initialization.
Because we can't really know what a given debugger object will need as
part of its setup process, we allow for as many arguments as desired to
be passed in, and leave it up to the implementations to decide what they
need.
This shouldn't be a problem, seeing as, unlike other methods in this
class, this should only be called as part of the debugger-specific
bringup code.
"""
raise NotImplementedError()
# WARNING
#
# These are hacky parts of the API that were strictly necessary to bring up
# pwndbg under LLDB without breaking it under GDB. Expect most of them to be
# removed or replaced as the porting work continues.
#
def addrsz(self, address: Any) -> str:
"""
Format the given address value.
"""
raise NotImplementedError()
def get_cmd_window_size(self) -> Tuple[int, int]:
"""
The size of the command window, in characters, if available.
"""
raise NotImplementedError()
def set_python_diagnostics(self, enabled: bool) -> None:
"""
Enables or disables Python diagnostic messages for this debugger.
"""
raise NotImplementedError()

@ -0,0 +1,120 @@
from __future__ import annotations
import signal
from typing import Any
from typing import Tuple
import gdb
from typing_extensions import override
import pwndbg
import pwndbg.commands
import pwndbg.gdblib
from pwndbg.commands import load_commands
from pwndbg.gdblib import gdb_version
from pwndbg.gdblib import load_gdblib
from pwndbg.gdblib import prompt
class GDB(pwndbg.dbg_mod.Debugger):
@override
def setup(self):
load_gdblib()
load_commands()
prompt.set_prompt()
pre_commands = f"""
set confirm off
set verbose off
set pagination off
set height 0
set history save on
set follow-fork-mode child
set backtrace past-main on
set step-mode on
set print pretty on
set width {pwndbg.ui.get_window_size()[1]}
handle SIGALRM nostop print nopass
handle SIGBUS stop print nopass
handle SIGPIPE nostop print nopass
handle SIGSEGV stop print nopass
""".strip()
# See https://github.com/pwndbg/pwndbg/issues/808
if gdb_version[0] <= 9:
pre_commands += "\nset remote search-memory-packet off"
for line in pre_commands.strip().splitlines():
gdb.execute(line)
# This may throw an exception, see pwndbg/pwndbg#27
try:
gdb.execute("set disassembly-flavor intel")
except gdb.error:
pass
# handle resize event to align width and completion
signal.signal(
signal.SIGWINCH,
lambda signum, frame: gdb.execute("set width %i" % pwndbg.ui.get_window_size()[1]),
)
# Reading Comment file
from pwndbg.commands import comments
comments.init()
from pwndbg.gdblib import config_mod
config_mod.init_params()
pwndbg.gdblib.prompt.show_hint()
@override
def addrsz(self, address: Any) -> str:
address = int(address) & pwndbg.gdblib.arch.ptrmask
return f"%#{2 * pwndbg.gdblib.arch.ptrsize}x" % address
@override
def get_cmd_window_size(self) -> Tuple[int, int]:
"""Get the size of the command window in TUI mode which could be different than the terminal window width \
with horizontal split "tui new-layout hsrc { -horizontal src 1 cmd 1 } 1".
Possible output of "info win" in TUI mode:
(gdb) info win
Name Lines Columns Focus
src 77 104 (has focus)
cmd 77 105
Output of "info win" in non-TUI mode:
(gdb) info win
The TUI is not active."""
try:
info_out = gdb.execute("info win", to_string=True).split()
except gdb.error:
# Return None if the command is not compiled into GDB
# (gdb.error: Undefined info command: "win". Try "help info")
return None, None
if "cmd" not in info_out:
# if TUI is not enabled, info win will output "The TUI is not active."
return None, None
# parse cmd window size from the output of "info win"
cmd_win_index = info_out.index("cmd")
if len(info_out) <= cmd_win_index + 2:
return None, None
elif (
not info_out[cmd_win_index + 1].isdigit() and not info_out[cmd_win_index + 2].isdigit()
):
return None, None
else:
return int(info_out[cmd_win_index + 1]), int(info_out[cmd_win_index + 2])
@override
def set_python_diagnostics(self, enabled: bool) -> None:
if enabled:
command = "set python print-stack full"
else:
command = "set python print-stack message"
gdb.execute(command, from_tty=True, to_string=True)

@ -4,8 +4,6 @@ import functools
import sys
import traceback
import gdb
import pwndbg.lib.cache
import pwndbg.lib.stdio
from pwndbg import config
@ -140,9 +138,5 @@ pdb.set_trace = set_trace
@config.trigger(verbose, debug)
def update() -> None:
if verbose or debug:
command = "set python print-stack full"
else:
command = "set python print-stack message"
gdb.execute(command, from_tty=True, to_string=True)
enable = verbose or debug
pwndbg.dbg.set_python_diagnostics(bool(enable))

@ -10,10 +10,8 @@ import struct
import sys
import termios
import gdb
import pwndbg.color.context as C
import pwndbg.gdblib.arch
import pwndbg.dbg
from pwndbg import config
from pwndbg.color import ljust_colored
from pwndbg.color import message
@ -65,8 +63,7 @@ def banner(title, target=sys.stdin, width=None, extra=""):
def addrsz(address) -> str:
address = int(address) & pwndbg.gdblib.arch.ptrmask
return f"%#{2 * pwndbg.gdblib.arch.ptrsize}x" % address
return pwndbg.dbg.addrsz(address)
def get_window_size(target=sys.stdin):
@ -85,32 +82,4 @@ def get_window_size(target=sys.stdin):
def get_cmd_window_size():
"""Get the size of the command window in TUI mode which could be different than the terminal window width \
with horizontal split "tui new-layout hsrc { -horizontal src 1 cmd 1 } 1".
Possible output of "info win" in TUI mode:
(gdb) info win
Name Lines Columns Focus
src 77 104 (has focus)
cmd 77 105
Output of "info win" in non-TUI mode:
(gdb) info win
The TUI is not active."""
try:
info_out = gdb.execute("info win", to_string=True).split()
except gdb.error:
# Return None if the command is not compiled into GDB
# (gdb.error: Undefined info command: "win". Try "help info")
return None, None
if "cmd" not in info_out:
# if TUI is not enabled, info win will output "The TUI is not active."
return None, None
# parse cmd window size from the output of "info win"
cmd_win_index = info_out.index("cmd")
if len(info_out) <= cmd_win_index + 2:
return None, None
elif not info_out[cmd_win_index + 1].isdigit() and not info_out[cmd_win_index + 2].isdigit():
return None, None
else:
return int(info_out[cmd_win_index + 1]), int(info_out[cmd_win_index + 2])
return pwndbg.dbg.get_cmd_window_size()

Loading…
Cancel
Save