public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Python bindings for GDB record
@ 2017-04-21 10:50 Tim Wiederhake
  2017-04-21 10:50 ` [PATCH v2 1/8] Python: Fix indentation in py-record-btrace.c Tim Wiederhake
                   ` (7 more replies)
  0 siblings, 8 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

Hi all,

This patch series addresses the design issues with the Python bindings for
GDB record, as discussed here:
https://sourceware.org/ml/gdb-patches/2017-04/msg00171.html

V1 of this series can be found here:
https://sourceware.org/ml/gdb-patches/2017-04/msg00424.html

Changes since V1:
* error_string and error_code were renamed to reason_string and reason_code for
  gdb.RecordGap.
* Explicitly test retrieving recorded data from a non current thread.
* Moved some error handling code from patch #6 to patch #5.

Documentation was OK'd by Eli,
Patches #1, #4 and #8 were OK'd by Yao.

Please OK this series to go into master and the 8.0 branch.

Regards,
Tim

Tim Wiederhake (8):
  Python: Fix indentation in py-record-btrace.c
  Python: Fix exception handling in py-record-btrace.c
  Python: Use correct ptid in btrace recording
  Python: Remove ptid from gdb.Record interface
  Python: Introduce gdb.RecordGap class
  Python: Move and rename gdb.BtraceInstruction
  Python: Move and rename gdb.BtraceFunction
  Python: Introduce gdb.Instruction class

 gdb/Makefile.in                                    |   2 +
 gdb/btrace.c                                       |   8 +-
 gdb/doc/python.texi                                | 108 ++--
 gdb/python/py-instruction.c                        |  67 +++
 gdb/python/py-instruction.h                        |  30 +
 gdb/python/py-record-btrace.c                      | 618 ++++++++-------------
 gdb/python/py-record-btrace.h                      |  42 ++
 gdb/python/py-record.c                             | 424 +++++++++++++-
 gdb/python/py-record.h                             |  74 +++
 gdb/python/python-internal.h                       |   2 +
 gdb/python/python.c                                |   1 +
 .../gdb.python/py-record-btrace-threads.c          |  58 ++
 .../gdb.python/py-record-btrace-threads.exp        |  81 +++
 gdb/testsuite/gdb.python/py-record-btrace.exp      |   6 +-
 14 files changed, 1058 insertions(+), 463 deletions(-)
 create mode 100644 gdb/python/py-instruction.c
 create mode 100644 gdb/python/py-instruction.h
 create mode 100644 gdb/python/py-record.h
 create mode 100644 gdb/testsuite/gdb.python/py-record-btrace-threads.c
 create mode 100644 gdb/testsuite/gdb.python/py-record-btrace-threads.exp

