Bug fix for `gdb.PARAM_ZUINTEGER*` with GDB < 9

GDB < 9 does not support PARAM_ZUINTEGER*, so we implement it by ourselves for consistency
This commit is contained in:
lebr0nli 2023-01-24 15:24:25 +08:00 committed by Gulshan Singh
parent dbfd8d88d7
commit 6f696cc82b
3 changed files with 53 additions and 10 deletions

View File

@ -21,6 +21,11 @@ import pwndbg.lib.config
config = pwndbg.lib.config.Config()
# GDB < 9 does not support PARAM_ZUINTEGER*, so we implement it by ourselves for consistency
if not hasattr(gdb, "PARAM_ZUINTEGER"):
gdb.PARAM_ZUINTEGER = "PARAM_ZUINTEGER"
gdb.PARAM_ZUINTEGER_UNLIMITED = "PARAM_ZUINTEGER_UNLIMITED"
# See this for details about the API of `gdb.Parameter`:
# https://sourceware.org/gdb/onlinedocs/gdb/Parameters-In-Python.html
@ -32,6 +37,7 @@ class Parameter(gdb.Parameter):
self.set_doc = "Set " + param.set_show_doc + "."
self.show_doc = "Show " + param.set_show_doc + "."
self.__doc__ = param.help_docstring or None
self._custom_param_class = None
if param.param_class == gdb.PARAM_ENUM:
super().__init__(
@ -40,6 +46,13 @@ class Parameter(gdb.Parameter):
param.param_class,
param.enum_sequence,
)
elif (
param.param_class == "PARAM_ZUINTEGER"
or param.param_class == "PARAM_ZUINTEGER_UNLIMITED"
):
# GDB < 9 does not support PARAM_ZUINTEGER*, so we implement it by ourselves for consistency
self._custom_param_class = param.param_class
super().__init__(param.name, gdb.COMMAND_SUPPORT, pwndbg.lib.config.PARAM_CLASSES[int])
else:
super().__init__(param.name, gdb.COMMAND_SUPPORT, param.param_class)
self.param = param
@ -66,6 +79,15 @@ class Parameter(gdb.Parameter):
# Anyway, to avoid some unexpected behaviors, we'll still set `self.param.value` to 0 here.
self.param.value = 0
else:
if self._custom_param_class:
if (self._custom_param_class == "PARAM_ZUINTEGER" and self.value < 0) or ( # type: ignore
self._custom_param_class == "PARAM_ZUINTEGER_UNLIMITED" and self.value < -1 # type: ignore
):
err = "integer %d out of range" % self.value # type: ignore
# Restore the old value
self.value = self.param.value
# GDB < 9 is too buggy, it won't handle `gdb.GdbError`..., so we return a string here
return err
self.param.value = self.value
for trigger in config.triggers[self.param.name]:
@ -81,6 +103,8 @@ class Parameter(gdb.Parameter):
def get_show_string(self, svalue) -> str:
"""Handles the GDB `show <param>` command"""
more_information_hint = " See `help set %s` for more information." % self.param.name
if self._custom_param_class == "PARAM_ZUINTEGER_UNLIMITED" and self.value == -1:
svalue = "unlimited"
return "%s is %r.%s" % (
self.param.set_show_doc.capitalize(),
svalue,

View File

@ -14,16 +14,33 @@ import pwndbg.gdblib.config
("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}),
# GDB < 9.x does not support PARAM_ZUINTEGER_UNLIMITED
("unlimited-zuint", -1, "unlimited", {"param_class": gdb.PARAM_ZUINTEGER_UNLIMITED})
if hasattr(gdb, "PARAM_ZUINTEGER_UNLIMITED")
else (),
(
"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):

View File

@ -168,14 +168,16 @@ def test_nearpc_opcode_seperator(start_binary, separator_bytes):
def test_nearpc_opcode_invalid_config():
expected = "integer -1 out of range"
try:
gdb.execute("set nearpc-opcode-bytes -1")
assert False, "nearpc-opcode-bytes should not accept negative values"
# We try to catch the output since GDB < 9 won't raise the exception
assert gdb.execute("set nearpc-opcode-bytes -1", to_string=True).rstrip() == expected
except gdb.error as e:
pass
assert expected == str(e)
try:
gdb.execute("set nearpc-opcode-separator-bytes -1")
assert False, "nearpc-opcode-separator-bytes should not accept negative values"
assert (
gdb.execute("set nearpc-opcode-separator-bytes -1", to_string=True).rstrip() == expected
)
except gdb.error as e:
pass
assert expected == str(e)