@@ -109,6 +109,13 @@ maint print arc arc-instruction address
Alpha running FreeBSD alpha*-*-freebsd*
Alpha running GNU/kFreeBSD alpha*-*-kfreebsd*-gnu
+* New fields in the MI thread output tuple
+
+ When MI prints information about threads (e.g. with -thread-info and
+ -list-thread-groups --recurse 1), it now includes the "inf-id" and
+ "id-in-inf" fields. They respectively indicate the inferior this thread
+ belongs to and its per-inferior id.
+
*** Changes in GDB 7.12
* GDB and GDBserver now build with a C++ compiler by default.
@@ -26859,6 +26859,12 @@ stated otherwise.
@item id
The global numeric id assigned to the thread by @value{GDBN}.
+@item inf-id
+The global numeric id of the inferior the thread belongs to.
+
+@item id-in-inf
+The per-inferior numeric id of the thread.
+
@item target-id
The target-specific string identifying the thread.
@@ -28114,16 +28120,76 @@ command.
@smallexample
-thread-info
-^done,threads=[
-@{id="2",target-id="Thread 0xb7e14b90 (LWP 21257)",
- frame=@{level="0",addr="0xffffe410",func="__kernel_vsyscall",
- args=[]@},state="running"@},
-@{id="1",target-id="Thread 0xb7e156b0 (LWP 21254)",
- frame=@{level="0",addr="0x0804891f",func="foo",
- args=[@{name="i",value="10"@}],
- file="/tmp/a.c",fullname="/tmp/a.c",line="158"@},
- state="running"@}],
-current-thread-id="1"
+^done,
+ threads = [
+ @{
+ inf-id = "1",
+ id-in-inf = "1",
+ id = "1",
+ target-id = "Thread 0x7ffff7fcb740 (LWP 28300)",
+ name = "a",
+ frame = @{
+ level = "0",
+ addr = "0x000000000040062a",
+ func = "main",
+ args = [],
+ file = "a.c",
+ fullname = "/tmp/a.c",
+ line = "13"
+ @},
+ state = "stopped",
+ core = "3"
+ @},
+ @{
+ inf-id = "1",
+ id-in-inf = "2",
+ id = "2",
+ target-id = "Thread 0x7ffff77f3700 (LWP 28304)",
+ name = "a",
+ frame = @{
+ level = "0",
+ addr = "0x0000000000400605",
+ func = "thread_func",
+ args = [
+ @{
+ name = "v",
+ value = "0x0"
+ @}
+ ],
+ file = "a.c",
+ fullname = "/tmp/a.c",
+ line = "5"
+ @},
+ state = "stopped",
+ core = "1"
+ @},
+ @{
+ inf-id = "2",
+ id-in-inf = "1",
+ id = "3",
+ target-id = "Thread 0x7ffff7fcb740 (LWP 28319)",
+ name = "b",
+ state = "running",
+ core = "0"
+ @},
+ @{
+ inf-id = "2",
+ id-in-inf = "2",
+ id = "4",
+ target-id = "Thread 0x7ffff77f3700 (LWP 28320)",
+ name = "b",
+ frame = @{
+ level = "0",
+ addr = "0x00007ffff78b893d",
+ func = "nanosleep",
+ args = [],
+ from = "/lib/x86_64-linux-gnu/libc.so.6"
+ @},
+ state = "stopped",
+ core = "3"
+ @}
+ ],
+ current-thread-id = "3"
(gdb)
@end smallexample
new file mode 100644
@@ -0,0 +1,57 @@
+/* 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 <pthread.h>
+
+static pthread_barrier_t barrier;
+
+static void *
+thread_func (void *arg)
+{
+ /* Notify the main thread that this thread has started. */
+ pthread_barrier_wait (&barrier);
+
+ /* Wait until main gives us the signal that we can quit. */
+ pthread_barrier_wait (&barrier);
+ return NULL;
+}
+
+static void
+thread_started ()
+{
+}
+
+int main ()
+{
+ pthread_t thread;
+
+ pthread_barrier_init (&barrier, NULL, 2);
+
+ pthread_create (&thread, NULL, thread_func, NULL);
+
+ /* Wait until the thread has started. */
+ pthread_barrier_wait (&barrier);
+
+ thread_started ();
+
+ /* Tell the thread that it can quit. */
+ pthread_barrier_wait (&barrier);
+
+ pthread_join (thread, NULL);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,98 @@
+# 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/>.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile
+
+if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "failed to compile"
+ return -1
+}
+
+# Start gdb and set up the first inferior. Run it until the thread_started
+# function.
+
+proc start_gdb_and_first_inferior { } {
+ global binfile
+ global srcdir
+ global subdir
+ global srcfile
+
+ gdb_exit
+ mi_gdb_start
+ mi_gdb_reinitialize_dir $srcdir/$subdir
+ mi_gdb_load ${binfile}
+
+ mi_create_breakpoint "thread_started" "insert breakpoint at thread_started"
+
+ mi_run_cmd
+ mi_expect_stop "breakpoint-hit" "thread_started" ".*" "${srcfile}" ".*" {"" "disp=\"keep\""} "inferior 1 stops"
+
+}
+
+# Add and start a second inferior. Run it until the thread_started function.
+
+proc start_second_inferior { } {
+ global srcfile
+ global binfile
+
+ mi_gdb_test "add-inferior" ".*=thread-group-added,id=\"i2\".*" "add second inferior"
+ mi_gdb_test "inferior 2" ".*" "switch to inferior 2"
+ mi_gdb_load ${binfile}
+ mi_run_cmd
+ mi_expect_stop "breakpoint-hit" "thread_started" ".*" "${srcfile}" ".*" {"" "disp=\"keep\""} "inferior 2 stops"
+}
+
+proc test_thread_info_qualified_thread_id { } {
+ start_gdb_and_first_inferior
+
+ # Test the output with a single inferior.
+ set expected [join \
+ { "111\\^done,threads=.*" \
+ "inf-id=\"1\",id-in-inf=\"1\",id=\"1\".*" \
+ "inf-id=\"1\",id-in-inf=\"2\",id=\"2\".*" \
+ } ""]
+
+ mi_gdb_test \
+ "111-thread-info" \
+ $expected \
+ "thread ids in -thread-info with 1 inferior"
+
+ if {[use_gdb_stub]} {
+ # We can't test with a second inferior if we can't have multiple
+ # inferiors.
+ return
+ }
+
+ start_second_inferior
+
+ # Test the output with two inferiors.
+ set expected [join \
+ { "112\\^done,threads=.*" \
+ "inf-id=\"1\",id-in-inf=\"1\",id=\"1\".*" \
+ "inf-id=\"1\",id-in-inf=\"2\",id=\"2\".*" \
+ "inf-id=\"2\",id-in-inf=\"1\",id=\"3\".*" \
+ "inf-id=\"2\",id-in-inf=\"2\",id=\"4\".*" \
+ } ""]
+
+ mi_gdb_test \
+ "112-thread-info" \
+ $expected \
+ "thread ids in -thread-info with 2 inferiors"
+}
+
+test_thread_info_qualified_thread_id
@@ -1264,7 +1264,7 @@ print_thread_info_1 (struct ui_out *uiout, char *requested_threads,
uiout->table_header (1, ui_left, "current", "");
if (!uiout->is_mi_like_p ())
- uiout->table_header (4, ui_left, "id-in-tg", "Id");
+ uiout->table_header (4, ui_left, "inf-qualified-id", "Id");
if (show_global_ids || uiout->is_mi_like_p ())
uiout->table_header (4, ui_left, "id", "GId");
uiout->table_header (17, ui_left, "target-id", "Target Id");
@@ -1291,8 +1291,13 @@ print_thread_info_1 (struct ui_out *uiout, char *requested_threads,
uiout->field_skip ("current");
}
- if (!uiout->is_mi_like_p ())
- uiout->field_string ("id-in-tg", print_thread_id (tp));
+ if (uiout->is_mi_like_p ())
+ {
+ uiout->field_int ("inf-id", tp->inf->num);
+ uiout->field_int ("id-in-inf", tp->per_inf_num);
+ }
+ else
+ uiout->field_string ("inf-qualified-id", print_thread_id (tp));
if (show_global_ids || uiout->is_mi_like_p ())
uiout->field_int ("id", tp->global_num);