[5/5] gdb/testsuite: Add test that reads auxv in a multi-threaded inferior

Message ID 20230331034432.3037148-6-thiago.bauermann@linaro.org
State New
Headers
Series gdbserver: Follow-up on linux_get_auxv using PID parameter |

Commit Message

Thiago Jung Bauermann March 31, 2023, 3:44 a.m. UTC
  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

Alexandra Petlanova Hajkova April 4, 2023, 2 p.m. UTC | #1
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
  

Patch

diff --git a/gdb/auxv.c b/gdb/auxv.c
index 812b28075548..a39d8afd2990 100644
--- a/gdb/auxv.c
+++ b/gdb/auxv.c
@@ -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");
diff --git a/gdb/testsuite/gdb.base/auxv.exp b/gdb/testsuite/gdb.base/auxv.exp
index 89242b6f4321..7f58bd318fbc 100644
--- a/gdb/testsuite/gdb.base/auxv.exp
+++ b/gdb/testsuite/gdb.base/auxv.exp
@@ -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.
diff --git a/gdb/testsuite/gdb.threads/auxv.c b/gdb/testsuite/gdb.threads/auxv.c
new file mode 100644
index 000000000000..5ad280145c89
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/auxv.c
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.threads/auxv.exp b/gdb/testsuite/gdb.threads/auxv.exp
new file mode 100644
index 000000000000..1ad3564642bd
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/auxv.exp
@@ -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"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 14ce39e8ed72..8dd79ba5008a 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -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