Some improvements to configuration

- Modify `get_set_string()` to match GDB's builtin behaviour
- Make `gcc-compiler-path`'s and `cymbol-editor`'s `set_show_doc` first strings to lowercase
- Change `gcc-compiler-path` and `cymbol-editor` to `gdb.PARAM_OPTIONAL_FILENAME`
- Add resolve_heap_via_heuristic as a gdb.PARAM_ENUM config with options:
  - auto: pwndbg will try to use heuristics if debug symbols are missing
  - force: pwndbg will always try to use heuristics, even if debug symbols are available
  - never: pwndbg will never use heuristics to resolve the heap
- Move some hints to `resolve_heap_via_heuristic`'s `help_docstring`
pull/1437/head
lebr0nli 3 years ago committed by Disconnect3d
parent d28f25c345
commit 0b394a440d

@ -34,11 +34,15 @@ from pwndbg.color import message
gcc_compiler_path = pwndbg.gdblib.config.add_param(
"gcc-compiler-path",
"",
"Path to the gcc/g++ toolchain for generating imported symbols",
"path to the gcc/g++ toolchain for generating imported symbols",
param_class=gdb.PARAM_OPTIONAL_FILENAME,
)
cymbol_editor = pwndbg.gdblib.config.add_param(
"cymbol-editor", "", "Path to the editor for editing custom structures"
"cymbol-editor",
"",
"path to the editor for editing custom structures",
param_class=gdb.PARAM_OPTIONAL_FILENAME,
)
# Remeber loaded symbols. This would be useful for 'remove-symbol-file'.

