[2/2] OpenMP: Search ancestor threads for variables

Message ID 20171129215519.085ed0bb@pinnacle.lan
State New, archived
Headers

Commit Message

Kevin Buettner Nov. 30, 2017, 4:55 a.m. UTC
  Consider this simple OpenMP program:

    void foo (int a1) {}

    int
    main (void)
    {
      static int s1 = -41;
      int i1 = 11, i2;

      for (i2 = 1; i2 <= 2; i2++)
	{
	  int pass = i2;
    #pragma omp parallel num_threads (2) firstprivate (i1)
	  {
	    foo (i1);
	  }
	  foo(pass);
	}
      foo (s1); foo (i2);
    }

When using a recent (development version) of GCC, GDB is now able to
access variables i2, and pass in the master thread.  (s1, due
to being a static variable is accessible from either thread.
Accessing i1 has been possible for a long while now.)

This patch makes variables such as i2 and pass accessible in
all other threads as well.  (Well, it does so long as a suitable
"thread parent" plugin is installed for libgomp.)

gdb/ChangeLog:
    
    	findvar.c (gdbthread.h): Include.
    	(get_hosting_frame): Add new parameter, errorp. Delete code
    	which generates an error and set errorp instead.
    	(default_read_var_value): Call get_hosting_frame() for
    	ancestor threads in addition to current thread.  Print errors
    	formerly printed by get_hosting_frame().
---
 gdb/findvar.c | 55 ++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 42 insertions(+), 13 deletions(-)
  

Patch

diff --git a/gdb/findvar.c b/gdb/findvar.c
index 2bc2095..81cac7d 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -33,6 +33,7 @@ 
 #include "language.h"
 #include "dwarf2loc.h"
 #include "selftest.h"
+#include "gdbthread.h"
 
 /* Basic byte-swapping routines.  All 'extract' functions return a
    host-format integer from a target-format integer at ADDR which is
@@ -474,10 +475,12 @@  follow_static_link (struct frame_info *frame,
 
 static struct frame_info *
 get_hosting_frame (struct symbol *var, const struct block *var_block,
-		   struct frame_info *frame)
+		   struct frame_info *frame, bool *errorp)
 {
   const struct block *frame_block = NULL;
 
+  *errorp = false;
+
   if (!symbol_read_needs_frame (var))
     return NULL;
 
@@ -564,17 +567,7 @@  get_hosting_frame (struct symbol *var, const struct block *var_block,
   if (frame == NULL)
     {
       frame = block_innermost_frame (var_block);
-      if (frame == NULL)
-	{
-	  if (BLOCK_FUNCTION (var_block)
-	      && !block_inlined_p (var_block)
-	      && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block)))
-	    error (_("No frame is currently executing in block %s."),
-		   SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block)));
-	  else
-	    error (_("No frame is currently executing in specified"
-		     " block"));
-	}
+      *errorp = true;
     }
 
   return frame;
@@ -605,8 +598,44 @@  default_read_var_value (struct symbol *var, const struct block *var_block,
   else if (sym_need == SYMBOL_NEEDS_REGISTERS && !target_has_registers)
     error (_("Cannot read `%s' without registers"), SYMBOL_PRINT_NAME (var));
 
+  scoped_restore_current_thread restore_thread;
+
   if (frame != NULL)
-    frame = get_hosting_frame (var, var_block, frame);
+    {
+      struct frame_info *frame0 = frame;
+      bool errorp;
+
+      frame = get_hosting_frame (var, var_block, frame0, &errorp);
+
+      /* If the hosting frame could not be determined for the current thread,
+         try again using ancestor threads.  This allows GDB to find variables
+	 in outlined OpenMP functions.  */
+      while (frame == NULL)
+        {
+	  struct thread_info *thr_parent = thread_parent (inferior_thread ());
+
+	  if (thr_parent == NULL)
+	    break;
+
+	  switch_to_thread (thr_parent->ptid);
+	  /* frame0 will not be on the stack after switching threads. So,
+	     instead, search using the current frame.  */
+	  frame0 = get_current_frame ();
+	  frame = get_hosting_frame (var, var_block, frame0, &errorp);
+	}
+
+      if (frame == NULL && errorp)
+	{
+	  if (BLOCK_FUNCTION (var_block)
+	      && !block_inlined_p (var_block)
+	      && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block)))
+	    error (_("No frame is currently executing in block %s."),
+		   SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block)));
+	  else
+	    error (_("No frame is currently executing in specified"
+		     " block"));
+	}
+    }
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);