From 14f819c8c5f7d080e5eea9256f0ec7453aac750e Mon Sep 17 00:00:00 2001 From: Tim Wiederhake Date: Tue, 2 May 2017 11:35:54 +0200 Subject: Python: Move and rename gdb.BtraceFunction Remove gdb.BtraceFunctionCall and replace by gdb.FunctionSegment. Additionally, rename prev_segment and next_segment to prev and next. --- gdb/python/py-record-btrace.c | 292 ++++++++++++++---------------------------- gdb/python/py-record-btrace.h | 21 +++ gdb/python/py-record.c | 136 +++++++++++++++++++- gdb/python/py-record.h | 7 + 4 files changed, 255 insertions(+), 201 deletions(-) (limited to 'gdb/python') diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c index 85fb531..d684561 100644 --- a/gdb/python/py-record-btrace.c +++ b/gdb/python/py-record-btrace.c @@ -36,16 +36,6 @@ #endif -#define BTPY_REQUIRE_VALID_CALL(obj, iter) \ - do { \ - struct thread_info *tinfo = find_thread_ptid (obj->ptid); \ - if (tinfo == NULL || btrace_is_empty (tinfo)) \ - return PyErr_Format (gdbpy_gdb_error, _("Empty branch trace.")); \ - if (0 == btrace_find_call_by_number (&iter, &tinfo->btrace, \ - obj->number)) \ - return PyErr_Format (gdbpy_gdb_error, _("No such call segment."));\ - } while (0) - /* Python object for btrace record lists. */ typedef struct { @@ -67,12 +57,6 @@ typedef struct { PyTypeObject* element_type; } btpy_list_object; -/* Python type for btrace function-calls. */ - -static PyTypeObject btpy_call_type = { - PyVarObject_HEAD_INIT (NULL, 0) -}; - /* Python type for btrace lists. */ static PyTypeObject btpy_list_type = { @@ -121,6 +105,49 @@ btrace_insn_from_recpy_insn (const PyObject * const pyobject) return insn; } +/* Returns either a btrace_function for the given Python + gdb.RecordFunctionSegment object or sets an appropriate Python exception and + returns NULL. */ + +static const btrace_function * +btrace_func_from_recpy_func (const PyObject * const pyobject) +{ + const btrace_function *func; + const recpy_element_object *obj; + thread_info *tinfo; + btrace_call_iterator iter; + + if (Py_TYPE (pyobject) != &recpy_func_type) + { + PyErr_Format (gdbpy_gdb_error, _("Must be gdb.RecordFunctionSegment")); + return NULL; + } + + obj = (const recpy_element_object *) pyobject; + tinfo = find_thread_ptid (obj->ptid); + + if (tinfo == NULL || btrace_is_empty (tinfo)) + { + PyErr_Format (gdbpy_gdb_error, _("No such function segment.")); + return NULL; + } + + if (btrace_find_call_by_number (&iter, &tinfo->btrace, obj->number) == 0) + { + PyErr_Format (gdbpy_gdb_error, _("No such function segment.")); + return NULL; + } + + func = btrace_call_get (&iter); + if (func == NULL) + { + PyErr_Format (gdbpy_gdb_error, _("Not a valid function segment.")); + return NULL; + } + + return func; +} + /* Looks at the recorded item with the number NUMBER and create a gdb.RecordInstruction or gdb.RecordGap object for it accordingly. */ @@ -147,24 +174,6 @@ btpy_insn_or_gap_new (const thread_info *tinfo, Py_ssize_t number) return recpy_insn_new (tinfo->ptid, RECORD_METHOD_BTRACE, number); } -/* Create a new gdb.BtraceFunctionCall object. */ - -static PyObject * -btpy_call_new (ptid_t ptid, Py_ssize_t number) -{ - recpy_element_object * const obj = PyObject_New (recpy_element_object, - &btpy_call_type); - - if (obj == NULL) - return NULL; - - obj->ptid = ptid; - obj->method = RECORD_METHOD_BTRACE; - obj->number = number; - - return (PyObject *) obj; -} - /* Create a new gdb.BtraceList object. */ static PyObject * @@ -186,28 +195,6 @@ btpy_list_new (ptid_t ptid, Py_ssize_t first, Py_ssize_t last, Py_ssize_t step, return (PyObject *) obj; } -/* Implementation of BtraceInstruction.number [int] and - BtraceFunctionCall.number [int]. */ - -static PyObject * -btpy_number (PyObject *self, void *closure) -{ - const recpy_element_object * const obj = (const recpy_element_object *) self; - - return PyInt_FromSsize_t (obj->number); -} - -/* Implementation of BtraceInstruction.__hash__ () -> int and - BtraceFunctionCall.__hash__ () -> int. */ - -static Py_hash_t -btpy_hash (PyObject *self) -{ - const recpy_element_object * const obj = (const recpy_element_object *) self; - - return obj->number; -} - /* Implementation of RecordInstruction.sal [gdb.Symtab_and_line] for btrace. Returns the SAL associated with this instruction. */ @@ -344,40 +331,32 @@ recpy_bt_insn_decoded (PyObject *self, void *closure) return PyBytes_FromString (strfile.string ().c_str ()); } -/* Implementation of BtraceFunctionCall.level [int]. Returns the - call level. */ +/* Implementation of RecordFunctionSegment.level [int] for btrace. + Returns the call level. */ -static PyObject * -btpy_call_level (PyObject *self, void *closure) +PyObject * +recpy_bt_func_level (PyObject *self, void *closure) { - const recpy_element_object * const obj = (const recpy_element_object *) self; - const struct btrace_function *func; - struct btrace_call_iterator iter; - - BTPY_REQUIRE_VALID_CALL (obj, iter); + const btrace_function * const func = btrace_func_from_recpy_func (self); + thread_info *tinfo; - func = btrace_call_get (&iter); if (func == NULL) - Py_RETURN_NONE; + return NULL; - return PyInt_FromLong (iter.btinfo->level + func->level); + tinfo = find_thread_ptid (((recpy_element_object *) self)->ptid); + return PyInt_FromLong (tinfo->btrace.level + func->level); } -/* Implementation of BtraceFunctionCall.symbol [gdb.Symbol]. Returns - the symbol associated with this function call. */ +/* Implementation of RecordFunctionSegment.symbol [gdb.Symbol] for btrace. + Returns the symbol associated with this function call. */ -static PyObject * -btpy_call_symbol (PyObject *self, void *closure) +PyObject * +recpy_bt_func_symbol (PyObject *self, void *closure) { - const recpy_element_object * const obj = (const recpy_element_object *) self; - const struct btrace_function *func; - struct btrace_call_iterator iter; + const btrace_function * const func = btrace_func_from_recpy_func (self); - BTPY_REQUIRE_VALID_CALL (obj, iter); - - func = btrace_call_get (&iter); if (func == NULL) - Py_RETURN_NONE; + return NULL; if (func->sym == NULL) Py_RETURN_NONE; @@ -385,22 +364,17 @@ btpy_call_symbol (PyObject *self, void *closure) return symbol_to_symbol_object (func->sym); } -/* Implementation of BtraceFunctionCall.instructions [list]. - Return the list of instructions that belong to this function call. */ +/* Implementation of RecordFunctionSegment.instructions [list] for btrace. + Returns the list of instructions that belong to this function call. */ -static PyObject * -btpy_call_instructions (PyObject *self, void *closure) +PyObject * +recpy_bt_func_instructions (PyObject *self, void *closure) { - const recpy_element_object * const obj = (const recpy_element_object *) self; - const struct btrace_function *func; - struct btrace_call_iterator iter; + const btrace_function * const func = btrace_func_from_recpy_func (self); unsigned int len; - BTPY_REQUIRE_VALID_CALL (obj, iter); - - func = btrace_call_get (&iter); if (func == NULL) - Py_RETURN_NONE; + return NULL; len = VEC_length (btrace_insn_s, func->insn); @@ -408,111 +382,63 @@ btpy_call_instructions (PyObject *self, void *closure) if (len == 0) len = 1; - return btpy_list_new (obj->ptid, func->insn_offset, func->insn_offset + len, - 1, &recpy_insn_type); + return btpy_list_new (((recpy_element_object *) self)->ptid, + func->insn_offset, func->insn_offset + len, 1, + &recpy_insn_type); } -/* Implementation of BtraceFunctionCall.up [gdb.BtraceRecordCall]. - Return the caller / returnee of this function. */ +/* Implementation of RecordFunctionSegment.up [RecordFunctionSegment] for + btrace. Returns the caller / returnee of this function. */ -static PyObject * -btpy_call_up (PyObject *self, void *closure) +PyObject * +recpy_bt_func_up (PyObject *self, void *closure) { - const recpy_element_object * const obj = (const recpy_element_object *) self; - const struct btrace_function *func; - struct btrace_call_iterator iter; - - BTPY_REQUIRE_VALID_CALL (obj, iter); + const btrace_function * const func = btrace_func_from_recpy_func (self); - func = btrace_call_get (&iter); if (func == NULL) - Py_RETURN_NONE; + return NULL; if (func->up == NULL) Py_RETURN_NONE; - return btpy_call_new (obj->ptid, func->up->number); + return recpy_func_new (((recpy_element_object *) self)->ptid, + RECORD_METHOD_BTRACE, func->up->number); } -/* Implementation of BtraceFunctionCall.prev_sibling [BtraceFunctionCall]. - Return a previous segment of this function. */ +/* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment] for + btrace. Returns a previous segment of this function. */ -static PyObject * -btpy_call_prev_sibling (PyObject *self, void *closure) +PyObject * +recpy_bt_func_prev (PyObject *self, void *closure) { - const recpy_element_object * const obj = (const recpy_element_object *) self; - const struct btrace_function *func; - struct btrace_call_iterator iter; - - BTPY_REQUIRE_VALID_CALL (obj, iter); + const btrace_function * const func = btrace_func_from_recpy_func (self); - func = btrace_call_get (&iter); if (func == NULL) - Py_RETURN_NONE; + return NULL; if (func->segment.prev == NULL) Py_RETURN_NONE; - return btpy_call_new (obj->ptid, func->segment.prev->number); + return recpy_func_new (((recpy_element_object *) self)->ptid, + RECORD_METHOD_BTRACE, func->segment.prev->number); } -/* Implementation of BtraceFunctionCall.next_sibling [BtraceFunctionCall]. - Return a following segment of this function. */ +/* Implementation of RecordFunctionSegment.next [RecordFunctionSegment] for + btrace. Returns a following segment of this function. */ -static PyObject * -btpy_call_next_sibling (PyObject *self, void *closure) +PyObject * +recpy_bt_func_next (PyObject *self, void *closure) { - const recpy_element_object * const obj = (const recpy_element_object *) self; - const struct btrace_function *func; - struct btrace_call_iterator iter; + const btrace_function * const func = btrace_func_from_recpy_func (self); - BTPY_REQUIRE_VALID_CALL (obj, iter); - - func = btrace_call_get (&iter); if (func == NULL) - Py_RETURN_NONE; + return NULL; if (func->segment.next == NULL) Py_RETURN_NONE; - return btpy_call_new (obj->ptid, func->segment.next->number); -} - -/* Python rich compare function to allow for equality and inequality checks - in Python. */ - -static PyObject * -btpy_richcompare (PyObject *self, PyObject *other, int op) -{ - const recpy_element_object * const obj1 = (recpy_element_object *) self; - const recpy_element_object * const obj2 = (recpy_element_object *) other; - - if (Py_TYPE (self) != Py_TYPE (other)) - { - Py_INCREF (Py_NotImplemented); - return Py_NotImplemented; - } - - switch (op) - { - case Py_EQ: - if (ptid_equal (obj1->ptid, obj2->ptid) && obj1->number == obj2->number) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; - - case Py_NE: - if (!ptid_equal (obj1->ptid, obj2->ptid) || obj1->number != obj2->number) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; - - default: - break; - } - - Py_INCREF (Py_NotImplemented); - return Py_NotImplemented; + return recpy_func_new (((recpy_element_object *) self)->ptid, + RECORD_METHOD_BTRACE, func->segment.next->number); } /* Implementation of BtraceList.__len__ (self) -> int. */ @@ -550,7 +476,7 @@ btpy_list_item (PyObject *self, Py_ssize_t index) if (obj->element_type == &recpy_insn_type) return recpy_insn_new (obj->ptid, RECORD_METHOD_BTRACE, number); else - return btpy_call_new (obj->ptid, number); + return recpy_func_new (obj->ptid, RECORD_METHOD_BTRACE, number); } /* Implementation of BtraceList.__getitem__ (self, slice) -> BtraceList. */ @@ -839,7 +765,7 @@ recpy_bt_function_call_history (PyObject *self, void *closure) btrace_call_end (&iterator, &tinfo->btrace); last = btrace_call_number (&iterator); - return btpy_list_new (record->ptid, first, last, 1, &btpy_call_type); + return btpy_list_new (record->ptid, first, last, 1, &recpy_func_type); } /* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None. */ @@ -880,23 +806,6 @@ recpy_bt_goto (PyObject *self, PyObject *args) Py_RETURN_NONE; } -/* BtraceFunctionCall members. */ - -static gdb_PyGetSetDef btpy_call_getset[] = -{ - { "number", btpy_number, NULL, "function call number", NULL}, - { "level", btpy_call_level, NULL, "call stack level", NULL}, - { "symbol", btpy_call_symbol, NULL, "associated line and symbol", NULL}, - { "instructions", btpy_call_instructions, NULL, "list of instructions in \ -this function segment", NULL}, - { "up", btpy_call_up, NULL, "caller or returned-to function segment", NULL}, - { "prev_sibling", btpy_call_prev_sibling, NULL, "previous segment of this \ -function", NULL}, - { "next_sibling", btpy_call_next_sibling, NULL, "next segment of this \ -function", NULL}, - {NULL} -}; - /* BtraceList methods. */ struct PyMethodDef btpy_list_methods[] = @@ -925,15 +834,6 @@ static PyMappingMethods btpy_list_mapping_methods = int gdbpy_initialize_btrace (void) { - btpy_call_type.tp_new = PyType_GenericNew; - btpy_call_type.tp_flags = Py_TPFLAGS_DEFAULT; - btpy_call_type.tp_basicsize = sizeof (recpy_element_object); - btpy_call_type.tp_name = "gdb.BtraceFunctionCall"; - btpy_call_type.tp_doc = "GDB btrace call object"; - btpy_call_type.tp_getset = btpy_call_getset; - btpy_call_type.tp_richcompare = btpy_richcompare; - btpy_call_type.tp_hash = btpy_hash; - btpy_list_type.tp_new = PyType_GenericNew; btpy_list_type.tp_flags = Py_TPFLAGS_DEFAULT; btpy_list_type.tp_basicsize = sizeof (btpy_list_object); @@ -950,9 +850,5 @@ gdbpy_initialize_btrace (void) btpy_list_mapping_methods.mp_subscript = btpy_list_slice; - if (PyType_Ready (&btpy_call_type) < 0 - || PyType_Ready (&btpy_list_type) < 0) - return -1; - else - return 0; + return PyType_Ready (&btpy_list_type); } diff --git a/gdb/python/py-record-btrace.h b/gdb/python/py-record-btrace.h index 945129d..81b60ae 100644 --- a/gdb/python/py-record-btrace.h +++ b/gdb/python/py-record-btrace.h @@ -67,4 +67,25 @@ extern PyObject *recpy_bt_insn_size (PyObject *self, void *closure); /* Implementation of RecordInstruction.is_speculative [bool]. */ extern PyObject *recpy_bt_insn_is_speculative (PyObject *self, void *closure); +/* Implementation of RecordFunctionSegment.number [int]. */ +extern PyObject *recpy_bt_func_number (PyObject *self, void *closure); + +/* Implementation of RecordFunctionSegment.number [int]. */ +extern PyObject *recpy_bt_func_level (PyObject *self, void *closure); + +/* Implementation of RecordFunctionSegment.symbol [gdb.Symbol]. */ +extern PyObject *recpy_bt_func_symbol (PyObject *self, void *closure); + +/* Implementation of RecordFunctionSegment.instructions [list]. */ +extern PyObject *recpy_bt_func_instructions (PyObject *self, void *closure); + +/* Implementation of RecordFunctionSegment.up [RecordFunctionSegment]. */ +extern PyObject *recpy_bt_func_up (PyObject *self, void *closure); + +/* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment]. */ +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); + #endif /* GDB_PY_RECORD_BTRACE_H */ diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c index bdc2a3b..d308a94 100644 --- a/gdb/python/py-record.c +++ b/gdb/python/py-record.c @@ -35,6 +35,12 @@ PyTypeObject recpy_insn_type = { PyVarObject_HEAD_INIT (NULL, 0) }; +/* Python RecordFunctionSegment type. */ + +PyTypeObject recpy_func_type = { + PyVarObject_HEAD_INIT (NULL, 0) +}; + /* Python RecordGap type. */ PyTypeObject recpy_gap_type = { @@ -262,7 +268,104 @@ recpy_insn_is_speculative (PyObject *self, void *closure) return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); } -/* Implementation of RecordInstruction.number [int]. */ +/* Create a new gdb.RecordFunctionSegment object. */ + +PyObject * +recpy_func_new (ptid_t ptid, enum record_method method, Py_ssize_t number) +{ + recpy_element_object * const obj = PyObject_New (recpy_element_object, + &recpy_func_type); + + if (obj == NULL) + return NULL; + + obj->ptid = ptid; + obj->method = method; + obj->number = number; + + return (PyObject *) obj; +} + +/* Implementation of RecordFunctionSegment.level [int]. */ + +static PyObject * +recpy_func_level (PyObject *self, void *closure) +{ + const recpy_element_object * const obj = (recpy_element_object *) self; + + if (obj->method == RECORD_METHOD_BTRACE) + return recpy_bt_func_level (self, closure); + + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of RecordFunctionSegment.symbol [gdb.Symbol]. */ + +static PyObject * +recpy_func_symbol (PyObject *self, void *closure) +{ + const recpy_element_object * const obj = (recpy_element_object *) self; + + if (obj->method == RECORD_METHOD_BTRACE) + return recpy_bt_func_symbol (self, closure); + + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of RecordFunctionSegment.instructions [list]. */ + +static PyObject * +recpy_func_instructions (PyObject *self, void *closure) +{ + const recpy_element_object * const obj = (recpy_element_object *) self; + + if (obj->method == RECORD_METHOD_BTRACE) + return recpy_bt_func_instructions (self, closure); + + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of RecordFunctionSegment.up [RecordFunctionSegment]. */ + +static PyObject * +recpy_func_up (PyObject *self, void *closure) +{ + const recpy_element_object * const obj = (recpy_element_object *) self; + + if (obj->method == RECORD_METHOD_BTRACE) + return recpy_bt_func_up (self, closure); + + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment]. */ + +static PyObject * +recpy_func_prev (PyObject *self, void *closure) +{ + const recpy_element_object * const obj = (recpy_element_object *) self; + + if (obj->method == RECORD_METHOD_BTRACE) + return recpy_bt_func_prev (self, closure); + + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of RecordFunctionSegment.next [RecordFunctionSegment]. */ + +static PyObject * +recpy_func_next (PyObject *self, void *closure) +{ + const recpy_element_object * const obj = (recpy_element_object *) self; + + if (obj->method == RECORD_METHOD_BTRACE) + return recpy_bt_func_next (self, closure); + + return PyErr_Format (PyExc_NotImplementedError, _("Not implemented.")); +} + +/* Implementation of RecordInstruction.number [int] and + RecordFunctionSegment.number [int]. */ static PyObject * recpy_element_number (PyObject *self, void* closure) @@ -272,7 +375,9 @@ recpy_element_number (PyObject *self, void* closure) return PyInt_FromSsize_t (obj->number); } -/* Implementation of RecordInstruction.__hash__ [int]. */ +/* Implementation of RecordInstruction.__hash__ [int] and + RecordFunctionSegment.__hash__ [int]. */ + static Py_hash_t recpy_element_hash (PyObject *self) { @@ -281,7 +386,8 @@ recpy_element_hash (PyObject *self) return obj->number; } -/* Implementation of operator == and != of RecordInstruction. */ +/* Implementation of operator == and != of RecordInstruction and + RecordFunctionSegment. */ static PyObject * recpy_element_richcompare (PyObject *self, PyObject *other, int op) @@ -411,6 +517,20 @@ static gdb_PyGetSetDef recpy_insn_getset[] = { { NULL } }; +/* RecordFunctionSegment member list. */ + +static gdb_PyGetSetDef recpy_func_getset[] = { + { "number", recpy_element_number, NULL, "function segment number", NULL}, + { "level", recpy_func_level, NULL, "call stack level", NULL}, + { "symbol", recpy_func_symbol, NULL, "associated line and symbol", NULL}, + { "instructions", recpy_func_instructions, NULL, "list of instructions in \ +this function segment", NULL}, + { "up", recpy_func_up, NULL, "caller or returned-to function segment", NULL}, + { "prev", recpy_func_prev, NULL, "previous segment of this function", NULL}, + { "next", recpy_func_next, NULL, "next segment of this function", NULL}, + { NULL } +}; + /* RecordGap member list. */ static gdb_PyGetSetDef recpy_gap_getset[] = { @@ -442,6 +562,15 @@ gdbpy_initialize_record (void) recpy_insn_type.tp_richcompare = recpy_element_richcompare; recpy_insn_type.tp_hash = recpy_element_hash; + recpy_func_type.tp_new = PyType_GenericNew; + recpy_func_type.tp_flags = Py_TPFLAGS_DEFAULT; + recpy_func_type.tp_basicsize = sizeof (recpy_element_object); + recpy_func_type.tp_name = "gdb.RecordFunctionSegment"; + recpy_func_type.tp_doc = "GDB record function segment object"; + recpy_func_type.tp_getset = recpy_func_getset; + recpy_func_type.tp_richcompare = recpy_element_richcompare; + recpy_func_type.tp_hash = recpy_element_hash; + recpy_gap_type.tp_new = PyType_GenericNew; recpy_gap_type.tp_flags = Py_TPFLAGS_DEFAULT; recpy_gap_type.tp_basicsize = sizeof (recpy_gap_object); @@ -451,6 +580,7 @@ gdbpy_initialize_record (void) 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) return -1; else diff --git a/gdb/python/py-record.h b/gdb/python/py-record.h index ae2d2d2..062abb2 100644 --- a/gdb/python/py-record.h +++ b/gdb/python/py-record.h @@ -56,10 +56,17 @@ typedef struct /* Python RecordInstruction type. */ extern PyTypeObject recpy_insn_type; +/* Python RecordFunctionSegment type. */ +extern PyTypeObject recpy_func_type; + /* Create a new gdb.RecordInstruction object. */ extern PyObject *recpy_insn_new (ptid_t ptid, enum record_method method, Py_ssize_t number); +/* Create a new gdb.RecordFunctionSegment object. */ +extern PyObject *recpy_func_new (ptid_t ptid, enum record_method method, + Py_ssize_t number); + /* Create a new gdb.RecordGap object. */ extern PyObject *recpy_gap_new (int reason_code, const char *reason_string, Py_ssize_t number); -- cgit v1.1