[5/5] gdb/testsuite: Add test that reads auxv in a multi-threaded inferior
Commit Message
This test exercises reading the auxiliary vector in a program where the
main thread exits before other threads.
Because GDB's auxv cache makes it difficult to hit the race that this test
exercises, add a maintenance command that flushes the cache.
Also, move the fetch_auxv procedure from gdb.base/auxv to lib/gdb.exp so
that the new testcase can use it.
---
gdb/auxv.c | 16 ++++++++
gdb/testsuite/gdb.base/auxv.exp | 56 ---------------------------
gdb/testsuite/gdb.threads/auxv.c | 62 ++++++++++++++++++++++++++++++
gdb/testsuite/gdb.threads/auxv.exp | 30 +++++++++++++++
gdb/testsuite/lib/gdb.exp | 62 ++++++++++++++++++++++++++++++
5 files changed, 170 insertions(+), 56 deletions(-)
create mode 100644 gdb/testsuite/gdb.threads/auxv.c
create mode 100644 gdb/testsuite/gdb.threads/auxv.exp
Comments
On Fri, Mar 31, 2023 at 5:46 AM Thiago Jung Bauermann via Gdb-patches <
gdb-patches@sourceware.org> wrote:
> This test exercises reading the auxiliary vector in a program where the
> main thread exits before other threads.
>
> Because GDB's auxv cache makes it difficult to hit the race that this test
> exercises, add a maintenance command that flushes the cache.
>
> Also, move the fetch_auxv procedure from gdb.base/auxv to lib/gdb.exp so
> that the new testcase can use it.
> ---
> gdb/auxv.c | 16 ++++++++
> gdb/testsuite/gdb.base/auxv.exp | 56 ---------------------------
> gdb/testsuite/gdb.threads/auxv.c | 62 ++++++++++++++++++++++++++++++
> gdb/testsuite/gdb.threads/auxv.exp | 30 +++++++++++++++
> gdb/testsuite/lib/gdb.exp | 62 ++++++++++++++++++++++++++++++
> 5 files changed, 170 insertions(+), 56 deletions(-)
> create mode 100644 gdb/testsuite/gdb.threads/auxv.c
> create mode 100644 gdb/testsuite/gdb.threads/auxv.exp
>
>
I tested the series on ppc64le and I've got a failure for
gdb.threads/auxv.exp:
Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for
target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for
target.
Using
/root/build_upstream/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/config/unix.exp
as tool-and-target-specific interface file.
Running
/root/build_upstream/gdb/testsuite/../../../binutils-gdb/gdb/testsuite/gdb.threads/auxv.exp
...
WARNING: Unrecognized tag value: 27 ???
0x1c
WARNING: Unrecognized tag value: 28 ???
0x20
FAIL: gdb.threads/auxv.exp: Get auxv after main thread exits
=== gdb Summary ===
# of expected passes 1
# of unexpected failures 1
Regards,
Alexandra
@@ -27,6 +27,7 @@
#include "observable.h"
#include "gdbsupport/filestuff.h"
#include "objfiles.h"
+#include "cli/cli-cmds.h"
#include "auxv.h"
#include "elf/common.h"
@@ -602,6 +603,17 @@ info_auxv_command (const char *cmd, int from_tty)
}
}
+/* Implement 'maint flush auxv' command. */
+
+static void
+auxv_flush_command (const char *command, int from_tty)
+{
+ /* Force-flush the auxv cache. */
+ invalidate_auxv_cache();
+ if (from_tty)
+ gdb_printf (_ ("Auxiliary vector cache flushed.\n"));
+}
+
void _initialize_auxv ();
void
_initialize_auxv ()
@@ -610,6 +622,10 @@ _initialize_auxv ()
_("Display the inferior's auxiliary vector.\n\
This is information provided by the operating system at program startup."));
+ add_cmd ("auxv-cache", class_maintenance, auxv_flush_command,
+ _ ("Force gdb to flush its auxiliary vector cache."),
+ &maintenanceflushlist);
+
/* Observers used to invalidate the auxv cache when needed. */
gdb::observers::inferior_exit.attach (invalidate_auxv_cache_inf, "auxv");
gdb::observers::inferior_appeared.attach (invalidate_auxv_cache_inf, "auxv");
@@ -59,62 +59,6 @@ set print_core_line [gdb_get_line_number "ABORT;"]
gdb_test "tbreak $print_core_line"
gdb_test continue ".*ABORT;.*"
-proc fetch_auxv {test} {
- global gdb_prompt
-
- set auxv_lines {}
- set bad -1
- # Former trailing `\[\r\n\]+' may eat just \r leaving \n in the buffer
- # corrupting the next matches.
- if {[gdb_test_multiple "info auxv" $test {
- -re "info auxv\r\n" {
- exp_continue
- }
- -ex "The program has no auxiliary information now" {
- set bad 1
- exp_continue
- }
- -ex "Auxiliary vector is empty" {
- set bad 1
- exp_continue
- }
- -ex "No auxiliary vector found" {
- set bad 1
- exp_continue
- }
- -re "^\[0-9\]+\[ \t\]+(AT_\[^ \t\]+)\[^\r\n\]+\r\n" {
- lappend auxv_lines $expect_out(0,string)
- exp_continue
- }
- -re "^\[0-9\]+\[ \t\]+\\?\\?\\?\[^\r\n\]+\r\n" {
- warning "Unrecognized tag value: $expect_out(0,string)"
- set bad 1
- lappend auxv_lines $expect_out(0,string)
- exp_continue
- }
- -re "$gdb_prompt $" {
- incr bad
- }
- -re "^\[^\r\n\]+\r\n" {
- if {!$bad} {
- warning "Unrecognized output: $expect_out(0,string)"
- set bad 1
- }
- exp_continue
- }
- }] != 0} {
- return {}
- }
-
- if {$bad} {
- fail $test
- return {}
- }
-
- pass $test
- return $auxv_lines
-}
-
set live_data [fetch_auxv "info auxv on live process"]
# Now try gcore.
new file mode 100644
@@ -0,0 +1,62 @@
+/* Copyright 2023 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/>. */
+
+/* This program creates an additional thread and then exits the leader thread.
+ It uses semaphores so that GDB can stop the program at specific points and
+ test how it deals with accessing the auxv information of a multi-threaded
+ program in different moments of the thread life cycle. */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static volatile pthread_t main_thread;
+
+static void *
+subthread (void *arg)
+{
+ int rc;
+
+ rc = pthread_join (main_thread, NULL);
+ if (rc != 0)
+ fprintf (stderr, "Warning: pthread_join failed: %s\n", strerror (rc));
+
+ return NULL; /* Main thread exited. */
+}
+
+int
+main (int argc, char *argv[])
+{
+ int rc;
+ pthread_t thread_id;
+
+ main_thread = pthread_self ();
+
+ rc = pthread_create (&thread_id, NULL, &subthread, NULL);
+ if (rc != 0)
+ {
+ fprintf (stderr, "Error: pthread_create failed: %s\n", strerror (rc));
+ return EXIT_FAILURE;
+ }
+
+ pthread_exit (NULL);
+ /* NOTREACHED */
+ return EXIT_FAILURE;
+}
new file mode 100644
@@ -0,0 +1,30 @@
+# Test 'info auxv' and related functionality with a multi-threaded inferior.
+
+# Copyright (C) 2023 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/>.
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ {debug pthreads}] } {
+ return
+}
+
+if ![runto ${srcfile}:[gdb_get_line_number "Main thread exited."]] {
+ return
+}
+
+gdb_test -nopass "maintenance flush auxv-cache" "Auxiliary vector cache flushed."
+
+fetch_auxv "Get auxv after main thread exits"
@@ -7821,6 +7821,68 @@ proc get_var_address { var } {
return ""
}
+# Retrieve the auxiliary vector from the inferior.
+#
+# Issues a pass/fail using TEST as the message, reflecting whether the "info auxv"
+# command worked.
+#
+# Returns the command's output.
+proc fetch_auxv {test} {
+ global gdb_prompt
+
+ set auxv_lines {}
+ set bad -1
+ # Former trailing `\[\r\n\]+' may eat just \r leaving \n in the buffer
+ # corrupting the next matches.
+ if {[gdb_test_multiple "info auxv" $test {
+ -re "info auxv\r\n" {
+ exp_continue
+ }
+ -ex "The program has no auxiliary information now" {
+ set bad 1
+ exp_continue
+ }
+ -ex "Auxiliary vector is empty" {
+ set bad 1
+ exp_continue
+ }
+ -ex "No auxiliary vector found" {
+ set bad 1
+ exp_continue
+ }
+ -re "^\[0-9\]+\[ \t\]+(AT_\[^ \t\]+)\[^\r\n\]+\r\n" {
+ lappend auxv_lines $expect_out(0,string)
+ exp_continue
+ }
+ -re "^\[0-9\]+\[ \t\]+\\?\\?\\?\[^\r\n\]+\r\n" {
+ warning "Unrecognized tag value: $expect_out(0,string)"
+ set bad 1
+ lappend auxv_lines $expect_out(0,string)
+ exp_continue
+ }
+ -re "$gdb_prompt $" {
+ incr bad
+ }
+ -re "^\[^\r\n\]+\r\n" {
+ if {!$bad} {
+ warning "Unrecognized output: $expect_out(0,string)"
+ set bad 1
+ }
+ exp_continue
+ }
+ }] != 0} {
+ return {}
+ }
+
+ if {$bad} {
+ fail $test
+ return {}
+ }
+
+ pass $test
+ return $auxv_lines
+}
+
# Return the frame number for the currently selected frame
proc get_current_frame_number {{test_name ""}} {
global gdb_prompt