diff options
Diffstat (limited to 'gdb/python/py-record-btrace.c')
-rw-r--r-- | gdb/python/py-record-btrace.c | 213 |
1 files changed, 193 insertions, 20 deletions
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c index 36454fc..620f033 100644 --- a/gdb/python/py-record-btrace.c +++ b/gdb/python/py-record-btrace.c @@ -1,6 +1,6 @@ /* Python interface to btrace instruction history. - Copyright 2016-2024 Free Software Foundation, Inc. + Copyright 2016-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -44,7 +44,8 @@ struct btpy_list_object { /* Stride size. */ Py_ssize_t step; - /* Either &BTPY_CALL_TYPE or &RECPY_INSN_TYPE. */ + /* Either &recpy_func_type, &recpy_insn_type, &recpy_aux_type or + &recpy_gap_type. */ PyTypeObject* element_type; }; @@ -140,15 +141,21 @@ btrace_func_from_recpy_func (const PyObject * const pyobject) } /* Looks at the recorded item with the number NUMBER and create a - gdb.RecordInstruction or gdb.RecordGap object for it accordingly. */ + gdb.RecordInstruction, gdb.RecordGap or gdb.RecordAuxiliary object + for it accordingly. */ static PyObject * -btpy_insn_or_gap_new (thread_info *tinfo, Py_ssize_t number) +btpy_item_new (thread_info *tinfo, Py_ssize_t number) { btrace_insn_iterator iter; int err_code; - btrace_find_insn_by_number (&iter, &tinfo->btrace, number); + if (btrace_find_insn_by_number (&iter, &tinfo->btrace, number) == 0) + { + PyErr_Format (gdbpy_gdb_error, _("No such instruction.")); + return nullptr; + } + err_code = btrace_insn_get_error (&iter); if (err_code != 0) @@ -162,6 +169,12 @@ btpy_insn_or_gap_new (thread_info *tinfo, Py_ssize_t number) return recpy_gap_new (err_code, err_string, number); } + const struct btrace_insn *insn = btrace_insn_get (&iter); + gdb_assert (insn != nullptr); + + if (insn->iclass == BTRACE_INSN_AUX) + return recpy_aux_new (tinfo, RECORD_METHOD_BTRACE, number); + return recpy_insn_new (tinfo, RECORD_METHOD_BTRACE, number); } @@ -204,7 +217,7 @@ recpy_bt_insn_sal (PyObject *self, void *closure) } catch (const gdb_exception &except) { - GDB_PY_HANDLE_EXCEPTION (except); + return gdbpy_handle_gdb_exception (nullptr, except); } return result; @@ -275,7 +288,7 @@ recpy_bt_insn_data (PyObject *self, void *closure) } catch (const gdb_exception &except) { - GDB_PY_HANDLE_EXCEPTION (except); + return gdbpy_handle_gdb_exception (nullptr, except); } object = PyBytes_FromStringAndSize ((const char *) buffer.data (), @@ -305,8 +318,7 @@ recpy_bt_insn_decoded (PyObject *self, void *closure) } catch (const gdb_exception &except) { - gdbpy_convert_exception (except); - return NULL; + return gdbpy_handle_gdb_exception (nullptr, except); } return PyBytes_FromString (strfile.string ().c_str ()); @@ -423,6 +435,48 @@ recpy_bt_func_next (PyObject *self, void *closure) RECORD_METHOD_BTRACE, func->next); } +/* Implementation of Auxiliary.data [str] for btrace. */ + +PyObject * +recpy_bt_aux_data (PyObject *self, void *closure) +{ + const btrace_insn *insn; + const recpy_element_object *obj; + thread_info *tinfo; + btrace_insn_iterator iter; + + if (Py_TYPE (self) != &recpy_aux_type) + { + PyErr_Format (gdbpy_gdb_error, _("Must be a gdb.Auxiliary.")); + return nullptr; + } + + obj = (const recpy_element_object *) self; + tinfo = obj->thread; + + if (tinfo == nullptr || btrace_is_empty (tinfo)) + { + PyErr_Format (gdbpy_gdb_error, _("No such auxiliary object.")); + return nullptr; + } + + if (btrace_find_insn_by_number (&iter, &tinfo->btrace, obj->number) == 0) + { + PyErr_Format (gdbpy_gdb_error, _("No such auxiliary object.")); + return nullptr; + } + + insn = btrace_insn_get (&iter); + if (insn == nullptr || insn->iclass != BTRACE_INSN_AUX) + { + PyErr_Format (gdbpy_gdb_error, _("Not a valid auxiliary object.")); + return nullptr; + } + + return PyUnicode_FromString + (iter.btinfo->aux_data.at (insn->aux_data_index).c_str ()); +} + /* Implementation of BtraceList.__len__ (self) -> int. */ static Py_ssize_t @@ -439,8 +493,9 @@ btpy_list_length (PyObject *self) } /* Implementation of - BtraceList.__getitem__ (self, key) -> BtraceInstruction and - BtraceList.__getitem__ (self, key) -> BtraceFunctionCall. */ + BtraceList.__getitem__ (self, key) -> BtraceInstruction, + BtraceList.__getitem__ (self, key) -> BtraceFunctionCall, + BtraceList.__getitem__ (self, key) -> BtraceAuxiliary. */ static PyObject * btpy_list_item (PyObject *self, Py_ssize_t index) @@ -454,10 +509,13 @@ btpy_list_item (PyObject *self, Py_ssize_t index) number = obj->first + (obj->step * index); - if (obj->element_type == &recpy_insn_type) - return recpy_insn_new (obj->thread, RECORD_METHOD_BTRACE, number); - else + if (obj->element_type == &recpy_func_type) return recpy_func_new (obj->thread, RECORD_METHOD_BTRACE, number); + else if (obj->element_type == &recpy_insn_type + || obj->element_type == &recpy_aux_type) + return btpy_item_new (obj->thread, number); + else + return PyErr_Format (gdbpy_gdb_error, _("Not a valid BtraceList object.")); } /* Implementation of BtraceList.__getitem__ (self, slice) -> BtraceList. */ @@ -644,8 +702,7 @@ recpy_bt_replay_position (PyObject *self, void *closure) if (tinfo->btrace.replay == NULL) Py_RETURN_NONE; - return btpy_insn_or_gap_new (tinfo, - btrace_insn_number (tinfo->btrace.replay)); + return btpy_item_new (tinfo, btrace_insn_number (tinfo->btrace.replay)); } /* Implementation of @@ -667,7 +724,7 @@ recpy_bt_begin (PyObject *self, void *closure) Py_RETURN_NONE; btrace_insn_begin (&iterator, &tinfo->btrace); - return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator)); + return btpy_item_new (tinfo, btrace_insn_number (&iterator)); } /* Implementation of @@ -689,7 +746,7 @@ recpy_bt_end (PyObject *self, void *closure) Py_RETURN_NONE; btrace_insn_end (&iterator, &tinfo->btrace); - return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator)); + return btpy_item_new (tinfo, btrace_insn_number (&iterator)); } /* Implementation of @@ -750,6 +807,109 @@ recpy_bt_function_call_history (PyObject *self, void *closure) return btpy_list_new (tinfo, first, last, 1, &recpy_func_type); } +/* Helper function that calls PTW_FILTER with PAYLOAD and IP as arguments. + Returns the string that will be printed, if there is a filter to call. */ +static std::optional<std::string> +recpy_call_filter (const uint64_t payload, std::optional<uint64_t> ip, + const void *ptw_filter) +{ + std::optional<std::string> result; + + gdb_assert (ptw_filter != nullptr); + if ((PyObject *) ptw_filter == Py_None) + return result; + + gdbpy_enter enter_py; + + gdbpy_ref<> py_payload = gdb_py_object_from_ulongest (payload); + + gdbpy_ref<> py_ip; + if (!ip.has_value ()) + py_ip = gdbpy_ref<>::new_reference (Py_None); + else + py_ip = gdb_py_object_from_ulongest (*ip); + + gdbpy_ref<> py_result (PyObject_CallFunctionObjArgs ((PyObject *) ptw_filter, + py_payload.get (), + py_ip.get (), + nullptr)); + + if (py_result == nullptr) + { + gdbpy_print_stack (); + gdbpy_error (_("Couldn't call the ptwrite filter.")); + } + + /* Py_None is valid and results in no output. */ + if (py_result == Py_None) + { + result = ""; + return result; + } + + gdb::unique_xmalloc_ptr<char> user_string + = gdbpy_obj_to_string (py_result.get ()); + + if (user_string == nullptr) + { + gdbpy_print_stack (); + gdbpy_error (_("The ptwrite filter didn't return a string.")); + } + else + result = user_string.get (); + + return result; +} + +/* Helper function returning the current ptwrite filter. */ + +static PyObject * +get_ptwrite_filter () +{ + gdbpy_ref<> module (PyImport_ImportModule ("gdb.ptwrite")); + + if (PyErr_Occurred ()) + { + gdbpy_print_stack (); + gdbpy_error (_("Couldn't import gdb.ptwrite.")); + } + + /* We need to keep the reference count. */ + gdbpy_ref<> ptw_filter (gdbpy_call_method (module.get (), "get_filter")); + + if (PyErr_Occurred ()) + { + gdbpy_print_stack (); + gdbpy_error (_("Couldn't get the ptwrite filter.")); + } + + return ptw_filter.get(); +} + +/* Used for registering any python ptwrite filter to the current thread. A + pointer to this function is stored in the python extension interface. */ + +void +gdbpy_load_ptwrite_filter (const struct extension_language_defn *extlang, + struct btrace_thread_info *btinfo) +{ + gdb_assert (btinfo != nullptr); + + gdbpy_enter enter_py; + + btinfo->ptw_context = get_ptwrite_filter (); + +#if defined (HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE) + if (!btinfo->target->conf.pt.ptwrite && btinfo->ptw_context != Py_None) + warning (_("The target doesn't support decoding ptwrite events.")); +#else + if (btinfo->ptw_context != Py_None) + warning (_("Libipt doesn't support decoding ptwrite events.")); +#endif /* defined (HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE) */ + + btinfo->ptw_callback_fun = &recpy_call_filter; +} + /* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None. */ PyObject * @@ -783,12 +943,25 @@ recpy_bt_goto (PyObject *self, PyObject *args) } catch (const gdb_exception &except) { - GDB_PY_HANDLE_EXCEPTION (except); + return gdbpy_handle_gdb_exception (nullptr, except); } Py_RETURN_NONE; } +/* Implementation of BtraceRecord.clear (self) -> None. */ + +PyObject * +recpy_bt_clear (PyObject *self, PyObject *args) +{ + const recpy_record_object * const record = (recpy_record_object *) self; + thread_info *const tinfo = record->thread; + + btrace_clear (tinfo); + + Py_RETURN_NONE; +} + /* BtraceList methods. */ static PyMethodDef btpy_list_methods[] = @@ -833,7 +1006,7 @@ gdbpy_initialize_btrace (void) btpy_list_mapping_methods.mp_subscript = btpy_list_slice; - return PyType_Ready (&btpy_list_type); + return gdbpy_type_ready (&btpy_list_type); } GDBPY_INITIALIZE_FILE (gdbpy_initialize_btrace); |