mirror of https://github.com/pwndbg/pwndbg
* Fix #1256: fixes next cmds hangs on segfaults Before this commit the next/step commands like `nextret`, `stepret`, `nextsyscall`, `nextproginstr` etc. would hang if they approach a segfault. This commit fixes it by checking for ANY signals by executing the GDB's `info prog` command and parsing its output. * fix lint
This commit is contained in:
parent
d42444274e
commit
478a569cb3
|
@ -91,6 +91,10 @@ def break_next_interrupt(address=None):
|
|||
|
||||
def break_next_call(symbol_regex=None):
|
||||
while pwndbg.gdblib.proc.alive:
|
||||
# Break on signal as it may be a segfault
|
||||
if pwndbg.gdblib.proc.stopped_with_signal:
|
||||
return
|
||||
|
||||
ins = break_next_branch()
|
||||
|
||||
if not ins:
|
||||
|
@ -115,6 +119,10 @@ def break_next_call(symbol_regex=None):
|
|||
|
||||
def break_next_ret(address=None):
|
||||
while pwndbg.gdblib.proc.alive:
|
||||
# Break on signal as it may be a segfault
|
||||
if pwndbg.gdblib.proc.stopped_with_signal:
|
||||
return
|
||||
|
||||
ins = break_next_branch(address)
|
||||
|
||||
if not ins:
|
||||
|
@ -126,13 +134,14 @@ def break_next_ret(address=None):
|
|||
|
||||
def break_on_program_code():
|
||||
"""
|
||||
Breaks on next instruction that belongs to process' objfile code.
|
||||
:return: True for success, False when process ended or when pc is at the code.
|
||||
Breaks on next instruction that belongs to process' objfile code
|
||||
|
||||
:return: True for success, False when process ended or when pc is not at the code or if a signal occurred
|
||||
"""
|
||||
exe = pwndbg.gdblib.proc.exe
|
||||
binary_exec_page_ranges = [
|
||||
binary_exec_page_ranges = tuple(
|
||||
(p.start, p.end) for p in pwndbg.vmmap.get() if p.objfile == exe and p.execute
|
||||
]
|
||||
)
|
||||
|
||||
pc = pwndbg.gdblib.regs.pc
|
||||
for start, end in binary_exec_page_ranges:
|
||||
|
@ -140,12 +149,18 @@ def break_on_program_code():
|
|||
print(message.error("The pc is already at the binary objfile code. Not stepping."))
|
||||
return False
|
||||
|
||||
while pwndbg.gdblib.proc.alive:
|
||||
gdb.execute("si", from_tty=False, to_string=False)
|
||||
proc = pwndbg.gdblib.proc
|
||||
regs = pwndbg.gdblib.regs
|
||||
|
||||
while proc.alive:
|
||||
# Break on signal as it may be a segfault
|
||||
if proc.stopped_with_signal:
|
||||
return False
|
||||
|
||||
o = gdb.execute("si", from_tty=False, to_string=True)
|
||||
|
||||
pc = pwndbg.gdblib.regs.pc
|
||||
for start, end in binary_exec_page_ranges:
|
||||
if start <= pc < end:
|
||||
if start <= regs.pc < end:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
|
@ -42,6 +42,11 @@ class module(ModuleType):
|
|||
|
||||
@property
|
||||
def alive(self):
|
||||
"""
|
||||
Informs whether the process has a thread. However, note that it will
|
||||
still return True for a segfaulted thread. To detect that, consider
|
||||
using the `stopped_with_signal` method.
|
||||
"""
|
||||
return gdb.selected_thread() is not None
|
||||
|
||||
@property
|
||||
|
@ -56,6 +61,15 @@ class module(ModuleType):
|
|||
"""
|
||||
return gdb.selected_thread().is_stopped()
|
||||
|
||||
@property
|
||||
def stopped_with_signal(self) -> bool:
|
||||
"""
|
||||
Returns whether the program has stopped with a signal
|
||||
|
||||
Can be used to detect segfaults (but will also detect other signals)
|
||||
"""
|
||||
return "It stopped with signal " in gdb.execute("info program", to_string=True)
|
||||
|
||||
@property
|
||||
def exe(self):
|
||||
"""
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import gdb
|
||||
import pytest
|
||||
|
||||
import pwndbg.gdblib.regs
|
||||
import tests
|
||||
|
||||
REFERENCE_BINARY = tests.binaries.get("reference-binary.out")
|
||||
CRASH_SIMPLE_BINARY = tests.binaries.get("crash_simple.out.hardcoded")
|
||||
|
||||
|
||||
def test_command_nextproginstr_binary_not_running():
|
||||
|
@ -40,3 +42,19 @@ def test_command_nextproginstr(start_binary):
|
|||
# Ensure that nextproginstr won't jump now
|
||||
out = gdb.execute("nextproginstr", to_string=True)
|
||||
assert out == "The pc is already at the binary objfile code. Not stepping.\n"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"command",
|
||||
("nextcall", "nextjump", "nextproginstr", "nextret", "nextsyscall", "stepret", "stepsyscall"),
|
||||
)
|
||||
def test_next_command_doesnt_freeze_crashed_binary(start_binary, command):
|
||||
start_binary(REFERENCE_BINARY)
|
||||
|
||||
# The nextproginstr won't step if we are already on the binary address
|
||||
# and interestingly, other commands won't step if the address can't be disassemblied
|
||||
if command == "nextproginstr":
|
||||
pwndbg.gdblib.regs.pc = 0x1234
|
||||
|
||||
# This should not halt/freeze the program
|
||||
gdb.execute(command, to_string=True)
|
||||
|
|
Loading…
Reference in New Issue