aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/NEWS4
-rw-r--r--gdb/doc/python.texi3
-rw-r--r--gdb/python/py-unwind.c113
-rw-r--r--gdb/testsuite/gdb.python/py-unwind.exp36
-rw-r--r--gdb/testsuite/gdb.python/py-unwind.py6
5 files changed, 111 insertions, 51 deletions
diff --git a/gdb/NEWS b/gdb/NEWS
index d5316ff..043847f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -140,6 +140,10 @@ show always-read-ctf
- gdb.PendingFrame.function: Return a gdb.Symbol for the
current pending frame, or None.
+ ** The frame-id passed to gdb.PendingFrame.create_unwind_info can
+ now use either an integer or a gdb.Value object for each of its
+ 'sp', 'pc', and 'special' attributes.
+
*** Changes in GDB 13
* MI version 1 is deprecated, and will be removed in GDB 14.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 80697f9..b41432a 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -2815,7 +2815,8 @@ Inside gdb, this is called a ``wild frame''. You will never need
this.
@end table
-Each attribute value should be an instance of @code{gdb.Value}.
+Each attribute value should either be an instance of @code{gdb.Value}
+or an integer.
@end defun
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 432a26a..409dbd3 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -132,58 +132,63 @@ extern PyTypeObject pending_frame_object_type
extern PyTypeObject unwind_info_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("unwind_info_object");
-/* Convert gdb.Value instance to inferior's pointer. Return 1 on success,
- 0 on failure. */
+/* An enum returned by pyuw_object_attribute_to_pointer, a function which
+ is used to extract an attribute from a Python object. */
-static int
-pyuw_value_obj_to_pointer (PyObject *pyo_value, CORE_ADDR *addr)
+enum class pyuw_get_attr_code
{
- int rc = 0;
- struct value *value;
+ /* The attribute was present, and its value was successfully extracted. */
+ ATTR_OK,
- try
- {
- if ((value = value_object_to_value (pyo_value)) != NULL)
- {
- *addr = unpack_pointer (value->type (),
- value->contents ().data ());
- rc = 1;
- }
- }
- catch (const gdb_exception &except)
- {
- gdbpy_convert_exception (except);
- }
- return rc;
-}
+ /* The attribute was not present, or was present and its value was None.
+ No Python error has been set. */
+ ATTR_MISSING,
-/* Get attribute from an object and convert it to the inferior's
- pointer value. Return 1 if attribute exists and its value can be
- converted. Otherwise, if attribute does not exist or its value is
- None, return 0. In all other cases set Python error and return
- 0. */
+ /* The attribute was present, but there was some error while trying to
+ get the value from the attribute. A Python error will be set when
+ this is returned. */
+ ATTR_ERROR,
+};
-static int
+/* Get the attribute named ATTR_NAME from the object PYO and convert it to
+ an inferior pointer value, placing the pointer in *ADDR.
+
+ Return pyuw_get_attr_code::ATTR_OK if the attribute was present and its
+ value was successfully written into *ADDR. For any other return value
+ the contents of *ADDR are undefined.
+
+ Return pyuw_get_attr_code::ATTR_MISSING if the attribute was not
+ present, or it was present but its value was None. The contents of
+ *ADDR are undefined in this case. No Python error will be set in this
+ case.
+
+ Return pyuw_get_attr_code::ATTR_ERROR if the attribute was present, but
+ there was some error while extracting the attribute's value. A Python
+ error will be set in this case. The contents of *ADDR are undefined. */
+
+static pyuw_get_attr_code
pyuw_object_attribute_to_pointer (PyObject *pyo, const char *attr_name,
CORE_ADDR *addr)
{
- int rc = 0;
+ if (!PyObject_HasAttrString (pyo, attr_name))
+ return pyuw_get_attr_code::ATTR_MISSING;
- if (PyObject_HasAttrString (pyo, attr_name))
+ gdbpy_ref<> pyo_value (PyObject_GetAttrString (pyo, attr_name));
+ if (pyo_value == nullptr)
{
- gdbpy_ref<> pyo_value (PyObject_GetAttrString (pyo, attr_name));
+ gdb_assert (PyErr_Occurred ());
+ return pyuw_get_attr_code::ATTR_ERROR;
+ }
+ if (pyo_value == Py_None)
+ return pyuw_get_attr_code::ATTR_MISSING;
- if (pyo_value != NULL && pyo_value != Py_None)
- {
- rc = pyuw_value_obj_to_pointer (pyo_value.get (), addr);
- if (!rc)
- PyErr_Format (
- PyExc_ValueError,
- _("The value of the '%s' attribute is not a pointer."),
- attr_name);
- }
+ if (get_addr_from_python (pyo_value.get (), addr) < 0)
+ {
+ gdb_assert (PyErr_Occurred ());
+ return pyuw_get_attr_code::ATTR_ERROR;
}
- return rc;
+
+ return pyuw_get_attr_code::ATTR_OK;
}
/* Called by the Python interpreter to obtain string representation
@@ -687,13 +692,18 @@ pending_framepy_create_unwind_info (PyObject *self, PyObject *args)
PENDING_FRAMEPY_REQUIRE_VALID ((pending_frame_object *) self);
if (!PyArg_ParseTuple (args, "O:create_unwind_info", &pyo_frame_id))
- return NULL;
- if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "sp", &sp))
+ return nullptr;
+
+ pyuw_get_attr_code code
+ = pyuw_object_attribute_to_pointer (pyo_frame_id, "sp", &sp);
+ if (code == pyuw_get_attr_code::ATTR_MISSING)
{
PyErr_SetString (PyExc_ValueError,
_("frame_id should have 'sp' attribute."));
- return NULL;
+ return nullptr;
}
+ else if (code == pyuw_get_attr_code::ATTR_ERROR)
+ return nullptr;
/* The logic of building frame_id depending on the attributes of
the frame_id object:
@@ -704,13 +714,20 @@ pending_framepy_create_unwind_info (PyObject *self, PyObject *args)
Y Y N frame_id_build (sp, pc)
Y Y Y frame_id_build_special (sp, pc, special)
*/
- if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "pc", &pc))
+ code = pyuw_object_attribute_to_pointer (pyo_frame_id, "pc", &pc);
+ if (code == pyuw_get_attr_code::ATTR_ERROR)
+ return nullptr;
+ else if (code == pyuw_get_attr_code::ATTR_MISSING)
return pyuw_create_unwind_info (self, frame_id_build_wild (sp));
- if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "special", &special))
+
+ code = pyuw_object_attribute_to_pointer (pyo_frame_id, "special", &special);
+ if (code == pyuw_get_attr_code::ATTR_ERROR)
+ return nullptr;
+ else if (code == pyuw_get_attr_code::ATTR_MISSING)
return pyuw_create_unwind_info (self, frame_id_build (sp, pc));
- else
- return pyuw_create_unwind_info (self,
- frame_id_build_special (sp, pc, special));
+
+ return pyuw_create_unwind_info (self,
+ frame_id_build_special (sp, pc, special));
}
/* Implementation of PendingFrame.architecture (self) -> gdb.Architecture. */
diff --git a/gdb/testsuite/gdb.python/py-unwind.exp b/gdb/testsuite/gdb.python/py-unwind.exp
index d65b844..fddf4f1 100644
--- a/gdb/testsuite/gdb.python/py-unwind.exp
+++ b/gdb/testsuite/gdb.python/py-unwind.exp
@@ -200,6 +200,42 @@ gdb_test "disable unwinder global \"simple\"" \
check_for_fixed_backtrace \
"check backtrace before testing PendingFrame methods"
+# Turn the 'simple' unwinder back on.
+gdb_test "enable unwinder global \"simple\"" \
+ "1 unwinder enabled"
+
+# Replace the "simple" unwinder with a new version that doesn't set
+# the 'sp' attribute. Also the 'pc' attribute is invalid, but we'll
+# hit the missing 'sp' error first.
+with_test_prefix "frame-id 'sp' is None" {
+ gdb_test_no_output "python obj = simple_unwinder(\"simple\", None, \"xyz\")"
+ gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
+ gdb_test_no_output "python captured_pending_frame = None"
+ gdb_test "backtrace" \
+ "Python Exception <class 'ValueError'>: frame_id should have 'sp' attribute\\.\r\n.*"
+}
+
+# Replace the "simple" unwinder with a new version that sets the 'sp'
+# attribute to an invalid value. Also the 'pc' attribute is invalid, but we'll
+# hit the invalid 'sp' error first.
+with_test_prefix "frame-id 'sp' is invalid" {
+ gdb_test_no_output "python obj = simple_unwinder(\"simple\", \"jkl\", \"xyz\")"
+ gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
+ gdb_test_no_output "python captured_pending_frame = None"
+ gdb_test "backtrace" \
+ "Python Exception <class 'ValueError'>: invalid literal for int\\(\\) with base 10: 'jkl'\r\n.*"
+}
+
+# Replace the "simple" unwinder with a new version that sets the 'sp'
+# to a valid value, but set the 'pc' attribute to an invalid value.
+with_test_prefix "frame-id 'pc' is invalid" {
+ gdb_test_no_output "python obj = simple_unwinder(\"simple\", 0x123, \"xyz\")"
+ gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
+ gdb_test_no_output "python captured_pending_frame = None"
+ gdb_test "backtrace" \
+ "Python Exception <class 'ValueError'>: invalid literal for int\\(\\) with base 10: 'xyz'\r\n.*"
+}
+
# Gather information about every frame.
gdb_test_no_output "python capture_all_frame_information()"
gdb_test_no_output "python gdb.newest_frame().select()"
diff --git a/gdb/testsuite/gdb.python/py-unwind.py b/gdb/testsuite/gdb.python/py-unwind.py
index f8f04b7..dbabb00 100644
--- a/gdb/testsuite/gdb.python/py-unwind.py
+++ b/gdb/testsuite/gdb.python/py-unwind.py
@@ -141,8 +141,10 @@ captured_unwind_info_repr = None
class simple_unwinder(Unwinder):
- def __init__(self, name):
+ def __init__(self, name, sp=0x123, pc=0x456):
super().__init__(name)
+ self._sp = sp
+ self._pc = pc
def __call__(self, pending_frame):
global captured_pending_frame
@@ -155,7 +157,7 @@ class simple_unwinder(Unwinder):
if captured_pending_frame is None:
captured_pending_frame = pending_frame
captured_pending_frame_repr = repr(pending_frame)
- fid = FrameId(gdb.Value(0x123), gdb.Value(0x456))
+ fid = FrameId(self._sp, self._pc)
uw = pending_frame.create_unwind_info(fid)
uw.add_saved_register("rip", gdb.Value(0x123))
uw.add_saved_register("rbp", gdb.Value(0x456))