@ -1179,7 +1179,7 @@ parser.add_argument(
@pwndbg.commands.ArgparsedCommand(parser)
def heap_config(filter_pattern):
display_config(filter_pattern, "heap")
display_config(filter_pattern, "heap", has_file_command=False)
print(
message.hint(

@ -29,9 +29,9 @@ class Parameter(gdb.Parameter):
# `set_doc`, `show_doc`, and `__doc__` must be set before `gdb.Parameter.__init__`.
# They will be used for `help set <param>` and `help show <param>`,
# respectively
self.set_doc = "Set " + param.set_show_doc
self.show_doc = "Show " + param.set_show_doc
self.__doc__ = param.help_docstring
self.set_doc = "Set " + param.set_show_doc + "."
self.show_doc = "Show " + param.set_show_doc + "."
self.__doc__ = param.help_docstring or None
if param.param_class == gdb.PARAM_ENUM:
super().__init__(
@ -76,13 +76,13 @@ class Parameter(gdb.Parameter):
if not pwndbg.decorators.first_prompt:
return ""
return "Set %s to %r" % (self.param.set_show_doc, self.native_value)
return "Set %s to %r." % (self.param.set_show_doc, self.native_value)
def get_show_string(self, svalue):
"""Handles the GDB `show <param>` command"""
return "The current value of %r is %r" % (
self.param.name,
Parameter._value_to_gdb_native(svalue, self.param.param_class),
return "%s is %r." % (
self.param.set_show_doc.capitalize(),
svalue,
)
@staticmethod

@ -1,3 +1,5 @@
import gdb
import pwndbg.color.message as message
import pwndbg.gdblib.config
import pwndbg.gdblib.symbol
@ -7,7 +9,7 @@ current = None
def add_heap_param(
name, default, set_show_doc, *, help_docstring=None, param_class=None, enum_sequence=None
name, default, set_show_doc, *, help_docstring="", param_class=None, enum_sequence=None
):
return pwndbg.gdblib.config.add_param(
name,
@ -35,7 +37,36 @@ symbol_list = [main_arena, thread_arena, mp_, tcache, global_max_fast]
heap_chain_limit = add_heap_param("heap-dereference-limit", 8, "number of bins to dereference")
resolve_heap_via_heuristic = add_heap_param(
"resolve-heap-via-heuristic", False, "Resolve missing heap related symbols via heuristics"
"resolve-heap-via-heuristic",
"auto",
"the strategy to resolve heap via heuristic",
help_docstring="""If pwndbg fails to use the debug symbols to resolve the heap, it can try to resolve the heap via heuristics.
This configuration sets the strategy for resolving the heap.
There are three strategies:
auto == pwndbg will try to use heuristics if debug symbols are missing
force == pwndbg will always try to use heuristics, even if debug symbols are available
never == pwndbg will never use heuristics to resolve the heap
If the output of the heap related command produces errors with heuristics, you can try manually setting the libc symbol addresses.
For this, see the `heap_config` command output and set the `main_arena`, `mp_`, `global_max_fast`, `tcache` and `thread_arena` addresses.
Note: pwndbg will generate more reliable results with proper debug symbols.
Therefore, when debug symbols are missing, you should try to install them first if you haven't already.
They can probably be installed via the package manager of your choice.
See also: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
E.g. on Ubuntu/Debian you might need to do the following steps (for 64-bit and 32-bit binaries):
sudo apt-get install libc6-dbg
sudo dpkg --add-architecture i386
sudo apt-get install libc-dbg:i386
If you used setup.sh on Arch based distro you'll need to do a power cycle or set environment variable manually like this: export DEBUGINFOD_URLS=https://debuginfod.archlinux.org
""",
param_class=gdb.PARAM_ENUM,
enum_sequence=["auto", "force", "never"],
)
@ -59,7 +90,7 @@ def resolve_heap(is_first_run=False):
import pwndbg.heap.ptmalloc
global current
if resolve_heap_via_heuristic:
if resolve_heap_via_heuristic == "force":
current = pwndbg.heap.ptmalloc.HeuristicHeap()
if not is_first_run and pwndbg.gdblib.proc.alive and current.libc_has_debug_syms():
print(
@ -68,11 +99,5 @@ def resolve_heap(is_first_run=False):
" This is not recommended!"
)
)
else:
print(
message.warn(
"You are going to resolve the heap via heuristic. This might not work in all cases."
)
)
else:
current = pwndbg.heap.ptmalloc.DebugSymsHeap()

@ -26,13 +26,18 @@ class Parameter:
default,
set_show_doc,
*,
help_docstring=None,
help_docstring="",
param_class=None,
enum_sequence=None,
scope="config",
):
# Note: `set_show_doc` should be a noun phrase, e.g. "the value of the foo"
# The `set_doc` will be "Set the value of the foo."
# The `show_doc` will be "Show the value of the foo."
# `get_set_string()` will return "Set the value of the foo to VALUE."
# `get_show_string()` will return "Show the value of the foo."
self.set_show_doc = set_show_doc.strip()
self.help_docstring = help_docstring.strip() if help_docstring else None
self.help_docstring = help_docstring.strip()
self.name = name
self.default = default
self.value = default
@ -129,7 +134,7 @@ class Config:
default,
set_show_doc,
*,
help_docstring=None,
help_docstring="",
param_class=None,
enum_sequence=None,
scope="config",

@ -123,7 +123,7 @@ def test_malloc_chunk_command(start_binary):
def test_malloc_chunk_command_heuristic(start_binary):
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")
@ -225,7 +225,7 @@ class mock_for_heuristic:
def test_main_arena_heuristic(start_binary):
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")
@ -267,7 +267,7 @@ def test_main_arena_heuristic(start_binary):
def test_mp_heuristic(start_binary):
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")
@ -303,7 +303,7 @@ def test_mp_heuristic(start_binary):
def test_global_max_fast_heuristic(start_binary):
# TODO: Support other architectures or different libc versions
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")
@ -331,7 +331,7 @@ def test_global_max_fast_heuristic(start_binary):
def test_thread_cache_heuristic(start_binary):
# TODO: Support other architectures or different libc versions
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")
@ -366,7 +366,7 @@ def test_thread_cache_heuristic(start_binary):
def test_thread_arena_heuristic(start_binary):
# TODO: Support other architectures or different libc versions
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")
@ -395,7 +395,7 @@ def test_thread_arena_heuristic(start_binary):
def test_heuristic_fail_gracefully(start_binary):
# TODO: Support other architectures or different libc versions
start_binary(HEAP_MALLOC_CHUNK)
gdb.execute("set resolve-heap-via-heuristic on")
gdb.execute("set resolve-heap-via-heuristic force")
gdb.execute("break break_here")
gdb.execute("continue")

@ -35,10 +35,12 @@ def test_gdb_parameter_default_value_works(start_binary, params):
param_name = f"test-param-{name_suffix}"
help_docstring = f"Help docstring for {param_name}"
set_show_doc = "the value of the foo"
param = pwndbg.gdblib.config.add_param(
param_name,
default_value,
"some show string",
set_show_doc,
help_docstring=help_docstring,
**optional_kwargs,
)
@ -47,7 +49,7 @@ def test_gdb_parameter_default_value_works(start_binary, params):
pwndbg.gdblib.config_mod.Parameter(param)
out = gdb.execute(f"show {param_name}", to_string=True)
assert out == f"The current value of {param_name!r} is {displayed_value!r}\n"
assert out == f"{set_show_doc.capitalize()} is {displayed_value!r}.\n"
if (
optional_kwargs.get("param_class") in (gdb.PARAM_UINTEGER, gdb.PARAM_INTEGER)
and default_value == 0
@ -62,10 +64,10 @@ def test_gdb_parameter_default_value_works(start_binary, params):
assert param.value == default_value
out = gdb.execute(f"help show {param_name}", to_string=True)
assert out == f"Show some show string\n{help_docstring}\n"
assert out == f"Show {set_show_doc}.\n{help_docstring}\n"
assert (
gdb.execute(f"help set {param_name}", to_string=True)
== f"Set some show string\n{help_docstring}\n"
== f"Set {set_show_doc}.\n{help_docstring}\n"
)
# TODO/FIXME: Is there a way to unregister a GDB parameter defined in Python?

@ -30,11 +30,15 @@ def test_triggers():
set_show(param_name, 0)
set_show(param_name, 1)
set_show(param_name, -1)
elif isinstance(p.value, str):
elif isinstance(p.value, str) and p.param_class != gdb.PARAM_ENUM:
set_show(param_name, "")
set_show(param_name, "some invalid text")
set_show(param_name, "red")
set_show(param_name, "bold,yellow")
elif isinstance(p.value, str) and p.param_class == gdb.PARAM_ENUM:
# Only valid values are allowed, invalid values will cause an error
for enum in p.enum_sequence:
set_show(param_name, enum)
else:
print(p.value, type(p.value))
assert False

Loading…
Cancel
Save