mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-27 01:28:46 +00:00
python: Introduce gdb.RecordAuxiliary class.
Auxiliary instructions are no real instructions and get their own object class, similar to gaps. gdb.Record.instruction_history is now possibly a list of gdb.RecordInstruction, gdb.RecordGap or gdb.RecordAuxiliary objects. This patch is in preparation for the new ptwrite feature, which is based on auxiliary instructions. Approved-By: Markus Metzger <markus.t.metzger@intel.com> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
This commit is contained in:
@@ -4369,6 +4369,19 @@ the current recording method.
|
||||
A human readable string with the reason for the gap.
|
||||
@end defvar
|
||||
|
||||
Some @value{GDBN} features write auxiliary information into the execution
|
||||
history. This information is represented by a @code{gdb.RecordAuxiliary} object
|
||||
in the instruction list. It has the following attributes:
|
||||
|
||||
@defvar RecordAuxiliary.@var{number}
|
||||
An integer identifying this auxiliary. @var{number} corresponds to the numbers
|
||||
seen in @code{record instruction-history} (@pxref{Process Record and Replay}).
|
||||
@end defvar
|
||||
|
||||
@defvar RecordAuxiliary.data
|
||||
A string representation of the auxiliary data.
|
||||
@end defvar
|
||||
|
||||
A @code{gdb.RecordFunctionSegment} object has the following attributes:
|
||||
|
||||
@defvar RecordFunctionSegment.number
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -423,6 +436,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 +494,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 +510,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 +703,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 +725,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 +747,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
|
||||
|
||||
@@ -88,4 +88,7 @@ extern PyObject *recpy_bt_func_prev (PyObject *self, void *closure);
|
||||
/* Implementation of RecordFunctionSegment.next [RecordFunctionSegment]. */
|
||||
extern PyObject *recpy_bt_func_next (PyObject *self, void *closure);
|
||||
|
||||
/* Implementation of RecordAuxiliary.decoded [str]. */
|
||||
extern PyObject *recpy_bt_aux_data (PyObject *self, void *closure);
|
||||
|
||||
#endif /* PYTHON_PY_RECORD_BTRACE_H */
|
||||
|
||||
@@ -48,6 +48,12 @@ static PyTypeObject recpy_gap_type = {
|
||||
PyVarObject_HEAD_INIT (NULL, 0)
|
||||
};
|
||||
|
||||
/* Python RecordAuxiliary type. */
|
||||
|
||||
PyTypeObject recpy_aux_type = {
|
||||
PyVarObject_HEAD_INIT (nullptr, 0)
|
||||
};
|
||||
|
||||
/* Python RecordGap object. */
|
||||
struct recpy_gap_object
|
||||
{
|
||||
@@ -389,8 +395,8 @@ recpy_element_hash (PyObject *self)
|
||||
return obj->number;
|
||||
}
|
||||
|
||||
/* Implementation of operator == and != of RecordInstruction and
|
||||
RecordFunctionSegment. */
|
||||
/* Implementation of operator == and != of RecordInstruction,
|
||||
RecordFunctionSegment and RecordAuxiliary. */
|
||||
|
||||
static PyObject *
|
||||
recpy_element_richcompare (PyObject *self, PyObject *other, int op)
|
||||
@@ -478,6 +484,38 @@ recpy_gap_reason_string (PyObject *self, void *closure)
|
||||
return PyUnicode_FromString (obj->reason_string);
|
||||
}
|
||||
|
||||
/* Create a new gdb.Auxiliary object. */
|
||||
|
||||
PyObject *
|
||||
recpy_aux_new (thread_info *thread, enum record_method method,
|
||||
Py_ssize_t number)
|
||||
{
|
||||
recpy_element_object * const obj = PyObject_New (recpy_element_object,
|
||||
&recpy_aux_type);
|
||||
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
|
||||
obj->thread = thread;
|
||||
obj->method = method;
|
||||
obj->number = number;
|
||||
|
||||
return (PyObject *) obj;
|
||||
}
|
||||
|
||||
/* Implementation of Auxiliary.data [buffer]. */
|
||||
|
||||
static PyObject *
|
||||
recpy_aux_data (PyObject *self, void *closure)
|
||||
{
|
||||
const recpy_element_object * const obj = (recpy_element_object *) self;
|
||||
|
||||
if (obj->method == RECORD_METHOD_BTRACE)
|
||||
return recpy_bt_aux_data (self, closure);
|
||||
|
||||
return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
|
||||
}
|
||||
|
||||
/* Record method list. */
|
||||
|
||||
static PyMethodDef recpy_record_methods[] = {
|
||||
@@ -543,6 +581,14 @@ static gdb_PyGetSetDef recpy_gap_getset[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* RecordAuxiliary member list. */
|
||||
|
||||
static gdb_PyGetSetDef recpy_aux_getset[] = {
|
||||
{ "number", recpy_element_number, nullptr, "element number", nullptr},
|
||||
{ "data", recpy_aux_data, nullptr, "data", nullptr},
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
/* Sets up the record API in the gdb module. */
|
||||
|
||||
static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
|
||||
@@ -582,10 +628,20 @@ gdbpy_initialize_record (void)
|
||||
recpy_gap_type.tp_doc = "GDB recorded gap object";
|
||||
recpy_gap_type.tp_getset = recpy_gap_getset;
|
||||
|
||||
recpy_aux_type.tp_new = PyType_GenericNew;
|
||||
recpy_aux_type.tp_flags = Py_TPFLAGS_DEFAULT;
|
||||
recpy_aux_type.tp_basicsize = sizeof (recpy_element_object);
|
||||
recpy_aux_type.tp_name = "gdb.RecordAuxiliary";
|
||||
recpy_aux_type.tp_doc = "GDB recorded auxiliary object";
|
||||
recpy_aux_type.tp_getset = recpy_aux_getset;
|
||||
recpy_aux_type.tp_richcompare = recpy_element_richcompare;
|
||||
recpy_aux_type.tp_hash = recpy_element_hash;
|
||||
|
||||
if (PyType_Ready (&recpy_record_type) < 0
|
||||
|| PyType_Ready (&recpy_insn_type) < 0
|
||||
|| PyType_Ready (&recpy_func_type) < 0
|
||||
|| PyType_Ready (&recpy_gap_type) < 0)
|
||||
|| PyType_Ready (&recpy_gap_type) < 0
|
||||
|| PyType_Ready (&recpy_aux_type) < 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
@@ -59,6 +59,9 @@ extern PyTypeObject recpy_insn_type;
|
||||
/* Python RecordFunctionSegment type. */
|
||||
extern PyTypeObject recpy_func_type;
|
||||
|
||||
/* Python RecordAuxiliary type. */
|
||||
extern PyTypeObject recpy_aux_type;
|
||||
|
||||
/* Create a new gdb.RecordInstruction object. */
|
||||
extern PyObject *recpy_insn_new (thread_info *thread, enum record_method method,
|
||||
Py_ssize_t number);
|
||||
@@ -71,4 +74,8 @@ extern PyObject *recpy_func_new (thread_info *thread, enum record_method method,
|
||||
extern PyObject *recpy_gap_new (int reason_code, const char *reason_string,
|
||||
Py_ssize_t number);
|
||||
|
||||
/* Create a new gdb.RecordGap object. */
|
||||
extern PyObject *recpy_aux_new (thread_info *thread, enum record_method method,
|
||||
Py_ssize_t number);
|
||||
|
||||
#endif /* PYTHON_PY_RECORD_H */
|
||||
|
||||
Reference in New Issue
Block a user