-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 3/8] Python: Use correct ptid in btrace recording
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
                   ` (5 preceding siblings ...)
  2017-04-21 10:50 ` [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 14:49   ` Yao Qi
  2017-04-21 10:50 ` [PATCH v2 5/8] Python: Introduce gdb.RecordGap class Tim Wiederhake
  7 siblings, 1 reply; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

The user would always get the instruction_history and function_call_history
objects of the current thread, not the thread for which the gdb.Record object
was created.

The attached testcase fails without this patch and passes with the patch.

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	* btrace.c (btrace_fetch): Set inferior_ptid.
	* python/py-record-btrace.c: Add "py-record.h" include.
	(recpy_bt_format, recpy_bt_replay_position, recpy_bt_begin,
	recpy_bt_end, recpy_bt_instruction_history,
	recpy_bt_function_call_history, recpy_bt_goto): Use ptid stored
	in gdb.Record object instead of current ptid.
	* python/py-record.c: Include new "py-record.h" file.
	(recpy_record_object): Moved to py-record.h.
	* python/py-record.h: New file.

gdb/testsuite/ChangeLog:
	* gdb.python/py-record-btrace-threads.c: New file.
	* gdb.python/py-record-btrace-threads.exp: New file.

---
 gdb/btrace.c                                       |  8 ++-
 gdb/python/py-record-btrace.c                      | 32 +++++----
 gdb/python/py-record.c                             | 17 +----
 gdb/python/py-record.h                             | 40 +++++++++++
 .../gdb.python/py-record-btrace-threads.c          | 58 ++++++++++++++++
 .../gdb.python/py-record-btrace-threads.exp        | 81 ++++++++++++++++++++++
 6 files changed, 207 insertions(+), 29 deletions(-)
 create mode 100644 gdb/python/py-record.h
 create mode 100644 gdb/testsuite/gdb.python/py-record-btrace-threads.c
 create mode 100644 gdb/testsuite/gdb.python/py-record-btrace-threads.exp

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 95dc7ab..77d706b 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -1797,11 +1797,17 @@ btrace_fetch (struct thread_info *tp)
   if (btinfo->replay != NULL)
     return;
 
+  /* With CLI usage, TP->PTID always equals INFERIOR_PTID here.  Now that we
+     can store a gdb.Record object in Python referring to a different thread
+     than the current one, temporarily set INFERIOR_PTID.  */
+  cleanup = save_inferior_ptid ();
+  inferior_ptid = tp->ptid;
+
   /* We should not be called on running or exited threads.  */
   gdb_assert (can_access_registers_ptid (tp->ptid));
 
   btrace_data_init (&btrace);
-  cleanup = make_cleanup_btrace_data (&btrace);
+  make_cleanup_btrace_data (&btrace);
 
   /* Let's first try to extend the trace we already have.  */
   if (btinfo->end != NULL)
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 9d79e2b..018b3d8 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -22,6 +22,7 @@
 #include "gdbcmd.h"
 #include "gdbthread.h"
 #include "btrace.h"
+#include "py-record.h"
 #include "py-record-btrace.h"
 #include "disasm.h"
 
@@ -740,7 +741,8 @@ recpy_bt_method (PyObject *self, void *closure)
 PyObject *
 recpy_bt_format (PyObject *self, void *closure)
 {
-  const struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  const struct thread_info * const tinfo = find_thread_ptid (record->ptid);
   const struct btrace_config * config;
 
   if (tinfo == NULL)
@@ -760,7 +762,8 @@ recpy_bt_format (PyObject *self, void *closure)
 PyObject *
 recpy_bt_replay_position (PyObject *self, void *closure)
 {
-  const struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  const struct thread_info * const tinfo = find_thread_ptid (record->ptid);
 
   if (tinfo == NULL)
     Py_RETURN_NONE;
@@ -768,7 +771,7 @@ recpy_bt_replay_position (PyObject *self, void *closure)
   if (tinfo->btrace.replay == NULL)
     Py_RETURN_NONE;
 
-  return btpy_insn_new (inferior_ptid,
+  return btpy_insn_new (record->ptid,
 			btrace_insn_number (tinfo->btrace.replay));
 }
 
@@ -778,7 +781,8 @@ recpy_bt_replay_position (PyObject *self, void *closure)
 PyObject *
 recpy_bt_begin (PyObject *self, void *closure)
 {
-  struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  struct thread_info * const tinfo = find_thread_ptid (record->ptid);
   struct btrace_insn_iterator iterator;
 
   if (tinfo == NULL)
@@ -790,7 +794,7 @@ recpy_bt_begin (PyObject *self, void *closure)
     Py_RETURN_NONE;
 
   btrace_insn_begin (&iterator, &tinfo->btrace);
-  return btpy_insn_new (inferior_ptid, btrace_insn_number (&iterator));
+  return btpy_insn_new (record->ptid, btrace_insn_number (&iterator));
 }
 
 /* Implementation of
@@ -799,7 +803,8 @@ recpy_bt_begin (PyObject *self, void *closure)
 PyObject *
 recpy_bt_end (PyObject *self, void *closure)
 {
-  struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  struct thread_info * const tinfo = find_thread_ptid (record->ptid);
   struct btrace_insn_iterator iterator;
 
   if (tinfo == NULL)
@@ -811,7 +816,7 @@ recpy_bt_end (PyObject *self, void *closure)
     Py_RETURN_NONE;
 
   btrace_insn_end (&iterator, &tinfo->btrace);
-  return btpy_insn_new (inferior_ptid, btrace_insn_number (&iterator));
+  return btpy_insn_new (record->ptid, btrace_insn_number (&iterator));
 }
 
 /* Implementation of
@@ -820,7 +825,8 @@ recpy_bt_end (PyObject *self, void *closure)
 PyObject *
 recpy_bt_instruction_history (PyObject *self, void *closure)
 {
-  struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  struct thread_info * const tinfo = find_thread_ptid (record->ptid);
   struct btrace_insn_iterator iterator;
   unsigned long first = 0;
   unsigned long last = 0;
@@ -839,7 +845,7 @@ recpy_bt_instruction_history (PyObject *self, void *closure)
    btrace_insn_end (&iterator, &tinfo->btrace);
    last = btrace_insn_number (&iterator);
 
-   return btpy_list_new (inferior_ptid, first, last, 1, &btpy_insn_type);
+   return btpy_list_new (record->ptid, first, last, 1, &btpy_insn_type);
 }
 
 /* Implementation of
@@ -848,7 +854,8 @@ recpy_bt_instruction_history (PyObject *self, void *closure)
 PyObject *
 recpy_bt_function_call_history (PyObject *self, void *closure)
 {
-  struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  struct thread_info * const tinfo = find_thread_ptid (record->ptid);
   struct btrace_call_iterator iterator;
   unsigned long first = 0;
   unsigned long last = 0;
@@ -867,7 +874,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 (inferior_ptid, first, last, 1, &btpy_call_type);
+  return btpy_list_new (record->ptid, first, last, 1, &btpy_call_type);
 }
 
 /* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None.  */
@@ -875,7 +882,8 @@ recpy_bt_function_call_history (PyObject *self, void *closure)
 PyObject *
 recpy_bt_goto (PyObject *self, PyObject *args)
 {
-  struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  const recpy_record_object * const record = (recpy_record_object *) self;
+  struct thread_info * const tinfo = find_thread_ptid (record->ptid);
   const btpy_object *obj;
   PyObject *ret = NULL;
 
diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c
index 72922a4..586687a 100644
--- a/gdb/python/py-record.c
+++ b/gdb/python/py-record.c
@@ -18,26 +18,11 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "inferior.h"
-#include "record.h"
-#include "python-internal.h"
+#include "py-record.h"
 #include "py-record-btrace.h"
 #include "py-record-full.h"
 #include "target.h"
 
-/* Python Record object.  */
-
-typedef struct
-{
-  PyObject_HEAD
-
-  /* The ptid this object refers to.  */
-  ptid_t ptid;
-
-  /* The current recording method.  */
-  enum record_method method;
-} recpy_record_object;
-
 /* Python Record type.  */
 
 static PyTypeObject recpy_record_type = {
diff --git a/gdb/python/py-record.h b/gdb/python/py-record.h
new file mode 100644
index 0000000..c386ba2
--- /dev/null
+++ b/gdb/python/py-record.h
@@ -0,0 +1,40 @@
+/* Python interface to record targets.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_PY_RECORD_H
+#define GDB_PY_RECORD_H
+
+#include "inferior.h"
+#include "python-internal.h"
+#include "record.h"
+
+/* Python Record object.  */
+
+typedef struct
+{
+  PyObject_HEAD
+
+  /* The ptid this object refers to.  */
+  ptid_t ptid;
+
+  /* The current recording method.  */
+  enum record_method method;
+} recpy_record_object;
+
+#endif /* GDB_PY_RECORD_H */
diff --git a/gdb/testsuite/gdb.python/py-record-btrace-threads.c b/gdb/testsuite/gdb.python/py-record-btrace-threads.c
new file mode 100644
index 0000000..3dc58ca
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-record-btrace-threads.c
@@ -0,0 +1,58 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+
+static pthread_barrier_t barrier;
+static int dummy;
+
+static void *
+func1 (void *arg)
+{
+  pthread_barrier_wait (&barrier);
+  dummy = 1; /* bp1 */
+  pthread_barrier_wait (&barrier);
+  dummy = 1;
+  pthread_barrier_wait (&barrier);
+  return arg;
+}
+
+static void *
+func2 (void *arg)
+{
+  pthread_barrier_wait (&barrier);
+  dummy = 2;
+  pthread_barrier_wait (&barrier);
+  dummy = 2;
+  pthread_barrier_wait (&barrier); /* bp2 */
+  return arg;
+}
+
+int
+main (void)
+{
+  pthread_t thread;
+
+  pthread_barrier_init (&barrier, NULL, 2);
+
+  pthread_create (&thread, NULL, func2, NULL);
+  func1 (NULL);
+
+  pthread_join (thread, NULL);
+  pthread_barrier_destroy (&barrier);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.python/py-record-btrace-threads.exp b/gdb/testsuite/gdb.python/py-record-btrace-threads.exp
new file mode 100644
index 0000000..17fb5d0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-record-btrace-threads.exp
@@ -0,0 +1,81 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2017 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Skip this test if btrace is disabled.
+
+if { [skip_btrace_tests] } {
+    untested "skipping btrace tests"
+    return -1
+}
+
+standard_testfile
+
+if { [gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug} ] != "" } {
+    untested "failed to prepare"
+    return -1
+}
+clean_restart $testfile
+
+# Skip this test if python is disabled.
+
+load_lib gdb-python.exp
+if { [skip_python_tests] } {
+    untested "skipping python tests"
+    return -1
+}
+
+if { ![runto_main] } {
+    untested "failed to run to main"
+    return -1
+}
+
+# set up breakpoints
+gdb_breakpoint $srcfile:[gdb_get_line_number "bp1" $srcfile]
+gdb_breakpoint $srcfile:[gdb_get_line_number "bp2" $srcfile]
+
+# record data
+gdb_continue_to_breakpoint "cont to bp.1" ".*bp1.*"
+gdb_test_no_output "record btrace"
+gdb_continue_to_breakpoint "cont to bp.2" ".*bp2.*"
+
+# acquire the record objects for thread 1 and thread 2
+gdb_test "thread 1" ".*"
+gdb_test "record function-call-history" ".*" "fch thread 1"
+gdb_test_no_output "python rec1 = gdb.current_recording()"
+gdb_test "thread 2" ".*"
+gdb_test "record function-call-history" ".*" "fch thread 2"
+gdb_test_no_output "python rec2 = gdb.current_recording()"
+
+# Thread 1 is supposed to call func1 (), thread 2 is supposed to call func2 ().
+# Check that the function call history for the current thread contains a call
+# to the right function and does not contain a call to the wrong function.
+proc check_insn_for_thread { self other } {
+  with_test_prefix "checking thread $self" {
+    gdb_test_no_output "python fch = rec$self.function_call_history"
+    gdb_test_no_output "python f1calls = \{x for x in fch if x.symbol and x.symbol.name == \"func1\"\}"
+    gdb_test_no_output "python f2calls = \{x for x in fch if x.symbol and x.symbol.name == \"func2\"\}"
+
+    gdb_test "python print not f${self}calls" "False"
+    gdb_test "python print not f${other}calls" "True"
+  }
+}
+
+foreach_with_prefix thread { 1 2 } {
+  gdb_test "thread $thread"
+  check_insn_for_thread 1 2
+  check_insn_for_thread 2 1
+}
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
                   ` (2 preceding siblings ...)
  2017-04-21 10:50 ` [PATCH v2 8/8] Python: Introduce gdb.Instruction class Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 12:23   ` Eli Zaretskii
  2017-04-21 15:21   ` Yao Qi
  2017-04-21 10:50 ` [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c Tim Wiederhake
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

Remove gdb.BtraceInstruction and replace by gdb.RecordInstruction.

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	* python/py-record-btrace.c (BTPY_REQUIRE_VALID_INSN): Remove.
	(btpy_object, btpy_insn_type, btpy_new): Remove.
	(btpy_list_object): Use gdb.RecordInstruction type instead of
	gdb.BtraceInstruction type.
	(btrace_insn_from_recpy_insn): New function.
	(btpy_insn_or_gap_new): Adjust comment. Use recpy_insn_new instead of
	btpy_new.
	(btpy_call_new, btpy_list_item): Do not use btpy_new anymore.
	(btpy_number, btpy_hash, btpy_call_level, btpy_call_symbol,
	btpy_call_instructions, btpy_call_up, btpy_call_prev_sibling,
	btpy_call_next_sibling, btpy_richcompare): Use recpy_element_object
	instead of btpy_object.
	(btpy_insn_sal, btpy_insn_pc, btpy_insn_size, btpy_insn_is_speculative,
	btpy_insn_data, btpy_insn_decode): Rename to ...
	(recpy_bt_insn_sal, recpy_bt_insn_pc, recpy_bt_insn_size,
	recpy_bt_insn_is_speculative, recpy_bt_insn_data,
	recpy_bt_insn_decode): This.  Also, use new helper functions.
	(btpy_list_position, recpy_bt_goto): Use recpy_element_object and
	recpy_insn_type.
	(btpy_insn_getset): Remove.
	(gdbpy_initialize_btrace): Remove code to initialize
	gdb.BtraceInstruction.  Use recpy_element_object.
	* python/py-record-btrace.h (recpy_bt_insn_number, recpy_bt_insn_sal,
	recpy_bt_insn_pc, recpy_bt_insn_data, recpy_bt_insn_decoded,
	recpy_bt_insn_size, recpy_bt_insn_is_speculative): New export.
	* python/py-record.c (recpy_insn_type): New static object.
	(recpy_insn_new, recpy_insn_sal, recpy_insn_pc, recpy_insn_data,
	recpy_insn_decoded, recpy_insn_size, recpy_insn_is_speculative,
	recpy_element_number, recpy_element_hash, recpy_element_richcompare):
	New function.
	(recpy_insn_getset): New static object.
	(gdbpy_initialize_record): Initialize gdb.RecordInstruction.
	* python/py-record.h (recpy_element_object): New typedef.
	(recpy_insn_type, recpy_insn_new): New export.

gdb/doc/ChangeLog:
	* python.texi (Recording in Python): Replace gdb.BtraceInstruction with
	gdb.RecordInstruction


---
 gdb/doc/python.texi           |  21 ++--
 gdb/python/py-record-btrace.c | 260 +++++++++++++++++-------------------------
 gdb/python/py-record-btrace.h |  21 ++++
 gdb/python/py-record.c        | 185 ++++++++++++++++++++++++++++++
 gdb/python/py-record.h        |  25 +++-
 5 files changed, 346 insertions(+), 166 deletions(-)

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 67b02ed..10a3ab5 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3149,41 +3149,38 @@ A @code{gdb.Record} object has the following methods:
 Move the replay position to the given @var{instruction}.
 @end defun
 
-The attributes and methods of instruction objects depend on the current
-recording method.  Currently, only btrace instructions are supported.
+A @code{gdb.RecordInstruction} object has the following attributes:
 
-A @code{gdb.BtraceInstruction} object has the following attributes:
-
-@defvar BtraceInstruction.number
+@defvar RecordInstruction.number
 An integer identifying this instruction.  @var{number} corresponds to
 the numbers seen in @code{record instruction-history}
 (@pxref{Process Record and Replay}).
 @end defvar
 
-@defvar BtraceInstruction.sal
+@defvar RecordInstruction.sal
 A @code{gdb.Symtab_and_line} object representing the associated symtab
 and line of this instruction.  May be @code{None} if no debug information is
 available.
 @end defvar
 
-@defvar BtraceInstruction.pc
+@defvar RecordInstruction.pc
 An integer representing this instruction's address.
 @end defvar
 
-@defvar BtraceInstruction.data
+@defvar RecordInstruction.data
 A buffer with the raw instruction data.  In Python 3, the return value is a
 @code{memoryview} object.
 @end defvar
 
-@defvar BtraceInstruction.decoded
+@defvar RecordInstruction.decoded
 A human readable string with the disassembled instruction.
 @end defvar
 
-@defvar BtraceInstruction.size
+@defvar RecordInstruction.size
 The size of the instruction in bytes.
 @end defvar
 
-@defvar BtraceInstruction.is_speculative
+@defvar RecordInstruction.is_speculative
 A boolean indicating whether the instruction was executed
 speculatively.
 @end defvar
@@ -3230,7 +3227,7 @@ An integer representing the function call's stack level.  May be
 @end defvar
 
 @defvar BtraceFunctionCall.instructions
-A list of @code{gdb.BtraceInstruction} or @code{gdb.RecordGap} objects
+A list of @code{gdb.RecordInstruction} or @code{gdb.RecordGap} objects
 associated with this function call.
 @end defvar
 
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 89a57e5..b0b4605 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -36,16 +36,6 @@
 
 #endif
 
-#define BTPY_REQUIRE_VALID_INSN(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_insn_by_number (&iter, &tinfo->btrace,		\
-					 obj->number))			\
-      return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));	\
-  } while (0)
-
 #define BTPY_REQUIRE_VALID_CALL(obj, iter)				\
   do {									\
     struct thread_info *tinfo = find_thread_ptid (obj->ptid);		\
@@ -56,20 +46,6 @@
       return PyErr_Format (gdbpy_gdb_error, _("No such call segment."));\
   } while (0)
 
-/* This can either be a btrace instruction or a function call segment,
-   depending on the chosen type.  */
-
-typedef struct {
-  PyObject_HEAD
-
-  /* The thread this object belongs to.  */
-  ptid_t ptid;
-
-  /* Instruction number or function call segment number, depending on the type
-     of this object.  */
-  Py_ssize_t number;
-} btpy_object;
-
 /* Python object for btrace record lists.  */
 
 typedef struct {
@@ -87,16 +63,10 @@ typedef struct {
   /* Stride size.  */
   Py_ssize_t step;
 
-  /* Either &BTPY_CALL_TYPE or &BTPY_INSN_TYPE.  */
+  /* Either &BTPY_CALL_TYPE or &RECPY_INSN_TYPE.  */
   PyTypeObject* element_type;
 } btpy_list_object;
 
-/* Python type for btrace instructions.  */
-
-static PyTypeObject btpy_insn_type = {
-  PyVarObject_HEAD_INIT (NULL, 0)
-};
-
 /* Python type for btrace function-calls.  */
 
 static PyTypeObject btpy_call_type = {
@@ -109,25 +79,50 @@ static PyTypeObject btpy_list_type = {
   PyVarObject_HEAD_INIT (NULL, 0)
 };
 
-/* Create a new gdb.BtraceInstruction or gdb.BtraceFunctionCall object,
-   depending on TYPE.  */
+/* Returns either a btrace_insn for the given Python gdb.RecordInstruction
+   object or sets an appropriate Python exception and returns NULL.  */
 
-static PyObject *
-btpy_new (ptid_t ptid, Py_ssize_t number, PyTypeObject* type)
+static const btrace_insn *
+btrace_insn_from_recpy_insn (const PyObject * const pyobject)
 {
-  btpy_object * const obj = PyObject_New (btpy_object, type);
+  const btrace_insn *insn;
+  const recpy_element_object *obj;
+  thread_info *tinfo;
+  btrace_insn_iterator iter;
 
-  if (obj == NULL)
-    return NULL;
+  if (Py_TYPE (pyobject) != &recpy_insn_type)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("Must be gdb.RecordInstruction"));
+      return NULL;
+    }
 
-  obj->ptid = ptid;
-  obj->number = number;
+  obj = (const recpy_element_object *) pyobject;
+  tinfo = find_thread_ptid (obj->ptid);
 
-  return (PyObject *) obj;
+  if (tinfo == NULL || btrace_is_empty (tinfo))
+    {
+      PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+      return NULL;
+    }
+
+  if (btrace_find_insn_by_number (&iter, &tinfo->btrace, obj->number) == 0)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+      return NULL;
+    }
+
+  insn = btrace_insn_get (&iter);
+  if (insn == NULL)
+    {
+      PyErr_Format (gdbpy_gdb_error, _("Not a valid instruction."));
+      return NULL;
+    }
+
+  return insn;
 }
 
 /* Looks at the recorded item with the number NUMBER and create a
-   gdb.BtraceInstruction or gdb.RecordGap object for it accordingly.  */
+   gdb.RecordInstruction or gdb.RecordGap object for it accordingly.  */
 
 static PyObject *
 btpy_insn_or_gap_new (const thread_info *tinfo, Py_ssize_t number)
@@ -149,7 +144,7 @@ btpy_insn_or_gap_new (const thread_info *tinfo, Py_ssize_t number)
       return recpy_gap_new (err_code, err_string, number);
     }
 
-  return btpy_new (tinfo->ptid, number, &btpy_insn_type);
+  return recpy_insn_new (tinfo->ptid, RECORD_METHOD_BTRACE, number);
 }
 
 /* Create a new gdb.BtraceFunctionCall object.  */
@@ -157,7 +152,17 @@ btpy_insn_or_gap_new (const thread_info *tinfo, Py_ssize_t number)
 static PyObject *
 btpy_call_new (ptid_t ptid, Py_ssize_t number)
 {
-  return btpy_new (ptid, number, &btpy_call_type);
+  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.  */
@@ -187,7 +192,7 @@ btpy_list_new (ptid_t ptid, Py_ssize_t first, Py_ssize_t last, Py_ssize_t step,
 static PyObject *
 btpy_number (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
 
   return PyInt_FromSsize_t (obj->number);
 }
@@ -198,27 +203,22 @@ btpy_number (PyObject *self, void *closure)
 static Py_hash_t
 btpy_hash (PyObject *self)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
 
   return obj->number;
 }
 
-/* Implementation of BtraceInstruction.sal [gdb.Symtab_and_line].
-   Return the SAL associated with this instruction.  */
+/* Implementation of RecordInstruction.sal [gdb.Symtab_and_line] for btrace.
+   Returns the SAL associated with this instruction.  */
 
-static PyObject *
-btpy_insn_sal (PyObject *self, void *closure)
+PyObject *
+recpy_bt_insn_sal (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
-  const struct btrace_insn *insn;
-  struct btrace_insn_iterator iter;
+  const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
   PyObject *result = NULL;
 
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
-
-  insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+    return NULL;
 
   TRY
     {
@@ -233,59 +233,44 @@ btpy_insn_sal (PyObject *self, void *closure)
   return result;
 }
 
-/* Implementation of BtraceInstruction.pc [int].  Returns
-   the instruction address.  */
+/* Implementation of RecordInstruction.pc [int] for btrace.
+   Returns the instruction address.  */
 
-static PyObject *
-btpy_insn_pc (PyObject *self, void *closure)
+PyObject *
+recpy_bt_insn_pc (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
-  const struct btrace_insn *insn;
-  struct btrace_insn_iterator iter;
+  const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
 
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
-
-  insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+    return NULL;
 
   return gdb_py_long_from_ulongest (insn->pc);
 }
 
-/* Implementation of BtraceInstruction.size [int].  Returns
-   the instruction size.  */
+/* Implementation of RecordInstruction.size [int] for btrace.
+   Returns the instruction size.  */
 
-static PyObject *
-btpy_insn_size (PyObject *self, void *closure)
+PyObject *
+recpy_bt_insn_size (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
-  const struct btrace_insn *insn;
-  struct btrace_insn_iterator iter;
-
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
+  const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
 
-  insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+    return NULL;
 
   return PyInt_FromLong (insn->size);
 }
 
-/* Implementation of BtraceInstruction.is_speculative [bool].
+/* Implementation of RecordInstruction.is_speculative [bool] for btrace.
    Returns if this instruction was executed speculatively.  */
 
-static PyObject *
-btpy_insn_is_speculative (PyObject *self, void *closure)
+PyObject *
+recpy_bt_insn_is_speculative (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
-  const struct btrace_insn *insn;
-  struct btrace_insn_iterator iter;
-
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
+  const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
 
-  insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+    return NULL;
 
   if (insn->flags & BTRACE_INSN_FLAG_SPECULATIVE)
     Py_RETURN_TRUE;
@@ -293,23 +278,18 @@ btpy_insn_is_speculative (PyObject *self, void *closure)
     Py_RETURN_FALSE;
 }
 
-/* Implementation of BtraceInstruction.data [buffer].
+/* Implementation of RecordInstruction.data [buffer] for btrace.
    Returns raw instruction data.  */
 
-static PyObject *
-btpy_insn_data (PyObject *self, void *closure)
+PyObject *
+recpy_bt_insn_data (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
-  const struct btrace_insn *insn;
-  struct btrace_insn_iterator iter;
+  const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
   gdb_byte *buffer = NULL;
   PyObject *object;
 
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
-
-  insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+    return NULL;
 
   TRY
     {
@@ -341,23 +321,18 @@ btpy_insn_data (PyObject *self, void *closure)
 
 }
 
-/* Implementation of BtraceInstruction.decode [str].  Returns
-   the instruction as human readable string.  */
+/* Implementation of RecordInstruction.decoded [str] for btrace.
+   Returns the instruction as human readable string.  */
 
-static PyObject *
-btpy_insn_decode (PyObject *self, void *closure)
+PyObject *
+recpy_bt_insn_decoded (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
-  const struct btrace_insn *insn;
-  struct btrace_insn_iterator iter;
+  const btrace_insn * const insn = btrace_insn_from_recpy_insn (self);
   string_file strfile;
   int length = 0;
 
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
-
-  insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
+    return NULL;
 
   TRY
     {
@@ -381,7 +356,7 @@ btpy_insn_decode (PyObject *self, void *closure)
 static PyObject *
 btpy_call_level (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
   const struct btrace_function *func;
   struct btrace_call_iterator iter;
 
@@ -400,7 +375,7 @@ btpy_call_level (PyObject *self, void *closure)
 static PyObject *
 btpy_call_symbol (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
   const struct btrace_function *func;
   struct btrace_call_iterator iter;
 
@@ -422,7 +397,7 @@ btpy_call_symbol (PyObject *self, void *closure)
 static PyObject *
 btpy_call_instructions (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
   const struct btrace_function *func;
   struct btrace_call_iterator iter;
   unsigned int len;
@@ -440,7 +415,7 @@ btpy_call_instructions (PyObject *self, void *closure)
     len = 1;
 
   return btpy_list_new (obj->ptid, func->insn_offset, func->insn_offset + len,
-			1, &btpy_insn_type);
+			1, &recpy_insn_type);
 }
 
 /* Implementation of BtraceFunctionCall.up [gdb.BtraceRecordCall].
@@ -449,7 +424,7 @@ btpy_call_instructions (PyObject *self, void *closure)
 static PyObject *
 btpy_call_up (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
   const struct btrace_function *func;
   struct btrace_call_iterator iter;
 
@@ -471,7 +446,7 @@ btpy_call_up (PyObject *self, void *closure)
 static PyObject *
 btpy_call_prev_sibling (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
   const struct btrace_function *func;
   struct btrace_call_iterator iter;
 
@@ -493,7 +468,7 @@ btpy_call_prev_sibling (PyObject *self, void *closure)
 static PyObject *
 btpy_call_next_sibling (PyObject *self, void *closure)
 {
-  const btpy_object * const obj = (btpy_object *) self;
+  const recpy_element_object * const obj = (const recpy_element_object *) self;
   const struct btrace_function *func;
   struct btrace_call_iterator iter;
 
@@ -515,8 +490,8 @@ btpy_call_next_sibling (PyObject *self, void *closure)
 static PyObject *
 btpy_richcompare (PyObject *self, PyObject *other, int op)
 {
-  const btpy_object * const obj1 = (btpy_object *) self;
-  const btpy_object * const obj2 = (btpy_object *) other;
+  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))
     {
@@ -570,13 +545,18 @@ btpy_list_item (PyObject *self, Py_ssize_t index)
 {
   const btpy_list_object * const obj = (btpy_list_object *) self;
   struct thread_info * const tinfo = find_thread_ptid (obj->ptid);
+  Py_ssize_t number;
 
   if (index < 0 || index >= btpy_list_length (self))
     return PyErr_Format (PyExc_IndexError, _("Index out of range: %zd."),
 			 index);
 
-  return btpy_new (obj->ptid, obj->first + (obj->step * index),
-		   obj->element_type);
+  number = obj->first + (obj->step * 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);
 }
 
 /* Implementation of BtraceList.__getitem__ (self, slice) -> BtraceList.  */
@@ -618,7 +598,7 @@ static LONGEST
 btpy_list_position (PyObject *self, PyObject *value)
 {
   const btpy_list_object * const list_obj = (btpy_list_object *) self;
-  const btpy_object * const obj = (btpy_object *) value;
+  const recpy_element_object * const obj = (const recpy_element_object *) value;
   Py_ssize_t index = obj->number;
 
   if (list_obj->element_type != Py_TYPE (value))
@@ -836,7 +816,7 @@ recpy_bt_instruction_history (PyObject *self, void *closure)
    btrace_insn_end (&iterator, &tinfo->btrace);
    last = btrace_insn_number (&iterator);
 
-   return btpy_list_new (record->ptid, first, last, 1, &btpy_insn_type);
+   return btpy_list_new (record->ptid, first, last, 1, &recpy_insn_type);
 }
 
 /* Implementation of
@@ -875,7 +855,7 @@ recpy_bt_goto (PyObject *self, PyObject *args)
 {
   const recpy_record_object * const record = (recpy_record_object *) self;
   struct thread_info * const tinfo = find_thread_ptid (record->ptid);
-  const btpy_object *obj;
+  const recpy_element_object *obj;
   PyObject *ret = NULL;
 
   if (tinfo == NULL || btrace_is_empty (tinfo))
@@ -884,7 +864,7 @@ recpy_bt_goto (PyObject *self, PyObject *args)
   if (!PyArg_ParseTuple (args, "O", &obj))
     return NULL;
 
-  if (Py_TYPE (obj) != &btpy_insn_type)
+  if (Py_TYPE (obj) != &recpy_insn_type)
     return PyErr_Format (PyExc_TypeError, _("Argument must be instruction."));
 
   TRY
@@ -910,22 +890,6 @@ recpy_bt_goto (PyObject *self, PyObject *args)
   return ret;
 }
 
-/* BtraceInstruction members.  */
-
-struct PyGetSetDef btpy_insn_getset[] =
-{
-  { "number", btpy_number, NULL, "instruction number", NULL},
-  { "sal", btpy_insn_sal, NULL, "associated symbol and line", NULL},
-  { "pc", btpy_insn_pc, NULL, "instruction address", NULL},
-  { "data", btpy_insn_data, NULL, "raw instruction data", NULL},
-  { "decoded", btpy_insn_decode, NULL, "decoded instruction or error message \
-if the instruction is a gap", NULL},
-  { "size", btpy_insn_size, NULL, "instruction size in byte", NULL},
-  { "is_speculative", btpy_insn_is_speculative, NULL, "if the instruction was \
-executed speculatively", NULL},
-  {NULL}
-};
-
 /* BtraceFunctionCall members.  */
 
 static PyGetSetDef btpy_call_getset[] =
@@ -971,18 +935,9 @@ static PyMappingMethods btpy_list_mapping_methods =
 int
 gdbpy_initialize_btrace (void)
 {
-  btpy_insn_type.tp_new = PyType_GenericNew;
-  btpy_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
-  btpy_insn_type.tp_basicsize = sizeof (btpy_object);
-  btpy_insn_type.tp_name = "gdb.BtraceInstruction";
-  btpy_insn_type.tp_doc = "GDB btrace instruction object";
-  btpy_insn_type.tp_getset = btpy_insn_getset;
-  btpy_insn_type.tp_richcompare = btpy_richcompare;
-  btpy_insn_type.tp_hash = btpy_hash;
-
   btpy_call_type.tp_new = PyType_GenericNew;
   btpy_call_type.tp_flags = Py_TPFLAGS_DEFAULT;
-  btpy_call_type.tp_basicsize = sizeof (btpy_object);
+  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;
@@ -1005,8 +960,7 @@ gdbpy_initialize_btrace (void)
 
   btpy_list_mapping_methods.mp_subscript = btpy_list_slice;
 
-  if (PyType_Ready (&btpy_insn_type) < 0
-      || PyType_Ready (&btpy_call_type) < 0
+  if (PyType_Ready (&btpy_call_type) < 0
       || PyType_Ready (&btpy_list_type) < 0)
     return -1;
   else
diff --git a/gdb/python/py-record-btrace.h b/gdb/python/py-record-btrace.h
index aefb1e4..945129d 100644
--- a/gdb/python/py-record-btrace.h
+++ b/gdb/python/py-record-btrace.h
@@ -46,4 +46,25 @@ extern PyObject *recpy_bt_begin (PyObject *self, void *closure);
 /* Implementation of record.end [instruction].  */
 extern PyObject *recpy_bt_end (PyObject *self, void *closure);
 
+/* Implementation of RecordInstruction.number [int].  */
+extern PyObject *recpy_bt_insn_number (PyObject *self, void *closure);
+
+/* Implementation of RecordInstruction.sal [gdb.Symtab_and_line].  */
+extern PyObject *recpy_bt_insn_sal (PyObject *self, void *closure);
+
+/* Implementation of RecordInstruction.pc [int].  */
+extern PyObject *recpy_bt_insn_pc (PyObject *self, void *closure);
+
+/* Implementation of RecordInstruction.data [buffer].  */
+extern PyObject *recpy_bt_insn_data (PyObject *self, void *closure);
+
+/* Implementation of RecordInstruction.decoded [str].  */
+extern PyObject *recpy_bt_insn_decoded (PyObject *self, void *closure);
+
+/* Implementation of RecordInstruction.size [int].  */
+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);
+
 #endif /* GDB_PY_RECORD_BTRACE_H */
diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c
index 8420bc0..d186e18 100644
--- a/gdb/python/py-record.c
+++ b/gdb/python/py-record.c
@@ -29,6 +29,12 @@ static PyTypeObject recpy_record_type = {
   PyVarObject_HEAD_INIT (NULL, 0)
 };
 
+/* Python RecordInstruction type.  */
+
+PyTypeObject recpy_insn_type = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+};
+
 /* Python RecordGap type.  */
 
 PyTypeObject recpy_gap_type = {
@@ -160,6 +166,161 @@ recpy_end (PyObject *self, void* closure)
   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
 }
 
+/* Create a new gdb.RecordInstruction object.  */
+
+PyObject *
+recpy_insn_new (ptid_t ptid, enum record_method method, Py_ssize_t number)
+{
+  recpy_element_object * const obj = PyObject_New (recpy_element_object,
+						   &recpy_insn_type);
+
+  if (obj == NULL)
+   return NULL;
+
+  obj->ptid = ptid;
+  obj->method = method;
+  obj->number = number;
+
+  return (PyObject *) obj;
+}
+
+/* Implementation of RecordInstruction.sal [gdb.Symtab_and_line].  */
+
+static PyObject *
+recpy_insn_sal (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_insn_sal (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Implementation of RecordInstruction.pc [int].  */
+
+static PyObject *
+recpy_insn_pc (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_insn_pc (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Implementation of RecordInstruction.data [buffer].  */
+
+static PyObject *
+recpy_insn_data (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_insn_data (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Implementation of RecordInstruction.decoded [str].  */
+
+static PyObject *
+recpy_insn_decoded (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_insn_decoded (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Implementation of RecordInstruction.size [int].  */
+
+static PyObject *
+recpy_insn_size (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_insn_size (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Implementation of RecordInstruction.is_speculative [bool].  */
+
+static PyObject *
+recpy_insn_is_speculative (PyObject *self, void *closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  if (obj->method == RECORD_METHOD_BTRACE)
+    return recpy_bt_insn_is_speculative (self, closure);
+
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Implementation of RecordInstruction.number [int].  */
+
+static PyObject *
+recpy_element_number (PyObject *self, void* closure)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  return PyInt_FromSsize_t (obj->number);
+}
+
+/* Implementation of RecordInstruction.__hash__ [int].  */
+static Py_hash_t
+recpy_element_hash (PyObject *self)
+{
+  const recpy_element_object * const obj = (recpy_element_object *) self;
+
+  return obj->number;
+}
+
+/* Implementation of operator == and != of RecordInstruction.  */
+
+static PyObject *
+recpy_element_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->method == obj2->method
+	  && obj1->number == obj2->number)
+	Py_RETURN_TRUE;
+      else
+	Py_RETURN_FALSE;
+
+    case Py_NE:
+      if (!ptid_equal (obj1->ptid, obj2->ptid)
+	  || obj1->method != obj2->method
+	  || obj1->number != obj2->number)
+	Py_RETURN_TRUE;
+      else
+	Py_RETURN_FALSE;
+
+    default:
+      break;
+  }
+
+  Py_INCREF (Py_NotImplemented);
+  return Py_NotImplemented;
+}
+
 /* Create a new gdb.RecordGap object.  */
 
 PyObject *
@@ -236,6 +397,20 @@ the current instruction and is used for e.g. record.goto (record.end).", NULL },
   { NULL }
 };
 
+/* RecordInstruction member list.  */
+
+static PyGetSetDef recpy_insn_getset[] = {
+  { "number", recpy_element_number, NULL, "instruction number", NULL},
+  { "sal", recpy_insn_sal, NULL, "associated symbol and line", NULL},
+  { "pc", recpy_insn_pc, NULL, "instruction address", NULL},
+  { "data", recpy_insn_data, NULL, "raw instruction data", NULL},
+  { "decoded", recpy_insn_decoded, NULL, "decoded instruction", NULL},
+  { "size", recpy_insn_size, NULL, "instruction size in byte", NULL},
+  { "is_speculative", recpy_insn_is_speculative, NULL, "if the instruction was \
+  executed speculatively", NULL},
+  { NULL }
+};
+
 /* RecordGap member list.  */
 
 static PyGetSetDef recpy_gap_getset[] = {
@@ -258,6 +433,15 @@ gdbpy_initialize_record (void)
   recpy_record_type.tp_methods = recpy_record_methods;
   recpy_record_type.tp_getset = recpy_record_getset;
 
+  recpy_insn_type.tp_new = PyType_GenericNew;
+  recpy_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
+  recpy_insn_type.tp_basicsize = sizeof (recpy_element_object);
+  recpy_insn_type.tp_name = "gdb.RecordInstruction";
+  recpy_insn_type.tp_doc = "GDB recorded instruction object";
+  recpy_insn_type.tp_getset = recpy_insn_getset;
+  recpy_insn_type.tp_richcompare = recpy_element_richcompare;
+  recpy_insn_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);
@@ -266,6 +450,7 @@ gdbpy_initialize_record (void)
   recpy_gap_type.tp_getset = recpy_gap_getset;
 
   if (PyType_Ready (&recpy_record_type) < 0
+      || PyType_Ready (&recpy_insn_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 5cf7a02..ae2d2d2 100644
--- a/gdb/python/py-record.h
+++ b/gdb/python/py-record.h
@@ -25,7 +25,6 @@
 #include "record.h"
 
 /* Python Record object.  */
-
 typedef struct
 {
   PyObject_HEAD
@@ -37,6 +36,30 @@ typedef struct
   enum record_method method;
 } recpy_record_object;
 
+/* Python recorded element object.  This is generic enough to represent
+   recorded instructions as well as recorded function call segments, hence the
+   generic name.  */
+typedef struct
+{
+  PyObject_HEAD
+
+  /* The ptid this object refers to.  */
+  ptid_t ptid;
+
+  /* The current recording method.  */
+  enum record_method method;
+
+  /* Element number.  */
+  Py_ssize_t number;
+} recpy_element_object;
+
+/* Python RecordInstruction type.  */
+extern PyTypeObject recpy_insn_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.RecordGap object.  */
 extern PyObject *recpy_gap_new (int reason_code, const char *reason_string,
 				Py_ssize_t number);
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
                   ` (3 preceding siblings ...)
  2017-04-21 10:50 ` [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 18:08   ` Yao Qi
  2017-04-27 16:35   ` Pedro Alves
  2017-04-21 10:50 ` [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction Tim Wiederhake
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

GDB_PY_HANDLE_EXCEPTION does not handle all exceptions.  Replace with call to
gdbpy_convert_exception.

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	python/py-record-btrace.c (btpy_insn_sal, btpy_insn_data,
	btpy_insn_decode, recpy_bt_goto): Handle all exceptions.

---
 gdb/python/py-record-btrace.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 0f8d7ef..9d79e2b 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -227,7 +227,7 @@ btpy_insn_sal (PyObject *self, void *closure)
     }
   CATCH (except, RETURN_MASK_ALL)
     {
-      GDB_PY_HANDLE_EXCEPTION (except);
+      gdbpy_convert_exception (except);
     }
   END_CATCH
 
@@ -320,10 +320,14 @@ btpy_insn_data (PyObject *self, void *closure)
   CATCH (except, RETURN_MASK_ALL)
     {
       xfree (buffer);
-      GDB_PY_HANDLE_EXCEPTION (except);
+      buffer = NULL;
+      gdbpy_convert_exception (except);
     }
   END_CATCH
 
+  if (buffer == NULL)
+    return NULL;
+
   object = PyBytes_FromStringAndSize ((const char*) buffer, insn->size);
   xfree (buffer);
 
@@ -348,6 +352,7 @@ btpy_insn_decode (PyObject *self, void *closure)
   const struct btrace_insn *insn;
   struct btrace_insn_iterator iter;
   string_file strfile;
+  int length = 0;
 
   BTPY_REQUIRE_VALID_INSN (obj, iter);
 
@@ -364,15 +369,16 @@ btpy_insn_decode (PyObject *self, void *closure)
 
   TRY
     {
-      gdb_print_insn (target_gdbarch (), insn->pc, &strfile, NULL);
+      length = gdb_print_insn (target_gdbarch (), insn->pc, &strfile, NULL);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
       gdbpy_convert_exception (except);
-      return NULL;
     }
   END_CATCH
 
+  if (length == 0)
+    return NULL;
 
   return PyBytes_FromString (strfile.string ().c_str ());
 }
@@ -871,6 +877,7 @@ recpy_bt_goto (PyObject *self, PyObject *args)
 {
   struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
   const btpy_object *obj;
+  PyObject *ret = NULL;
 
   if (tinfo == NULL || btrace_is_empty (tinfo))
 	return PyErr_Format (gdbpy_gdb_error, _("Empty branch trace."));
@@ -891,14 +898,17 @@ recpy_bt_goto (PyObject *self, PyObject *args)
 	target_goto_record_end ();
       else
 	target_goto_record (obj->number);
+
+      Py_INCREF (Py_None);
+      ret = Py_None;
     }
   CATCH (except, RETURN_MASK_ALL)
     {
-      GDB_PY_HANDLE_EXCEPTION (except);
+      gdbpy_convert_exception (except);
     }
   END_CATCH
 
-  Py_RETURN_NONE;
+  return ret;
 }
 
 /* BtraceInstruction members.  */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 5/8] Python: Introduce gdb.RecordGap class
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
                   ` (6 preceding siblings ...)
  2017-04-21 10:50 ` [PATCH v2 3/8] Python: Use correct ptid in btrace recording Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 12:25   ` Eli Zaretskii
  2017-04-21 14:50   ` Yao Qi
  7 siblings, 2 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

As discussed here: https://sourceware.org/ml/gdb-patches/2017-04/msg00157.html

A gap is not an instruction and it should not pretend to be one.

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	* py-record-btrace.c (btpy_insn_new): Removed.
	(btpy_insn_or_gap_new): New function.
	(btpy_insn_error): Removed.
	(btpy_insn_sal, btpy_insn_pc, btpy_insn_size, btpy_insn_is_speculative,
	btpy_insn_data, btpy_insn_decode): Remove code path for gaps.
	(recpy_bt_replay_position, recpy_bt_begin, recpy_bt_end): Call
	btpy_insn_or_gap_new instead of btpy_insn_new.
	(btpy_insn_getset): Remove btpy_insn_error.
	* py-record.c (recpy_gap_type): New static object.
	(recpy_gap_object): New typedef.
	(recpy_gap_new, recpy_gap_number, recpy_gap_reason_code,
	recpy_gap_reason_string): New function.
	(recpy_gap_getset): New static object.
	(gdbpy_initialize_record): Initialize gdb.RecordGap type.
	* py-record.h (recpy_gap_new): New export.

gdb/doc/ChangeLog:
	* python.texi (Recording in Python): Add documentation for
	gdb.RecordGap and remove documentation of special cases for
	gdb.BtraceInstruction.

gdb/testsuite/ChangeLog:
	* gdb.python/py-record-btrace.exp: Remove test for
	gdb.BtraceInstruction.error.

---
 gdb/doc/python.texi                           | 47 ++++++++------
 gdb/python/py-record-btrace.c                 | 72 +++++++++------------
 gdb/python/py-record.c                        | 91 ++++++++++++++++++++++++++-
 gdb/python/py-record.h                        |  4 ++
 gdb/testsuite/gdb.python/py-record-btrace.exp |  1 -
 5 files changed, 153 insertions(+), 62 deletions(-)

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 8c246a4..67b02ed 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3160,41 +3160,50 @@ the numbers seen in @code{record instruction-history}
 (@pxref{Process Record and Replay}).
 @end defvar
 
-@defvar BtraceInstruction.error
-An integer identifying the error code for gaps in the history.
-@code{None} for regular instructions.
-@end defvar
-
 @defvar BtraceInstruction.sal
 A @code{gdb.Symtab_and_line} object representing the associated symtab
-and line of this instruction.  May be @code{None} if the instruction
-is a gap.
+and line of this instruction.  May be @code{None} if no debug information is
+available.
 @end defvar
 
 @defvar BtraceInstruction.pc
-An integer representing this instruction's address.  May be @code{None}
-if the instruction is a gap or the debug symbols could not be read.
+An integer representing this instruction's address.
 @end defvar
 
 @defvar BtraceInstruction.data
-A buffer with the raw instruction data.  May be @code{None} if the
-instruction is a gap.  In Python 3, the return value is a @code{memoryview}
-object.
+A buffer with the raw instruction data.  In Python 3, the return value is a
+@code{memoryview} object.
 @end defvar
 
 @defvar BtraceInstruction.decoded
-A human readable string with the disassembled instruction.  Contains the
-error message for gaps.
+A human readable string with the disassembled instruction.
 @end defvar
 
 @defvar BtraceInstruction.size
-The size of the instruction in bytes.  Will be @code{None} if the
-instruction is a gap.
+The size of the instruction in bytes.
 @end defvar
 
 @defvar BtraceInstruction.is_speculative
 A boolean indicating whether the instruction was executed
-speculatively.  Will be @code{None} for gaps.
+speculatively.
+@end defvar
+
+If an error occured during recording or decoding a recording, this error is
+represented by a @code{gdb.RecordGap} object in the instruction list.  It has
+the following attributes:
+
+@defvar RecordGap.number
+An integer identifying this gap.  @var{number} corresponds to the numbers seen
+in @code{record instruction-history} (@pxref{Process Record and Replay}).
+@end defvar
+
+@defvar RecordGap.error_code
+A numerical representation of the reason for the gap.  The value is specific to
+the current recording method.
+@end defvar
+
+@defvar RecordGap.error_string
+A human readable string with the reason for the gap.
 @end defvar
 
 The attributes and methods of function call objects depend on the
@@ -3221,8 +3230,8 @@ An integer representing the function call's stack level.  May be
 @end defvar
 
 @defvar BtraceFunctionCall.instructions
-A list of @code{gdb.BtraceInstruction} objects associated with this function
-call.
+A list of @code{gdb.BtraceInstruction} or @code{gdb.RecordGap} objects
+associated with this function call.
 @end defvar
 
 @defvar BtraceFunctionCall.up
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index 018b3d8..89a57e5 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -126,12 +126,30 @@ btpy_new (ptid_t ptid, Py_ssize_t number, PyTypeObject* type)
   return (PyObject *) obj;
 }
 
-/* Create a new gdb.BtraceInstruction object.  */
+/* Looks at the recorded item with the number NUMBER and create a
+   gdb.BtraceInstruction or gdb.RecordGap object for it accordingly.  */
 
 static PyObject *
-btpy_insn_new (ptid_t ptid, Py_ssize_t number)
+btpy_insn_or_gap_new (const thread_info *tinfo, Py_ssize_t number)
 {
-  return btpy_new (ptid, number, &btpy_insn_type);
+  btrace_insn_iterator iter;
+  int err_code;
+
+  btrace_find_insn_by_number (&iter, &tinfo->btrace, number);
+  err_code = btrace_insn_get_error (&iter);
+
+  if (err_code != 0)
+    {
+      const btrace_config *config;
+      const char *err_string;
+
+      config = btrace_conf (&tinfo->btrace);
+      err_string = btrace_decode_error (config->format, err_code);
+
+      return recpy_gap_new (err_code, err_string, number);
+    }
+
+  return btpy_new (tinfo->ptid, number, &btpy_insn_type);
 }
 
 /* Create a new gdb.BtraceFunctionCall object.  */
@@ -185,26 +203,6 @@ btpy_hash (PyObject *self)
   return obj->number;
 }
 
