+2017-05-01 Tim Wiederhake <tim.wiederhake@intel.com>
+
+ * 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.
+
2017-05-01 Tim Wiederhake <tim.wiederhake@intel.com>
* python/py-record-btrace.c (BTPY_REQUIRE_VALID_INSN,
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)
#include "gdbcmd.h"
#include "gdbthread.h"
#include "btrace.h"
+#include "py-record.h"
#include "py-record-btrace.h"
#include "disasm.h"
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)
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;
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));
}
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)
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
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)
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
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;
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
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;
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. */
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;
if (tinfo == NULL || btrace_is_empty (tinfo))
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 = {
--- /dev/null
+/* 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 */
+2017-05-01 Tim Wiederhake <tim.wiederhake@intel.com>
+
+ * gdb.python/py-record-btrace-threads.c: New file.
+ * gdb.python/py-record-btrace-threads.exp: New file.
+
2017-04-28 Sergio Durigan Junior <sergiodj@redhat.com>
PR testsuite/8595
--- /dev/null
+/* 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;
+}
--- /dev/null
+# 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
+}