diff options
-rw-r--r-- | gdb/NEWS | 4 | ||||
-rw-r--r-- | gdb/doc/python.texi | 3 | ||||
-rw-r--r-- | gdb/python/py-unwind.c | 113 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-unwind.exp | 36 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-unwind.py | 6 |
5 files changed, 111 insertions, 51 deletions
@@ -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)) |