-/* Implementation of BtraceInstruction.error [int].  Returns the
-   error code for gaps.  */
-
-static PyObject *
-btpy_insn_error (PyObject *self, void *closure)
-{
-  const btpy_object * const obj = (btpy_object *) self;
-  struct btrace_insn_iterator iter;
-  int error;
-
-  BTPY_REQUIRE_VALID_INSN (obj, iter);
-
-  error = btrace_insn_get_error (&iter);
-
-  if (error == 0)
-    Py_RETURN_NONE;
-
-  return PyInt_FromLong (error);
-}
-
 /* Implementation of BtraceInstruction.sal [gdb.Symtab_and_line].
    Return the SAL associated with this instruction.  */
 
@@ -220,7 +218,7 @@ btpy_insn_sal (PyObject *self, void *closure)
 
   insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    Py_RETURN_NONE;
+    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
 
   TRY
     {
@@ -249,7 +247,7 @@ btpy_insn_pc (PyObject *self, void *closure)
 
   insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    Py_RETURN_NONE;
+    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
 
   return gdb_py_long_from_ulongest (insn->pc);
 }
@@ -268,7 +266,7 @@ btpy_insn_size (PyObject *self, void *closure)
 
   insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    Py_RETURN_NONE;
+    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
 
   return PyInt_FromLong (insn->size);
 }
