You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pwndbg/tests/gdb-tests/tests/test_gdblib_parameter.py

101 lines
3.6 KiB
Python

from __future__ import annotations
import gdb
import pytest
import pwndbg.gdblib.config
@pytest.mark.parametrize(
"params",
(
("int", 123, "123", {}),
("bool", True, "on", {}),
("bool", False, "off", {}),
("string", "some-string-val", "some-string-val", {}),
("auto-bool", None, "auto", {"param_class": gdb.PARAM_AUTO_BOOLEAN}),
("unlimited-uint", 0, "unlimited", {"param_class": gdb.PARAM_UINTEGER}),
("unlimited-int", 0, "unlimited", {"param_class": gdb.PARAM_INTEGER}),
(
"enum",
"enum1",
"enum1",
{"param_class": gdb.PARAM_ENUM, "enum_sequence": ["enum1", "enum2", "enum3"]},
),
# Note: GDB < 9 does not support PARAM_ZUINTEGER*, so we implement it by ourselves for consistency
(
"zuint",
0,
"0",
{
"param_class": (
gdb.PARAM_ZUINTEGER if hasattr(gdb, "PARAM_ZUINTEGER") else "PARAM_ZUINTEGER"
)
},
),
(
"unlimited-zuint",
-1,
"unlimited",
{
"param_class": (
gdb.PARAM_ZUINTEGER_UNLIMITED
if hasattr(gdb, "PARAM_ZUINTEGER_UNLIMITED")
else "PARAM_ZUINTEGER_UNLIMITED"
)
},
),
),
)
def test_gdb_parameter_default_value_works(start_binary, params):
if not params:
pytest.skip("Current GDB version does not support this testcase")
name_suffix, default_value, displayed_value, optional_kwargs = 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,
set_show_doc,
help_docstring=help_docstring,
**optional_kwargs,
)
# Initialize and register param in GDB as if it would be done by gdblib.config.init_params
pwndbg.gdblib.config_mod.Parameter(param)
out = gdb.execute(f"show {param_name}", to_string=True)
assert (
out
== f"{set_show_doc.capitalize()} is {displayed_value!r}. See `help set {param_name}` for more information.\n"
)
if (
optional_kwargs.get("param_class") in (gdb.PARAM_UINTEGER, gdb.PARAM_INTEGER)
and default_value == 0
):
# Note: This is really weird, according to GDB docs, 0 should mean "unlimited" for gdb.PARAM_UINTEGER and gdb.PARAM_INTEGER, but somehow GDB sets the value to `None` actually :/
# And hilarious thing is that GDB won't let you set the default value to `None` when you construct the `gdb.Parameter` object with `gdb.PARAM_UINTEGER` or `gdb.PARAM_INTEGER` lol
# Maybe it's a bug of GDB?
# Anyway, to avoid some unexpected behaviors, we still set pwndbg's Parameter object's value to 0 in `get_set_string()` and `__init__()`
assert gdb.parameter(param_name) is None
else:
assert gdb.parameter(param_name) == default_value
assert param.value == default_value
out = gdb.execute(f"help show {param_name}", to_string=True)
assert out == f"Show {set_show_doc}.\n{help_docstring}\n"
assert (
gdb.execute(f"help set {param_name}", to_string=True)
== f"Set {set_show_doc}.\n{help_docstring}\n"
)
# TODO/FIXME: Is there a way to unregister a GDB parameter defined in Python?
# Probably no? If the fact that we register params above ever causes issues,
# then we should just not test it via gdb.* APIs and only check if the added param
# has proper/expected fields set?