lldb: port version and bugreport commands + refactor (#2708)

* lldb: port version and bugreport commands + refactor

Port `version` and `bugreport` commands to LLDB.

Additionally, refactor them to provide better information and be less
bloated.

* fix lint

* fix lint

* fix lint
pull/2714/head
Disconnect3d 11 months ago committed by GitHub
parent 3fef9a1556
commit 1ce7ee36e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -696,7 +696,6 @@ def load_commands() -> None:
import pwndbg.commands.ropper import pwndbg.commands.ropper
import pwndbg.commands.segments import pwndbg.commands.segments
import pwndbg.commands.shell import pwndbg.commands.shell
import pwndbg.commands.version
import pwndbg.commands.argv import pwndbg.commands.argv
import pwndbg.commands.aslr import pwndbg.commands.aslr
@ -763,6 +762,7 @@ def load_commands() -> None:
import pwndbg.commands.tips import pwndbg.commands.tips
import pwndbg.commands.tls import pwndbg.commands.tls
import pwndbg.commands.valist import pwndbg.commands.valist
import pwndbg.commands.version
import pwndbg.commands.vmmap import pwndbg.commands.vmmap
import pwndbg.commands.windbg import pwndbg.commands.windbg
import pwndbg.commands.xinfo import pwndbg.commands.xinfo

@ -1,5 +1,5 @@
""" """
Displays gdb, python and pwndbg versions. Implements version and bugreport commands.
""" """
from __future__ import annotations from __future__ import annotations
@ -14,8 +14,6 @@ from subprocess import check_output
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from urllib.parse import quote from urllib.parse import quote
import gdb
import pwndbg import pwndbg
import pwndbg.commands import pwndbg.commands
import pwndbg.integration import pwndbg.integration
@ -23,53 +21,81 @@ from pwndbg.color import message
from pwndbg.commands import CommandCategory from pwndbg.commands import CommandCategory
def _gdb_version() -> str: def os_info():
return gdb.VERSION os_info = platform.system()
if os_info.lower() == "linux" and os.path.isfile("/etc/os-release"):
with open("/etc/os-release") as os_release:
contents = os_release.read()
match = re.search('PRETTY_NAME="?([^",\n]+)', contents)
if match:
os_info = match.group(1)
def _py_version(): return os_info
return sys.version.replace("\n", " ")
def capstone_version(): def module_version(module):
try: try:
import capstone return __import__(module).__version__
return ".".join(map(str, capstone.cs_version()))
except ImportError: except ImportError:
return "not found" return "not found"
def unicorn_version(): def debugger_version():
try: if pwndbg.dbg.is_gdblib_available():
import unicorn import gdb
return unicorn.__version__ return f"GDB: {gdb.VERSION}"
except ImportError: else:
return "not found" return f"LLDB: {'.'.join(map(str, pwndbg.dbg_mod.lldb.LLDB_VERSION))}"
def all_versions(): def all_versions():
gdb_str = f"Gdb: {_gdb_version()}" return (
py_str = f"Python: {_py_version()}" f"Pwndbg: {pwndbg.__version__}",
pwndbg_str = f"Pwndbg: {pwndbg.__version__}" f"Python: {sys.version.replace('\n', ' ')}",
debugger_version(),
f"Capstone: {module_version('capstone')}",
f"Unicorn: {module_version('unicorn')}",
f"Pwnlib: {module_version('pwnlib')}",
) + pwndbg.integration.provider.get_versions()
def get_target_arch():
arch_info = pwndbg.aglib.arch.current
target = f"Target Arch: {arch_info}\n"
if pwndbg.dbg.is_gdblib_available():
import gdb
# Note: this are only available if given arch is supported by GDB
# (e.g., `gdb-multiarch` on Ubuntu)
if arch_info in ("arm", "armcm", "aarch64"):
arm_info = gdb.execute("show arm", to_string=True)
target += f"ARM: {arm_info}\n"
elif arch_info in ("mips", "mips64"):
mips_info = gdb.execute("show mips", to_string=True)
target += f"MIPS: {mips_info}\n"
return target
capstone_str = f"Capstone: {capstone_version()}"
unicorn_str = f"Unicorn: {unicorn_version()}"
all_versions = (gdb_str, py_str, pwndbg_str, capstone_str, unicorn_str) def get_terminal_size():
try:
width_info = os.get_terminal_size().columns
height_info = os.get_terminal_size().lines
except OSError:
# Terminal size may not be available in non-interactive environments (e.g., scripts, IDEs)
width_info = height_info = "<unavailable>"
all_versions += pwndbg.integration.provider.get_versions() return f"Terminal width: {width_info}, height: {height_info}\n"
return all_versions
@pwndbg.commands.ArgparsedCommand( @pwndbg.commands.ArgparsedCommand(
"Displays GDB, Python, and pwndbg versions.", category=CommandCategory.PWNDBG "Displays Pwndbg and its important deps versions.", category=CommandCategory.PWNDBG
) )
def version() -> None: def version() -> None:
"""
Displays GDB, Python, and pwndbg versions.
"""
print("\n".join(map(message.system, all_versions()))) print("\n".join(map(message.system, all_versions())))
@ -87,20 +113,19 @@ bugreport_group.add_argument(
def bugreport(run_browser=False, use_gh=False): def bugreport(run_browser=False, use_gh=False):
ISSUE_TEMPLATE = """ ISSUE_TEMPLATE = """
<!-- <!--
Before reporting a new issue, make sure that we do not have any duplicates already open. Please see if the bug isn't reported already on: https://github.com/pwndbg/pwndbg/issues
If there is one it might be good to take part in the discussion there. and take part in discussion if it was.
Please make sure you have checked that the issue persists on LATEST pwndbg version. Before reporting a new issue, make sure it happens on latest Pwndbg version.
Below is a template for BUG REPORTS. Use the template below.
Don't include it if this is a FEATURE REQUEST.
--> -->
### Description ### Description
<!-- <!--
Briefly describe the problem you are having in a few paragraphs. Describe the problem you are having in a few paragraphs.
--> -->
### Steps to reproduce ### Steps to reproduce
@ -111,84 +136,73 @@ If this is connected to particular C/asm code or a binary,
please provide the binary or if possible, a smallest C code that reproduces the issue. please provide the binary or if possible, a smallest C code that reproduces the issue.
--> -->
Gdb session history: Session history:
``` ```
{gdb_history} {session_history}
``` ```
### My setup ### My setup
<!-- <!--
Show us your gdb/python/pwndbg/OS/IDA Pro version (depending on your case). Show us your Pwndbg and any other relevant versions.
NOTE: We are currently testing Pwndbg only on Ubuntu installations but it should work fine on other distros as well.
This can be displayed in pwndbg through `version` command.
If it is somehow unavailable, use:
* `show version` - for gdb
* `py import sys; print(sys.version)` - for python
* pwndbg version/git commit id
--> -->
``` ```
{setup} {setup}
```""" ```"""
setup = "\n".join(all_versions()) + "\n"
setup += f"OS: {os_info()} ({platform.platform()}, {sys.byteorder} endian)\n"
setup += f"OS ABI: {platform.uname().version}\n"
setup += f"Charset: {sys.getdefaultencoding()}\n"
setup += get_terminal_size()
setup += get_target_arch()
gdb_config = gdb.execute("show configuration", to_string=True).split("\n") # Commented out for now: do we need this? It seems to be a bloat for GDB.
all_info = all_versions() # People rarely build custom GDB with fancy options...?
os_info = platform.system() # setup += get_debugger_configuration()
current_setup = f"Platform: {platform.platform()}\n" session_history = get_debugger_session_history()
if os_info.lower() == "linux" and os.path.isfile("/etc/os-release"): issue_bugreport = ISSUE_TEMPLATE.format(setup=setup, session_history=session_history)
with open("/etc/os-release") as os_release: print(issue_bugreport)
contents = os_release.read()
match = re.search('PRETTY_NAME="?([^",\n]+)', contents)
if match:
os_info = match.group(1)
current_setup += f"OS: {os_info}\n"
# 1. showing osabi
osabi_info = platform.uname().version
current_setup += f"OS ABI: {osabi_info}\n"
# 2. showing architecture please_please_submit = "Please submit the bugreport generated above at "
arch_info = platform.machine() github_issue_url = "https://github.com/pwndbg/pwndbg/issues/new"
current_setup += f"Architecture: {arch_info}\n" github_issue_body = "?body=" + quote(issue_bugreport)
# 3. showing endian if use_gh:
endian_info = sys.byteorder try:
current_setup += f"Endian: {endian_info}\n" with NamedTemporaryFile("w", delete=True) as f:
f.write(issue_bugreport)
f.flush()
check_call([os.environ.get("EDITOR", "vi"), f.name])
check_call(["gh", "issue", "create", "--body-file", f.name])
except Exception:
print(please_please_submit + github_issue_url)
elif run_browser:
try:
check_output(["xdg-open", github_issue_url + github_issue_body])
except Exception:
print(please_please_submit + github_issue_url)
else:
print(please_please_submit + github_issue_url)
# 4. Depending on current arch -- note that those are only available if given arch is supported by current GDB, like gdb-multiarch
if arch_info in ["armv7l", "aarch64"]:
arm_info = gdb.execute("show arm", to_string=True)
current_setup += f"ARM: {arm_info}\n"
elif arch_info in ["mips", "mips64"]: def get_debugger_configuration():
mips_info = gdb.execute("show mips", to_string=True) if pwndbg.dbg.is_gdblib_available():
current_setup += f"MIPS: {mips_info}\n" import gdb
# 7. showing charset gdb_config = gdb.execute("show configuration", to_string=True).split("\n")
charset_info = sys.getdefaultencoding() return "\n" + "\n".join(gdb_config)
current_setup += f"Charset: {charset_info}\n"
# 8. showing width, height # LLDB: TODO/FIXME: Do we need this?
try: else:
width_info = os.get_terminal_size().columns return ""
height_info = os.get_terminal_size().lines
except OSError:
# Terminal size may not be available in non-interactive environments (e.g., scripts, IDEs)
width_info = "no terminal size"
height_info = "no terminal size"
current_setup += f"Width: {width_info}\n"
current_setup += f"Height: {height_info}\n"
current_setup += "\n".join(all_info) def get_debugger_session_history():
current_setup += "\n" + "\n".join(gdb_config) if pwndbg.dbg.is_gdblib_available():
import gdb
# get saved history size (not including current gdb session) # get saved history size (not including current gdb session)
gdb_history_file = gdb.execute("show history filename", to_string=True) gdb_history_file = gdb.execute("show history filename", to_string=True)
@ -232,30 +246,8 @@ If it is somehow unavailable, use:
current_command_no += 1 current_command_no += 1
gdb_current_session_history = (v for (k, v) in sorted(gdb_current_session_history.items())) gdb_current_session_history = (v for (k, v) in sorted(gdb_current_session_history.items()))
gdb_current_session_history = "\n".join(gdb_current_session_history) return "\n".join(gdb_current_session_history)
issue_bugreport = ISSUE_TEMPLATE.format( # LLDB: TODO/FIXME: Not yet supported
gdb_history=gdb_current_session_history, setup=current_setup
)
print(issue_bugreport)
please_please_submit = "Please submit the bugreport generated above at "
github_issue_url = "https://github.com/pwndbg/pwndbg/issues/new"
github_issue_body = "?body=" + quote(issue_bugreport)
if use_gh:
try:
with NamedTemporaryFile("w", delete=True) as f:
f.write(issue_bugreport)
f.flush()
check_call([os.environ.get("EDITOR", "vi"), f.name])
check_call(["gh", "issue", "create", "--body-file", f.name])
except Exception:
print(please_please_submit + github_issue_url)
elif run_browser:
try:
check_output(["xdg-open", github_issue_url + github_issue_body])
except Exception:
print(please_please_submit + github_issue_url)
else: else:
print(please_please_submit + github_issue_url) return "<session history not supported on lldb yet>"

Loading…
Cancel
Save