@@ -287,7 +285,7 @@ btpy_insn_is_speculative (PyObject *self, void *closure)
 
   insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    Py_RETURN_NONE;
+    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
 
   if (insn->flags & BTRACE_INSN_FLAG_SPECULATIVE)
     Py_RETURN_TRUE;
@@ -311,7 +309,7 @@ btpy_insn_data (PyObject *self, void *closure)
 
   insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    Py_RETURN_NONE;
+    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
 
   TRY
     {
@@ -359,14 +357,7 @@ btpy_insn_decode (PyObject *self, void *closure)
 
   insn = btrace_insn_get (&iter);
   if (insn == NULL)
-    {
-      int error_code = btrace_insn_get_error (&iter);
-      const struct btrace_config *config;
-
-      config = btrace_conf (&find_thread_ptid (obj->ptid)->btrace);
-      return PyBytes_FromString (btrace_decode_error (config->format,
-						      error_code));
-    }
+    return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
 
   TRY
     {
@@ -771,8 +762,8 @@ recpy_bt_replay_position (PyObject *self, void *closure)
   if (tinfo->btrace.replay == NULL)
     Py_RETURN_NONE;
 
-  return btpy_insn_new (record->ptid,
-			btrace_insn_number (tinfo->btrace.replay));
+  return btpy_insn_or_gap_new (tinfo,
+			       btrace_insn_number (tinfo->btrace.replay));
 }
 
 /* Implementation of
@@ -794,7 +785,7 @@ recpy_bt_begin (PyObject *self, void *closure)
     Py_RETURN_NONE;
 
   btrace_insn_begin (&iterator, &tinfo->btrace);
-  return btpy_insn_new (record->ptid, btrace_insn_number (&iterator));
+  return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator));
 }
 
 /* Implementation of
@@ -816,7 +807,7 @@ recpy_bt_end (PyObject *self, void *closure)
     Py_RETURN_NONE;
 
   btrace_insn_end (&iterator, &tinfo->btrace);
-  return btpy_insn_new (record->ptid, btrace_insn_number (&iterator));
+  return btpy_insn_or_gap_new (tinfo, btrace_insn_number (&iterator));
 }
 
 /* Implementation of
@@ -924,7 +915,6 @@ recpy_bt_goto (PyObject *self, PyObject *args)
 struct PyGetSetDef btpy_insn_getset[] =
 {
   { "number", btpy_number, NULL, "instruction number", NULL},
-  { "error", btpy_insn_error, NULL, "error number for gaps", NULL},
   { "sal", btpy_insn_sal, NULL, "associated symbol and line", NULL},
   { "pc", btpy_insn_pc, NULL, "instruction address", NULL},
   { "data", btpy_insn_data, NULL, "raw instruction data", NULL},
diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c
index bef0784..8420bc0 100644
--- a/gdb/python/py-record.c
+++ b/gdb/python/py-record.c
@@ -29,6 +29,27 @@ static PyTypeObject recpy_record_type = {
   PyVarObject_HEAD_INIT (NULL, 0)
 };
 
+/* Python RecordGap type.  */
+
+PyTypeObject recpy_gap_type = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+};
+
+/* Python RecordGap object.  */
+typedef struct
+{
+  PyObject_HEAD
+
+  /* Reason code.  */
+  int reason_code;
+
+  /* Reason message.  */
+  const char *reason_string;
+
+  /* Element number.  */
+  Py_ssize_t number;
+} recpy_gap_object;
+
 /* Implementation of record.method.  */
 
 static PyObject *
