2008-03-25 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / varobj.c
index 223693180c7be46d48ecab28185cba0ce6d8fbab..c8d85a9bbdc336cd60fc2fdcc08ef2efafe99d70 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "varobj.h"
 #include "vec.h"
+#include "gdbthread.h"
+#include "inferior.h"
 
 /* Non-zero if we want to see trace of varobj level stuff.  */
 
@@ -62,9 +64,17 @@ struct varobj_root
   /* Block for which this expression is valid */
   struct block *valid_block;
 
-  /* The frame for this expression */
+  /* The frame for this expression.  This field is set iff valid_block is
+     not NULL.  */
   struct frame_id frame;
 
+  /* The thread ID that this varobj_root belong to.  This field
+     is only valid if valid_block is not NULL.  
+     When not 0, indicates which thread 'frame' belongs to.
+     When 0, indicates that the thread list was empty when the varobj_root
+     was created.  */
+  int thread_id;
+
   /* If 1, "update" always recomputes the frame & valid block
      using the currently selected frame. */
   int use_selected_frame;
@@ -497,11 +507,12 @@ varobj_create (char *objname,
          we must select the appropriate frame before parsing
          the expression, otherwise the value will not be current.
          Since select_frame is so benign, just call it for all cases. */
-      if (fi != NULL)
+      if (innermost_block && fi != NULL)
        {
          var->root->frame = get_frame_id (fi);
+         var->root->thread_id = pid_to_thread_id (inferior_ptid);
          old_fi = get_selected_frame (NULL);
-         select_frame (fi);
+         select_frame (fi);     
        }
 
       /* We definitely need to catch errors here.
@@ -689,6 +700,19 @@ varobj_get_display_format (struct varobj *var)
   return var->format;
 }
 
+/* If the variable object is bound to a specific thread, that
+   is its evaluation can always be done in context of a frame
+   inside that thread, returns GDB id of the thread -- which
+   is always positive.  Otherwise, returns -1. */
+int
+varobj_get_thread_id (struct varobj *var)
+{
+  if (var->root->valid_block && var->root->thread_id > 0)
+    return var->root->thread_id;
+  else
+    return -1;
+}
+
 void
 varobj_set_frozen (struct varobj *var, int frozen)
 {
@@ -1110,7 +1134,6 @@ varobj_update (struct varobj **varp, struct varobj ***changelist,
   struct value *new;
   VEC (varobj_p) *stack = NULL;
   VEC (varobj_p) *result = NULL;
-  struct frame_id old_fid;
   struct frame_info *fi;
 
   /* sanity check: have we been passed a pointer?  */
@@ -1129,10 +1152,6 @@ varobj_update (struct varobj **varp, struct varobj ***changelist,
 
   if ((*varp)->root->rootvar == *varp)
     {
-      /* Save the selected stack frame, since we will need to change it
-        in order to evaluate expressions.  */
-      old_fid = get_frame_id (deprecated_safe_get_selected_frame ());
-      
       /* Update the root variable. value_of_root can return NULL
         if the variable is no longer around, i.e. we stepped out of
         the frame in which a local existed. We are letting the 
@@ -1140,11 +1159,6 @@ varobj_update (struct varobj **varp, struct varobj ***changelist,
         has changed.  */
       type_changed = 1;
       new = value_of_root (varp, &type_changed);
-
-      /* Restore selected frame.  */
-      fi = frame_find_by_id (old_fid);
-      if (fi)
-       select_frame (fi);
       
       /* If this is a "use_selected_frame" varobj, and its type has changed,
         them note that it's changed.  */
@@ -2145,37 +2159,65 @@ c_path_expr_of_child (struct varobj *child)
   return child->path_expr;
 }
 
+/* If frame associated with VAR can be found, switch
+   to it and return 1.  Otherwise, return 0.  */
+static int
+check_scope (struct varobj *var)
+{
+  struct frame_info *fi;
+  int scope;
+
+  fi = frame_find_by_id (var->root->frame);
+  scope = fi != NULL;
+
+  if (fi)
+    {
+      CORE_ADDR pc = get_frame_pc (fi);
+      if (pc <  BLOCK_START (var->root->valid_block) ||
+         pc >= BLOCK_END (var->root->valid_block))
+       scope = 0;
+      else
+       select_frame (fi);
+    }
+  return scope;
+}
+
 static struct value *
 c_value_of_root (struct varobj **var_handle)
 {
   struct value *new_val = NULL;
   struct varobj *var = *var_handle;
   struct frame_info *fi;
-  int within_scope;
-
+  int within_scope = 0;
+  struct cleanup *back_to;
+                                                                
   /*  Only root variables can be updated... */
   if (!is_root_p (var))
     /* Not a root var */
     return NULL;
 
+  back_to = make_cleanup_restore_current_thread (
+    inferior_ptid, get_frame_id (deprecated_safe_get_selected_frame ()));
 
   /* Determine whether the variable is still around. */
   if (var->root->valid_block == NULL || var->root->use_selected_frame)
     within_scope = 1;
+  else if (var->root->thread_id == 0)
+    {
+      /* The program was single-threaded when the variable object was
+        created.  Technically, it's possible that the program became
+        multi-threaded since then, but we don't support such
+        scenario yet.  */
+      within_scope = check_scope (var);          
+    }
   else
     {
-      fi = frame_find_by_id (var->root->frame);
-      within_scope = fi != NULL;
-      /* FIXME: select_frame could fail */
-      if (fi)
+      ptid_t ptid = thread_id_to_pid (var->root->thread_id);
+      if (in_thread_list (ptid))
        {
-         CORE_ADDR pc = get_frame_pc (fi);
-         if (pc <  BLOCK_START (var->root->valid_block) ||
-             pc >= BLOCK_END (var->root->valid_block))
-           within_scope = 0;
-         else
-           select_frame (fi);
-       }         
+         switch_to_thread (ptid);
+         within_scope = check_scope (var);
+       }
     }
 
   if (within_scope)
@@ -2186,6 +2228,8 @@ c_value_of_root (struct varobj **var_handle)
       return new_val;
     }
 
+  do_cleanups (back_to);
+
   return NULL;
 }
 
This page took 0.030144 seconds and 4 git commands to generate.