@@ -139,6 +160,54 @@ recpy_end (PyObject *self, void* closure)
   return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
 }
 
+/* Create a new gdb.RecordGap object.  */
+
+PyObject *
+recpy_gap_new (int reason_code, const char *reason_string, Py_ssize_t number)
+{
+  recpy_gap_object * const obj = PyObject_New (recpy_gap_object,
+					       &recpy_gap_type);
+
+  if (obj == NULL)
+   return NULL;
+
+  obj->reason_code = reason_code;
+  obj->reason_string = reason_string;
+  obj->number = number;
+
+  return (PyObject *) obj;
+}
+
+/* Implementation of RecordGap.number [int].  */
+
+static PyObject *
+recpy_gap_number (PyObject *self, void *closure)
+{
+  const recpy_gap_object * const obj = (const recpy_gap_object *) self;
+
+  return PyInt_FromSsize_t (obj->number);
+}
+
+/* Implementation of RecordGap.error_code [int].  */
+
+static PyObject *
+recpy_gap_reason_code (PyObject *self, void *closure)
+{
+  const recpy_gap_object * const obj = (const recpy_gap_object *) self;
+
+  return PyInt_FromLong (obj->reason_code);
+}
+
+/* Implementation of RecordGap.error_string [str].  */
+
+static PyObject *
+recpy_gap_reason_string (PyObject *self, void *closure)
+{
+  const recpy_gap_object * const obj = (const recpy_gap_object *) self;
+
+  return PyString_FromString (obj->reason_string);
+}
+
 /* Record method list.  */
 
 static PyMethodDef recpy_record_methods[] = {
@@ -167,6 +236,15 @@ the current instruction and is used for e.g. record.goto (record.end).", NULL },
   { NULL }
 };
 
+/* RecordGap member list.  */
+
+static PyGetSetDef recpy_gap_getset[] = {
+  { "number", recpy_gap_number, NULL, "element number", NULL},
+  { "reason_code", recpy_gap_reason_code, NULL, "reason code", NULL},
+  { "reason_string", recpy_gap_reason_string, NULL, "reason string", NULL},
+  { NULL }
+};
+
 /* Sets up the record API in the gdb module.  */
 
 int
@@ -180,7 +258,18 @@ gdbpy_initialize_record (void)
   recpy_record_type.tp_methods = recpy_record_methods;
   recpy_record_type.tp_getset = recpy_record_getset;
 
-  return PyType_Ready (&recpy_record_type);
+  recpy_gap_type.tp_new = PyType_GenericNew;
+  recpy_gap_type.tp_flags = Py_TPFLAGS_DEFAULT;
+  recpy_gap_type.tp_basicsize = sizeof (recpy_gap_object);
+  recpy_gap_type.tp_name = "gdb.RecordGap";
+  recpy_gap_type.tp_doc = "GDB recorded gap object";
+  recpy_gap_type.tp_getset = recpy_gap_getset;
+
+  if (PyType_Ready (&recpy_record_type) < 0
+      || PyType_Ready (&recpy_gap_type) < 0)
+    return -1;
+  else
+    return 0;
 }
 
 /* Implementation of gdb.start_recording (method) -> gdb.Record.  */
diff --git a/gdb/python/py-record.h b/gdb/python/py-record.h
index c386ba2..5cf7a02 100644
--- a/gdb/python/py-record.h
+++ b/gdb/python/py-record.h
@@ -37,4 +37,8 @@ typedef struct
   enum record_method method;
 } recpy_record_object;
 
+/* Create a new gdb.RecordGap object.  */
+extern PyObject *recpy_gap_new (int reason_code, const char *reason_string,
+				Py_ssize_t number);
+
 #endif /* GDB_PY_RECORD_H */
diff --git a/gdb/testsuite/gdb.python/py-record-btrace.exp b/gdb/testsuite/gdb.python/py-record-btrace.exp
index ecc8bdf..045e63e 100644
--- a/gdb/testsuite/gdb.python/py-record-btrace.exp
+++ b/gdb/testsuite/gdb.python/py-record-btrace.exp
@@ -81,7 +81,6 @@ with_test_prefix "replay end" {
 
 with_test_prefix "instruction " {
     gdb_test "python print(i.number)" "1"
-    gdb_test "python print(i.error)" "None"
     gdb_test "python print(i.sal)" "symbol and line for .*"
     gdb_test "python print(i.pc)" "$decimal"
     if { $gdb_py_is_py3k == 0 } {
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
                   ` (4 preceding siblings ...)
  2017-04-21 10:50 ` [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 12:22   ` Eli Zaretskii
  2017-04-21 16:41   ` Yao Qi
  2017-04-21 10:50 ` [PATCH v2 3/8] Python: Use correct ptid in btrace recording Tim Wiederhake
  2017-04-21 10:50 ` [PATCH v2 5/8] Python: Introduce gdb.RecordGap class Tim Wiederhake
  7 siblings, 2 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

Remove gdb.BtraceFunctionCall and replace by gdb.FunctionSegment.  Additionally,
rename prev_segment and next_segment to prev and next.

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	* python/py-record-btrace.c (BTPY_REQUIRE_VALID_CALL, btpy_call_type):
	Remove.
	(btrace_func_from_recpy_func): New function.
	(btpy_call_new, btpy_number, btpy_hash, btpy_richcompare): Remove.
	(btpy_call_level, btpy_call_symbol, btpy_call_instructions,
	btpy_call_up, btpy_call_prev_sibling, btpy_call_next_sibling): Rename to ...
	(recpy_bt_func_level, recpy_bt_func_symbol, recpy_bt_func_instructions,
	recpy_bt_func_up, recpy_bt_func_prev, recpy_bt_func_next): This.
	Also, use new helper functions.
	(btpy_list_item): Use new helper functions.
	(recpy_bt_function_call_history): Use new type name.
	(btpy_call_getset): Remove.
	(gdbpy_initialize_btrace): Remove code to initialize
	gdb.BtraceFunctionCall.
	* python/py-record-btrace.h (recpy_bt_func_number, recpy_btb_func_level,
	recpy_btb_func_symbol, recpy_bt_func_instructions, recpy_bt_func_up,
	recpy_bt_func_prev, recpy_bt_func_next): New export.
	* python/py-record.c (recpy_func_type): New static object.
	(recpy_func_new, recpy_func_level, recpy_func_symbol,
	recpy_func_instructions, recpy_func_up, recpy_func_prev,
	recpy_func_next): New function.
	(recpy_element_hash, recpy_element_richcompare): Updated comment.
	(recpy_func_getset): New static object.
	(gdbpy_initialize_record): Add code to initialize gdb.RecordInstruction.
	* python/py-record.h (recpy_func_type, recpy_func_new): New export.

gdb/doc/ChangeLog:
	* python.texi (Recording in Python): Replace gdb.BtraceFunction with
	gdb.RecordFunctionSegment.  Rename prev_sibling and next_sibling to
	prev and next.

gdb/testsuite/ChangeLog:
	* gdb.python/py-record-btrace.exp: Rename prev_sibling and next_sibling
	to prev and next.

---
 gdb/doc/python.texi                           |  31 ++-
 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 +
 gdb/testsuite/gdb.python/py-record-btrace.exp |   4 +-
 6 files changed, 270 insertions(+), 221 deletions(-)

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 10a3ab5..1231521 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3203,48 +3203,43 @@ the current recording method.
 A human readable string with the reason for the gap.
 @end defvar
 
-The attributes and methods of function call objects depend on the
-current recording format.  Currently, only btrace function calls are
-supported.
+A @code{gdb.RecordFunctionSegment} object has the following attributes:
 
-A @code{gdb.BtraceFunctionCall} object has the following attributes:
-
-@defvar BtraceFunctionCall.number
-An integer identifying this function call.  @var{number} corresponds to
+@defvar RecordFunctionSegment.number
+An integer identifying this function segment.  @var{number} corresponds to
 the numbers seen in @code{record function-call-history}
 (@pxref{Process Record and Replay}).
 @end defvar
 
-@defvar BtraceFunctionCall.symbol
+@defvar RecordFunctionSegment.symbol
 A @code{gdb.Symbol} object representing the associated symbol.  May be
-@code{None} if the function call is a gap or the debug symbols could
-not be read.
+@code{None} if no debug information is available.
 @end defvar
 
-@defvar BtraceFunctionCall.level
+@defvar RecordFunctionSegment.level
 An integer representing the function call's stack level.  May be
 @code{None} if the function call is a gap.
 @end defvar
 
-@defvar BtraceFunctionCall.instructions
+@defvar RecordFunctionSegment.instructions
 A list of @code{gdb.RecordInstruction} or @code{gdb.RecordGap} objects
 associated with this function call.
 @end defvar
 
-@defvar BtraceFunctionCall.up
-A @code{gdb.BtraceFunctionCall} object representing the caller's
+@defvar RecordFunctionSegment.up
+A @code{gdb.RecordFunctionSegment} object representing the caller's
 function segment.  If the call has not been recorded, this will be the
 function segment to which control returns.  If neither the call nor the
 return have been recorded, this will be @code{None}.
 @end defvar
 
-@defvar BtraceFunctionCall.prev_sibling
-A @code{gdb.BtraceFunctionCall} object representing the previous
+@defvar RecordFunctionSegment.prev
+A @code{gdb.RecordFunctionSegment} object representing the previous
 segment of this function call.  May be @code{None}.
 @end defvar
 
-@defvar BtraceFunctionCall.next_sibling
-A @code{gdb.BtraceFunctionCall} object representing the next segment of
+@defvar RecordFunctionSegment.next
+A @code{gdb.RecordFunctionSegment} object representing the next segment of
 this function call.  May be @code{None}.
 @end defvar
 
diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index b0b4605..674a3aa 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.  */
 
@@ -350,40 +337,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;
@@ -391,22 +370,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);
 
@@ -414,111 +388,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.  */
@@ -556,7 +482,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.  */
@@ -845,7 +771,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.  */
@@ -890,23 +816,6 @@ recpy_bt_goto (PyObject *self, PyObject *args)
   return ret;
 }
 
-/* BtraceFunctionCall members.  */
-
-static 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[] =
@@ -935,15 +844,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);
@@ -960,9 +860,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 d186e18..bd74e43 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 PyGetSetDef recpy_insn_getset[] = {
   { NULL }
 };
 
+/* RecordFunctionSegment member list.  */
+
+static 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 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);
diff --git a/gdb/testsuite/gdb.python/py-record-btrace.exp b/gdb/testsuite/gdb.python/py-record-btrace.exp
index 045e63e..cda822d 100644
--- a/gdb/testsuite/gdb.python/py-record-btrace.exp
+++ b/gdb/testsuite/gdb.python/py-record-btrace.exp
@@ -99,8 +99,8 @@ with_test_prefix "function call" {
     gdb_test "python print(c.level)" "$decimal"
     gdb_test "python print(len(c.instructions))" "$decimal"
     gdb_test "python print(c.up)" "None"
-    gdb_test "python print(c.prev_sibling)" "None"
-    gdb_test "python print(c == c.next_sibling.prev_sibling)" "True"
+    gdb_test "python print(c.prev)" "None"
+    gdb_test "python print(c == c.next.prev)" "True"
 }
 
 with_test_prefix "list" {
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 8/8] Python: Introduce gdb.Instruction class
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
  2017-04-21 10:50 ` [PATCH v2 1/8] Python: Fix indentation in py-record-btrace.c Tim Wiederhake
  2017-04-21 10:50 ` [PATCH v2 4/8] Python: Remove ptid from gdb.Record interface Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 12:19   ` Eli Zaretskii
  2017-04-21 18:10   ` Yao Qi
  2017-04-21 10:50 ` [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction Tim Wiederhake
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

This adds a generic instruction class to Python and has gdb.RecordInstruction
inherit from it.

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:

	* Makefile.in (SUBDIR_PYTHON_OBS): Add py-instruction.o.
	(SUBDIR_PYTHON_SRCS): Add py-instruction.c.
	* python/py-instruction.c, python/py-instruction.h: New file.
	* python/py-record.c: Add py-instruction.h include.
	(gdbpy_initialize_record): Make gdb.Instruction a super class of
	gdb.RecordInstruction.
	* python/python-internal.h: Add gdbpy_initialize_instruction
	declaration.
	* python/python.c (do_start_initialization): Add
	gdbpy_initialize_instruction.

gdb/doc/ChangeLog:
	* python.texi (Recording in Python): Factor out the documentation of
	gdb.RecordInstruction's super class.


---
 gdb/Makefile.in              |  2 ++
 gdb/doc/python.texi          | 40 +++++++++++++-------------
 gdb/python/py-instruction.c  | 67 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/python/py-instruction.h  | 30 ++++++++++++++++++++
 gdb/python/py-record.c       |  2 ++
 gdb/python/python-internal.h |  2 ++
 gdb/python/python.c          |  1 +
 7 files changed, 125 insertions(+), 19 deletions(-)
 create mode 100644 gdb/python/py-instruction.c
 create mode 100644 gdb/python/py-instruction.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 479d273..7af63a8 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -453,6 +453,7 @@ SUBDIR_PYTHON_OBS = \
 	py-inferior.o \
 	py-infevents.o \
 	py-infthread.o \
+	py-instruction.o \
 	py-lazy-string.o \
 	py-linetable.o \
 	py-newobjfileevent.o \
@@ -496,6 +497,7 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-inferior.c \
 	python/py-infevents.c \
 	python/py-infthread.c \
+	python/py-instruction.c \
 	python/py-lazy-string.c \
 	python/py-linetable.c \
 	python/py-newobjfileevent.c \
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 1231521..d4f93ce 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3149,40 +3149,42 @@ A @code{gdb.Record} object has the following methods:
 Move the replay position to the given @var{instruction}.
 @end defun
 
-A @code{gdb.RecordInstruction} object has the following attributes:
+The common @code{gdb.Instruction} class that recording method specific
+instruction objects inherit from, has the following attributes:
 
-@defvar RecordInstruction.number
-An integer identifying this instruction.  @var{number} corresponds to
-the numbers seen in @code{record instruction-history}
-(@pxref{Process Record and Replay}).
-@end defvar
-
-@defvar RecordInstruction.sal
-A @code{gdb.Symtab_and_line} object representing the associated symtab
-and line of this instruction.  May be @code{None} if no debug information is
-available.
-@end defvar
-
-@defvar RecordInstruction.pc
+@defvar Instruction.pc
 An integer representing this instruction's address.
 @end defvar
 
-@defvar RecordInstruction.data
+@defvar Instruction.data
 A buffer with the raw instruction data.  In Python 3, the return value is a
 @code{memoryview} object.
 @end defvar
 
-@defvar RecordInstruction.decoded
+@defvar Instruction.decoded
 A human readable string with the disassembled instruction.
 @end defvar
 
-@defvar RecordInstruction.size
+@defvar Instruction.size
 The size of the instruction in bytes.
 @end defvar
 
+Additionally @code{gdb.RecordInstruction} has the following attributes:
+
+@defvar RecordInstruction.number
+An integer identifying this instruction.  @var{number} corresponds to
+the numbers seen in @code{record instruction-history}
+(@pxref{Process Record and Replay}).
+@end defvar
+
+@defvar RecordInstruction.sal
+A @code{gdb.Symtab_and_line} object representing the associated symtab
+and line of this instruction.  May be @code{None} if no debug information is
+available.
+@end defvar
+
 @defvar RecordInstruction.is_speculative
-A boolean indicating whether the instruction was executed
-speculatively.
+A boolean indicating whether the instruction was executed speculatively.
 @end defvar
 
 If an error occured during recording or decoding a recording, this error is
diff --git a/gdb/python/py-instruction.c b/gdb/python/py-instruction.c
new file mode 100644
index 0000000..da0a3c5
--- /dev/null
+++ b/gdb/python/py-instruction.c
@@ -0,0 +1,67 @@
+/* Python interface to instruction objects.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "py-instruction.h"
+
+/* See py-instruction.h.  */
+
+PyTypeObject py_insn_type = {
+  PyVarObject_HEAD_INIT (NULL, 0)
+};
+
+/* Python instruction object.  */
+
+typedef struct {
+  PyObject_HEAD
+} py_insn_obj;
+
+/* Getter function for gdb.Instruction attributes.  */
+
+static PyObject *
+py_insn_getter (PyObject *self, void *closure)
+{
+  return PyErr_Format (PyExc_NotImplementedError, _("Not implemented."));
+}
+
+/* Instruction members.  */
+
+static PyGetSetDef py_insn_getset[] =
+{
+  { "pc", py_insn_getter, NULL, "instruction address", NULL},
+  { "data", py_insn_getter, NULL, "instruction memory", NULL},
+  { "decoded", py_insn_getter, NULL, "decoded instruction", NULL},
+  { "size", py_insn_getter, NULL, "instruction size in bytes", NULL},
+  {NULL}
+};
+
+/* Sets up the gdb.Instruction type.  */
+
+int
+gdbpy_initialize_instruction (void)
+{
+  py_insn_type.tp_new = PyType_GenericNew;
+  py_insn_type.tp_flags = Py_TPFLAGS_DEFAULT;
+  py_insn_type.tp_basicsize = sizeof (py_insn_obj);
+  py_insn_type.tp_name = "gdb.Instruction";
+  py_insn_type.tp_doc = "GDB instruction object";
+  py_insn_type.tp_getset = py_insn_getset;
+
+  return PyType_Ready (&py_insn_type);
+}
diff --git a/gdb/python/py-instruction.h b/gdb/python/py-instruction.h
new file mode 100644
index 0000000..b855fb5
--- /dev/null
+++ b/gdb/python/py-instruction.h
@@ -0,0 +1,30 @@
+/* Python interface to instruction objects.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_PY_INSTRUCTION_H
+#define GDB_PY_INSTRUCTION_H
+
+#include "python-internal.h"
+
+/* Python type object for the abstract gdb.Instruction class.  This class
+   contains getters for four elements: "pc" (int), "data" (buffer), "decode"
+   (str) and "size" (int) that must be overriden by sub classes.  */
+extern PyTypeObject py_insn_type;
+
+#endif /* GDB_PY_INSTRUCTION_H */
diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c
index bd74e43..c83a3e8 100644
--- a/gdb/python/py-record.c
+++ b/gdb/python/py-record.c
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "py-instruction.h"
 #include "py-record.h"
 #include "py-record-btrace.h"
 #include "py-record-full.h"
@@ -561,6 +562,7 @@ gdbpy_initialize_record (void)
   recpy_insn_type.tp_getset = recpy_insn_getset;
   recpy_insn_type.tp_richcompare = recpy_element_richcompare;
   recpy_insn_type.tp_hash = recpy_element_hash;
+  recpy_insn_type.tp_base = &py_insn_type;
 
   recpy_func_type.tp_new = PyType_GenericNew;
   recpy_func_type.tp_flags = Py_TPFLAGS_DEFAULT;
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 4dd413d..376d70c 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -441,6 +441,8 @@ int gdbpy_initialize_values (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_frames (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_instruction (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_btrace (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_record (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index a7aff53..1de7c3d 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1633,6 +1633,7 @@ do_start_initialization ()
       || gdbpy_initialize_values () < 0
       || gdbpy_initialize_frames () < 0
       || gdbpy_initialize_commands () < 0
+      || gdbpy_initialize_instruction () < 0
       || gdbpy_initialize_record () < 0
       || gdbpy_initialize_btrace () < 0
       || gdbpy_initialize_symbols () < 0
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 1/8] Python: Fix indentation in py-record-btrace.c
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 10:50 ` [PATCH v2 4/8] Python: Remove ptid from gdb.Record interface Tim Wiederhake
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	* python/py-record-btrace.c (BTPY_REQUIRE_VALID_INSN,
	BTPY_REQUIRE_VALID_CALL, recpy_bt_function_call_history): Fix
	indentation.

---
 gdb/python/py-record-btrace.c | 60 +++++++++++++++++++++----------------------
 1 file changed, 30 insertions(+), 30 deletions(-)

diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c
index c816332..0f8d7ef 100644
--- a/gdb/python/py-record-btrace.c
+++ b/gdb/python/py-record-btrace.c
@@ -36,24 +36,24 @@
 #endif
 
 #define BTPY_REQUIRE_VALID_INSN(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_insn_by_number (&iter, &tinfo->btrace,	\
-					   obj->number))		\
-	return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));\
-    } while (0)
+  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_insn_by_number (&iter, &tinfo->btrace,		\
+					 obj->number))			\
+      return PyErr_Format (gdbpy_gdb_error, _("No such instruction."));	\
+  } while (0)
 
 #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)
+  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)
 
 /* This can either be a btrace instruction or a function call segment,
    depending on the chosen type.  */
@@ -842,26 +842,26 @@ recpy_bt_instruction_history (PyObject *self, void *closure)
 PyObject *
 recpy_bt_function_call_history (PyObject *self, void *closure)
 {
-    struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
-    struct btrace_call_iterator iterator;
-    unsigned long first = 0;
-    unsigned long last = 0;
+  struct thread_info * const tinfo = find_thread_ptid (inferior_ptid);
+  struct btrace_call_iterator iterator;
+  unsigned long first = 0;
+  unsigned long last = 0;
 
-    if (tinfo == NULL)
-      Py_RETURN_NONE;
+  if (tinfo == NULL)
+    Py_RETURN_NONE;
 
-    btrace_fetch (tinfo);
+  btrace_fetch (tinfo);
 
-    if (btrace_is_empty (tinfo))
-      Py_RETURN_NONE;
+  if (btrace_is_empty (tinfo))
+    Py_RETURN_NONE;
 
-    btrace_call_begin (&iterator, &tinfo->btrace);
-    first = btrace_call_number (&iterator);
+  btrace_call_begin (&iterator, &tinfo->btrace);
+  first = btrace_call_number (&iterator);
 
-    btrace_call_end (&iterator, &tinfo->btrace);
-    last = btrace_call_number (&iterator);
+  btrace_call_end (&iterator, &tinfo->btrace);
+  last = btrace_call_number (&iterator);
 
-    return btpy_list_new (inferior_ptid, first, last, 1, &btpy_call_type);
+  return btpy_list_new (inferior_ptid, first, last, 1, &btpy_call_type);
 }
 
 /* Implementation of BtraceRecord.goto (self, BtraceInstruction) -> None.  */
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 4/8] Python: Remove ptid from gdb.Record interface
  2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
  2017-04-21 10:50 ` [PATCH v2 1/8] Python: Fix indentation in py-record-btrace.c Tim Wiederhake
@ 2017-04-21 10:50 ` Tim Wiederhake
  2017-04-21 12:20   ` Eli Zaretskii
  2017-04-21 10:50 ` [PATCH v2 8/8] Python: Introduce gdb.Instruction class Tim Wiederhake
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 22+ messages in thread
From: Tim Wiederhake @ 2017-04-21 10:50 UTC (permalink / raw)
  To: gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

As discussed here: https://sourceware.org/ml/gdb-patches/2017-04/msg00166.html

2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>

gdb/ChangeLog:
	* python/py-record.c (recpy_ptid): Remove.
	(recpy_record_getset): Remove recpy_ptid.

gdb/doc/ChangeLog:
	* python.texi (Recording in Python): Remove Record.ptid defvar.

gdb/testsuite/ChangeLog:
	* gdb.python/py-record-btrace.exp: Remove Record.ptid test.

---
 gdb/doc/python.texi                           |  7 -------
 gdb/python/py-record.c                        | 11 -----------
 gdb/testsuite/gdb.python/py-record-btrace.exp |  1 -
 3 files changed, 19 deletions(-)

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index ce5810e..8c246a4 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3110,13 +3110,6 @@ currently active.  All record objects become invalid after this call.
 
 A @code{gdb.Record} object has the following attributes:
 
-@defvar Record.ptid
-ID of the thread associated with this object as a tuple of three integers.  The
-first is the Process ID (PID); the second is the Lightweight Process ID (LWPID),
-and the third is the Thread ID (TID). Either the LWPID or TID may be 0, which
-indicates that the operating system does not use that identifier.
-@end defvar
-
 @defvar Record.method
 A string with the current recording method, e.g.@: @code{full} or
 @code{btrace}.
diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c
index 586687a..bef0784 100644
--- a/gdb/python/py-record.c
+++ b/gdb/python/py-record.c
@@ -29,16 +29,6 @@ static PyTypeObject recpy_record_type = {
   PyVarObject_HEAD_INIT (NULL, 0)
 };
 
-/* Implementation of record.ptid.  */
-
-static PyObject *
-recpy_ptid (PyObject *self, void* closure)
-{
-  const recpy_record_object * const obj = (recpy_record_object *) self;
-
-  return gdbpy_create_ptid_object (obj->ptid);
-}
-
 /* Implementation of record.method.  */
 
 static PyObject *
@@ -161,7 +151,6 @@ Rewind to given location."},
 /* Record member list.  */
 
 static PyGetSetDef recpy_record_getset[] = {
-  { "ptid", recpy_ptid, NULL, "Current thread.", NULL },
   { "method", recpy_method, NULL, "Current recording method.", NULL },
   { "format", recpy_format, NULL, "Current recording format.", NULL },
   { "replay_position", recpy_replay_position, NULL, "Current replay position.",
diff --git a/gdb/testsuite/gdb.python/py-record-btrace.exp b/gdb/testsuite/gdb.python/py-record-btrace.exp
index 7752cac..ecc8bdf 100644
--- a/gdb/testsuite/gdb.python/py-record-btrace.exp
+++ b/gdb/testsuite/gdb.python/py-record-btrace.exp
@@ -59,7 +59,6 @@ with_test_prefix "preopened record btrace" {
 
 with_test_prefix "prepare record" {
     gdb_test_no_output "python r = gdb.start_recording(\"btrace\")"
-    gdb_test "python print(len(r.ptid))" "3"
     gdb_test "python print(r.method)" "btrace"
     gdb_test "python print(r.format)" "pt|bts"
     gdb_test "stepi 100" ".*"
-- 
2.7.4

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 8/8] Python: Introduce gdb.Instruction class
  2017-04-21 10:50 ` [PATCH v2 8/8] Python: Introduce gdb.Instruction class Tim Wiederhake
@ 2017-04-21 12:19   ` Eli Zaretskii
  2017-04-24  5:34     ` Wiederhake, Tim
  2017-04-21 18:10   ` Yao Qi
  1 sibling, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2017-04-21 12:19 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker, qiyaoltc

> From: Tim Wiederhake <tim.wiederhake@intel.com>
> Cc: markus.t.metzger@intel.com, brobecker@adacore.com, qiyaoltc@gmail.com
> Date: Fri, 21 Apr 2017 12:49:46 +0200
> 
> +@defvar RecordInstruction.number
> +An integer identifying this instruction.  @var{number} corresponds to

@var is wrong here; please use @code instead.  (Yes, I know it was
that way in theoriginal text.)

Otherwise, the documentation part is approved.

Thanks.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 4/8] Python: Remove ptid from gdb.Record interface
  2017-04-21 10:50 ` [PATCH v2 4/8] Python: Remove ptid from gdb.Record interface Tim Wiederhake
@ 2017-04-21 12:20   ` Eli Zaretskii
  0 siblings, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2017-04-21 12:20 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker, qiyaoltc

> From: Tim Wiederhake <tim.wiederhake@intel.com>
> Cc: markus.t.metzger@intel.com, brobecker@adacore.com, qiyaoltc@gmail.com
> Date: Fri, 21 Apr 2017 12:49:42 +0200
> 
> gdb/ChangeLog:
> 	* python/py-record.c (recpy_ptid): Remove.
> 	(recpy_record_getset): Remove recpy_ptid.
> 
> gdb/doc/ChangeLog:
> 	* python.texi (Recording in Python): Remove Record.ptid defvar.
> 
> gdb/testsuite/ChangeLog:
> 	* gdb.python/py-record-btrace.exp: Remove Record.ptid test.

The documentation part is OK.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction
  2017-04-21 10:50 ` [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction Tim Wiederhake
@ 2017-04-21 12:22   ` Eli Zaretskii
  2017-04-21 16:41   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2017-04-21 12:22 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker, qiyaoltc

> From: Tim Wiederhake <tim.wiederhake@intel.com>
> Cc: markus.t.metzger@intel.com, brobecker@adacore.com, qiyaoltc@gmail.com
> Date: Fri, 21 Apr 2017 12:49:45 +0200
> 
> +@defvar RecordFunctionSegment.number
> +An integer identifying this function segment.  @var{number} corresponds to

Please use @code, not @var here.

The documentation part is okay with this fixed.

Thanks.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction
  2017-04-21 10:50 ` [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction Tim Wiederhake
@ 2017-04-21 12:23   ` Eli Zaretskii
  2017-04-21 15:21   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2017-04-21 12:23 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker, qiyaoltc

> From: Tim Wiederhake <tim.wiederhake@intel.com>
> Cc: markus.t.metzger@intel.com, brobecker@adacore.com, qiyaoltc@gmail.com
> Date: Fri, 21 Apr 2017 12:49:44 +0200
> 
> Remove gdb.BtraceInstruction and replace by gdb.RecordInstruction.
> 
> 2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>
> 
> gdb/ChangeLog:
> 	* python/py-record-btrace.c (BTPY_REQUIRE_VALID_INSN): Remove.
> 	(btpy_object, btpy_insn_type, btpy_new): Remove.
> 	(btpy_list_object): Use gdb.RecordInstruction type instead of
> 	gdb.BtraceInstruction type.
> 	(btrace_insn_from_recpy_insn): New function.
> 	(btpy_insn_or_gap_new): Adjust comment. Use recpy_insn_new instead of
> 	btpy_new.
> 	(btpy_call_new, btpy_list_item): Do not use btpy_new anymore.
> 	(btpy_number, btpy_hash, btpy_call_level, btpy_call_symbol,
> 	btpy_call_instructions, btpy_call_up, btpy_call_prev_sibling,
> 	btpy_call_next_sibling, btpy_richcompare): Use recpy_element_object
> 	instead of btpy_object.
> 	(btpy_insn_sal, btpy_insn_pc, btpy_insn_size, btpy_insn_is_speculative,
> 	btpy_insn_data, btpy_insn_decode): Rename to ...
> 	(recpy_bt_insn_sal, recpy_bt_insn_pc, recpy_bt_insn_size,
> 	recpy_bt_insn_is_speculative, recpy_bt_insn_data,
> 	recpy_bt_insn_decode): This.  Also, use new helper functions.
> 	(btpy_list_position, recpy_bt_goto): Use recpy_element_object and
> 	recpy_insn_type.
> 	(btpy_insn_getset): Remove.
> 	(gdbpy_initialize_btrace): Remove code to initialize
> 	gdb.BtraceInstruction.  Use recpy_element_object.
> 	* python/py-record-btrace.h (recpy_bt_insn_number, recpy_bt_insn_sal,
> 	recpy_bt_insn_pc, recpy_bt_insn_data, recpy_bt_insn_decoded,
> 	recpy_bt_insn_size, recpy_bt_insn_is_speculative): New export.
> 	* python/py-record.c (recpy_insn_type): New static object.
> 	(recpy_insn_new, recpy_insn_sal, recpy_insn_pc, recpy_insn_data,
> 	recpy_insn_decoded, recpy_insn_size, recpy_insn_is_speculative,
> 	recpy_element_number, recpy_element_hash, recpy_element_richcompare):
> 	New function.
> 	(recpy_insn_getset): New static object.
> 	(gdbpy_initialize_record): Initialize gdb.RecordInstruction.
> 	* python/py-record.h (recpy_element_object): New typedef.
> 	(recpy_insn_type, recpy_insn_new): New export.
> 
> gdb/doc/ChangeLog:
> 	* python.texi (Recording in Python): Replace gdb.BtraceInstruction with
> 	gdb.RecordInstruction

OK for the documentation part.  Bonus points for fixing the
@var{number} thing in the text you didn't touch.

Thanks.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 5/8] Python: Introduce gdb.RecordGap class
  2017-04-21 10:50 ` [PATCH v2 5/8] Python: Introduce gdb.RecordGap class Tim Wiederhake
@ 2017-04-21 12:25   ` Eli Zaretskii
  2017-04-21 14:50   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2017-04-21 12:25 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker, qiyaoltc

> From: Tim Wiederhake <tim.wiederhake@intel.com>
> Cc: markus.t.metzger@intel.com, brobecker@adacore.com, qiyaoltc@gmail.com
> Date: Fri, 21 Apr 2017 12:49:43 +0200
> 
> +@defvar RecordGap.number
> +An integer identifying this gap.  @var{number} corresponds to the numbers seen

"number" should be in @code, not @var.

The documentation part is OK with this fixed.

Thanks.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 3/8] Python: Use correct ptid in btrace recording
  2017-04-21 10:50 ` [PATCH v2 3/8] Python: Use correct ptid in btrace recording Tim Wiederhake
@ 2017-04-21 14:49   ` Yao Qi
  0 siblings, 0 replies; 22+ messages in thread
From: Yao Qi @ 2017-04-21 14:49 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker

Tim Wiederhake <tim.wiederhake@intel.com> writes:

> 2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>
>
> gdb/ChangeLog:
> 	* btrace.c (btrace_fetch): Set inferior_ptid.
> 	* python/py-record-btrace.c: Add "py-record.h" include.
> 	(recpy_bt_format, recpy_bt_replay_position, recpy_bt_begin,
> 	recpy_bt_end, recpy_bt_instruction_history,
> 	recpy_bt_function_call_history, recpy_bt_goto): Use ptid stored
> 	in gdb.Record object instead of current ptid.
> 	* python/py-record.c: Include new "py-record.h" file.
> 	(recpy_record_object): Moved to py-record.h.
> 	* python/py-record.h: New file.
>
> gdb/testsuite/ChangeLog:
> 	* gdb.python/py-record-btrace-threads.c: New file.
> 	* gdb.python/py-record-btrace-threads.exp: New file.

LGTM.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 5/8] Python: Introduce gdb.RecordGap class
  2017-04-21 10:50 ` [PATCH v2 5/8] Python: Introduce gdb.RecordGap class Tim Wiederhake
  2017-04-21 12:25   ` Eli Zaretskii
@ 2017-04-21 14:50   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Yao Qi @ 2017-04-21 14:50 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker

Tim Wiederhake <tim.wiederhake@intel.com> writes:

> As discussed here: https://sourceware.org/ml/gdb-patches/2017-04/msg00157.html
>
> A gap is not an instruction and it should not pretend to be one.

Hi Tim,
Patch is good to me, a comment on commit log.  Could you extract the
discussion summary in the url into the commit log? so people can read
them in git log easily.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction
  2017-04-21 10:50 ` [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction Tim Wiederhake
  2017-04-21 12:23   ` Eli Zaretskii
@ 2017-04-21 15:21   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Yao Qi @ 2017-04-21 15:21 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker

Tim Wiederhake <tim.wiederhake@intel.com> writes:

> 2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>
>
> gdb/ChangeLog:
> 	* python/py-record-btrace.c (BTPY_REQUIRE_VALID_INSN): Remove.
> 	(btpy_object, btpy_insn_type, btpy_new): Remove.
> 	(btpy_list_object): Use gdb.RecordInstruction type instead of
> 	gdb.BtraceInstruction type.
> 	(btrace_insn_from_recpy_insn): New function.
> 	(btpy_insn_or_gap_new): Adjust comment. Use recpy_insn_new instead of
> 	btpy_new.
> 	(btpy_call_new, btpy_list_item): Do not use btpy_new anymore.
> 	(btpy_number, btpy_hash, btpy_call_level, btpy_call_symbol,
> 	btpy_call_instructions, btpy_call_up, btpy_call_prev_sibling,
> 	btpy_call_next_sibling, btpy_richcompare): Use recpy_element_object
> 	instead of btpy_object.
> 	(btpy_insn_sal, btpy_insn_pc, btpy_insn_size, btpy_insn_is_speculative,
> 	btpy_insn_data, btpy_insn_decode): Rename to ...
> 	(recpy_bt_insn_sal, recpy_bt_insn_pc, recpy_bt_insn_size,
> 	recpy_bt_insn_is_speculative, recpy_bt_insn_data,
> 	recpy_bt_insn_decode): This.  Also, use new helper functions.
> 	(btpy_list_position, recpy_bt_goto): Use recpy_element_object and
> 	recpy_insn_type.
> 	(btpy_insn_getset): Remove.
> 	(gdbpy_initialize_btrace): Remove code to initialize
> 	gdb.BtraceInstruction.  Use recpy_element_object.
> 	* python/py-record-btrace.h (recpy_bt_insn_number, recpy_bt_insn_sal,
> 	recpy_bt_insn_pc, recpy_bt_insn_data, recpy_bt_insn_decoded,
> 	recpy_bt_insn_size, recpy_bt_insn_is_speculative): New export.
> 	* python/py-record.c (recpy_insn_type): New static object.
> 	(recpy_insn_new, recpy_insn_sal, recpy_insn_pc, recpy_insn_data,
> 	recpy_insn_decoded, recpy_insn_size, recpy_insn_is_speculative,
> 	recpy_element_number, recpy_element_hash, recpy_element_richcompare):
> 	New function.
> 	(recpy_insn_getset): New static object.
> 	(gdbpy_initialize_record): Initialize gdb.RecordInstruction.
> 	* python/py-record.h (recpy_element_object): New typedef.
> 	(recpy_insn_type, recpy_insn_new): New export.

Patch is good to me.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction
  2017-04-21 10:50 ` [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction Tim Wiederhake
  2017-04-21 12:22   ` Eli Zaretskii
@ 2017-04-21 16:41   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Yao Qi @ 2017-04-21 16:41 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker

Tim Wiederhake <tim.wiederhake@intel.com> writes:

> Remove gdb.BtraceFunctionCall and replace by gdb.FunctionSegment.  Additionally,
> rename prev_segment and next_segment to prev and next.
>
> 2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>
>
> gdb/ChangeLog:
> 	* python/py-record-btrace.c (BTPY_REQUIRE_VALID_CALL, btpy_call_type):
> 	Remove.
> 	(btrace_func_from_recpy_func): New function.
> 	(btpy_call_new, btpy_number, btpy_hash, btpy_richcompare): Remove.
> 	(btpy_call_level, btpy_call_symbol, btpy_call_instructions,
> 	btpy_call_up, btpy_call_prev_sibling, btpy_call_next_sibling): Rename to ...
> 	(recpy_bt_func_level, recpy_bt_func_symbol, recpy_bt_func_instructions,
> 	recpy_bt_func_up, recpy_bt_func_prev, recpy_bt_func_next): This.
> 	Also, use new helper functions.
> 	(btpy_list_item): Use new helper functions.
> 	(recpy_bt_function_call_history): Use new type name.
> 	(btpy_call_getset): Remove.
> 	(gdbpy_initialize_btrace): Remove code to initialize
> 	gdb.BtraceFunctionCall.
> 	* python/py-record-btrace.h (recpy_bt_func_number, recpy_btb_func_level,
> 	recpy_btb_func_symbol, recpy_bt_func_instructions, recpy_bt_func_up,
> 	recpy_bt_func_prev, recpy_bt_func_next): New export.
> 	* python/py-record.c (recpy_func_type): New static object.
> 	(recpy_func_new, recpy_func_level, recpy_func_symbol,
> 	recpy_func_instructions, recpy_func_up, recpy_func_prev,
> 	recpy_func_next): New function.
> 	(recpy_element_hash, recpy_element_richcompare): Updated comment.
> 	(recpy_func_getset): New static object.
> 	(gdbpy_initialize_record): Add code to initialize gdb.RecordInstruction.
> 	* python/py-record.h (recpy_func_type, recpy_func_new): New export.
>
> gdb/doc/ChangeLog:
> 	* python.texi (Recording in Python): Replace gdb.BtraceFunction with
> 	gdb.RecordFunctionSegment.  Rename prev_sibling and next_sibling to
> 	prev and next.
>
> gdb/testsuite/ChangeLog:
> 	* gdb.python/py-record-btrace.exp: Rename prev_sibling and next_sibling
> 	to prev and next.

LGTM.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c
  2017-04-21 10:50 ` [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c Tim Wiederhake
@ 2017-04-21 18:08   ` Yao Qi
  2017-04-27 16:35   ` Pedro Alves
  1 sibling, 0 replies; 22+ messages in thread
From: Yao Qi @ 2017-04-21 18:08 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker, pmuldoon, dje

Tim Wiederhake <tim.wiederhake@intel.com> writes:

> GDB_PY_HANDLE_EXCEPTION does not handle all exceptions.  Replace with call to
> gdbpy_convert_exception.
>
> 2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>
>
> gdb/ChangeLog:
> 	python/py-record-btrace.c (btpy_insn_sal, btpy_insn_data,
> 	btpy_insn_decode, recpy_bt_goto): Handle all exceptions.

I don't know much about exception in python, could some one else review
this patch?  Phil, Doug?

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 8/8] Python: Introduce gdb.Instruction class
  2017-04-21 10:50 ` [PATCH v2 8/8] Python: Introduce gdb.Instruction class Tim Wiederhake
  2017-04-21 12:19   ` Eli Zaretskii
@ 2017-04-21 18:10   ` Yao Qi
  1 sibling, 0 replies; 22+ messages in thread
From: Yao Qi @ 2017-04-21 18:10 UTC (permalink / raw)
  To: Tim Wiederhake; +Cc: gdb-patches, markus.t.metzger, brobecker

Tim Wiederhake <tim.wiederhake@intel.com> writes:

> 2017-04-21  Tim Wiederhake  <tim.wiederhake@intel.com>
>
> gdb/ChangeLog:
>
> 	* Makefile.in (SUBDIR_PYTHON_OBS): Add py-instruction.o.
> 	(SUBDIR_PYTHON_SRCS): Add py-instruction.c.
> 	* python/py-instruction.c, python/py-instruction.h: New file.
> 	* python/py-record.c: Add py-instruction.h include.
> 	(gdbpy_initialize_record): Make gdb.Instruction a super class of
> 	gdb.RecordInstruction.
> 	* python/python-internal.h: Add gdbpy_initialize_instruction
> 	declaration.
> 	* python/python.c (do_start_initialization): Add
> 	gdbpy_initialize_instruction.

Patch is good to me.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH v2 8/8] Python: Introduce gdb.Instruction class
  2017-04-21 12:19   ` Eli Zaretskii
@ 2017-04-24  5:34     ` Wiederhake, Tim
  0 siblings, 0 replies; 22+ messages in thread
From: Wiederhake, Tim @ 2017-04-24  5:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, Metzger, Markus T, brobecker, qiyaoltc

Hi Eli!

Thank you! I've changed it locally (and the issues from your other mails as well).

Regards,
Tim

> -----Original Message-----
> From: Eli Zaretskii [mailto:eliz@gnu.org]
> Sent: Friday, April 21, 2017 2:20 PM
> To: Wiederhake, Tim <tim.wiederhake@intel.com>
> Cc: gdb-patches@sourceware.org; Metzger, Markus T
> <markus.t.metzger@intel.com>; brobecker@adacore.com; qiyaoltc@gmail.com
> Subject: Re: [PATCH v2 8/8] Python: Introduce gdb.Instruction class
> 
> > From: Tim Wiederhake <tim.wiederhake@intel.com>
> > Cc: markus.t.metzger@intel.com, brobecker@adacore.com,
> qiyaoltc@gmail.com
> > Date: Fri, 21 Apr 2017 12:49:46 +0200
> >
> > +@defvar RecordInstruction.number
> > +An integer identifying this instruction.  @var{number} corresponds to
> 
> @var is wrong here; please use @code instead.  (Yes, I know it was
> that way in theoriginal text.)
> 
> Otherwise, the documentation part is approved.
> 
> Thanks.
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c
  2017-04-21 10:50 ` [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c Tim Wiederhake
  2017-04-21 18:08   ` Yao Qi
@ 2017-04-27 16:35   ` Pedro Alves
  1 sibling, 0 replies; 22+ messages in thread
From: Pedro Alves @ 2017-04-27 16:35 UTC (permalink / raw)
  To: Tim Wiederhake, gdb-patches; +Cc: markus.t.metzger, brobecker, qiyaoltc

On 04/21/2017 11:49 AM, Tim Wiederhake wrote:
> GDB_PY_HANDLE_EXCEPTION does not handle all exceptions.  Replace with call to
> gdbpy_convert_exception.

This makes no sense to me.  Here's the definition:

/* Use this after a TRY_EXCEPT to throw the appropriate Python
   exception.  */
#define GDB_PY_HANDLE_EXCEPTION(Exception)	\
  do {						\
    if (Exception.reason < 0)			\
      {						\
	gdbpy_convert_exception (Exception);	\
        return NULL;				\
      }						\
  } while (0)

That definitely handles all exceptions.  "reason" is never
positive.

I could see

> @@ -891,14 +898,17 @@ recpy_bt_goto (PyObject *self, PyObject *args)
>  	target_goto_record_end ();
>        else
>  	target_goto_record (obj->number);
> +
> +      Py_INCREF (Py_None);
> +      ret = Py_None;
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> -      GDB_PY_HANDLE_EXCEPTION (except);
> +      gdbpy_convert_exception (except);
>      }
>    END_CATCH
>
> -  Py_RETURN_NONE;
> +  return ret;
>  }

this particular change making sense, but for a completely
different reason -- GDB_PY_HANDLE_EXCEPTION returns NULL
and here you seem to want to return a Py_None with a
reference.  But that should be split to its own patch
with its own rationale.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2017-04-27 16:35 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-21 10:50 [PATCH v2 0/8] Python bindings for GDB record Tim Wiederhake
2017-04-21 10:50 ` [PATCH v2 1/8] Python: Fix indentation in py-record-btrace.c Tim Wiederhake
2017-04-21 10:50 ` [PATCH v2 4/8] Python: Remove ptid from gdb.Record interface Tim Wiederhake
2017-04-21 12:20   ` Eli Zaretskii
2017-04-21 10:50 ` [PATCH v2 8/8] Python: Introduce gdb.Instruction class Tim Wiederhake
2017-04-21 12:19   ` Eli Zaretskii
2017-04-24  5:34     ` Wiederhake, Tim
2017-04-21 18:10   ` Yao Qi
2017-04-21 10:50 ` [PATCH v2 6/8] Python: Move and rename gdb.BtraceInstruction Tim Wiederhake
2017-04-21 12:23   ` Eli Zaretskii
2017-04-21 15:21   ` Yao Qi
2017-04-21 10:50 ` [PATCH v2 2/8] Python: Fix exception handling in py-record-btrace.c Tim Wiederhake
2017-04-21 18:08   ` Yao Qi
2017-04-27 16:35   ` Pedro Alves
2017-04-21 10:50 ` [PATCH v2 7/8] Python: Move and rename gdb.BtraceFunction Tim Wiederhake
2017-04-21 12:22   ` Eli Zaretskii
2017-04-21 16:41   ` Yao Qi
2017-04-21 10:50 ` [PATCH v2 3/8] Python: Use correct ptid in btrace recording Tim Wiederhake
2017-04-21 14:49   ` Yao Qi
2017-04-21 10:50 ` [PATCH v2 5/8] Python: Introduce gdb.RecordGap class Tim Wiederhake
2017-04-21 12:25   ` Eli Zaretskii
2017-04-21 14:50   ` Yao Qi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).