This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add proper handling for non-local references in nested subprograms


GDB's current behavior when dealing with non-local references in the
context of nested subprograms is approximative:

  - code using valops.c:value_of_variable read the first available stack
    frame that holds the corresponding variable (whereas there can be
    multiple candidates for this);

  - code directly relying on read_var_value will instead read non-local
    variables in frames where they are not even defined.

This change adds necessary information to symbols (the block they belong
to) and to blocks (the static link property, if any) so that GDB can
make the proper decisions when dealing with non-local variables.

Regtested on x86_64-linux with both GCC 4.9.2 and a patched GCC (see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53927>).

PS: I'm aware that this patches increases the size of two critical data structures (namely struct block and struct symbol) and I'm completely open to suggestions. :-)

Since I'm not sure of how this issue should be solved, I'm nevertheless posting this patch here so this matter can be discussed. In the context of this feature, I think we need a backlink from all symbols to the corresponding embedding block but on the other hand only a few blocks have static link: maybe we could turn this static_link field into a objfile-based hashtable lookup. Thoughts?

Thank you in advance!

gdb/ChangeLog:
2015-03-02  Pierre-Marie de Rodat  <derodat@adacore.com>

        * ada-lang.c (get_var_value): Update call to value_of_variable.
        * block.h (struct block): Add a static_link field.
        (BLOCK_STATIC_LINK): New accessor.
        * buildsym.c (finish_block_internal): Add a static_link
        argument.  Associate each symbol to the new block.  Initialize
        the static_link field in blocks.
        (finish_block): Add a static link argument and update call to
        finish_block_internal.
        (end_symtab_get_static_block): Update calls to finish_block.
        (end_symtab_with_blockvector): Update call to
        finish_block_internal.
        * buildsym.h: Pull gdbtypes.h.
        (struct context_stack): Add a static_link field.
        (finish_block): Add a static link argument.
        * coffread.c (coff_symtab_read): Update calls to finish_block.
        * dbxread.c (process_one_symbol): Likewise.
        * xcoffread.c (read_xcoff_symtab): Likewise.
        * jit.c (finalize_symtab): Initialize to NULL the static link
        field for the new block.
        * dwarf2loc.c (block_op_get_frame_base): New.
        (dwarf2_block_frame_base_locexpr_funcs): Implement the
        get_frame_base method.
        (dwarf2_block_frame_base_loclist_funcs): Likewise.
        (dwarf2locexpr_baton_eval): Add a frame argument and use it
        instead of the selected frame in order to evaluate the
        expression.
        (dwarf2_evaluate_property): Add a frame argument.  Update call
        to dwarf2_locexpr_baton_eval to provide a frame in available and
        to handle the absence of address stack.
        * dwarf2loc.h (dwarf2_evaluate_property): Add a frame argument.
        * dwarf2read.c (attr_to_dynamic_prop): Add a forward
        declaration.
        (read_func_scope): Record any available static link description.
        Update call to finish_block.
        (read_lexical_block_scope): Update call to finish_block.
        * eval.c (evaluate_subexp_standard): Update calls to
        value_of_variable.
        (evaluate_subexp_for_address): Likewise.
        (evaluate_subexp_with_coercion): Likewise.
        * f-valprint.c (info_common_command_for_block): Likewise.
        * findvar.c (follow_static_link): New.
        (get_hosting_frame): New.
        (default_read_var_value): Use get_hosting_frame to handle
        non-local references.
        * gdbtypes.c (resolve_dynamic_range): Update calls to
        dwarf2_evaluate_property.
        (resolve_dynamic_type_internal): Likewise.
        * python/py-type.c (typy_template_argument): Update call to
        value_of_variable.
        * symtab.h (struct symbol_block_ops): Add a get_frame_base
        method.
        (struct symbol): Add a block field.
        (SYMBOL_BLOCK): New accessor.
        * valarith.c (value_user_defined_cpp_op): Update call to
        value_of_variable.
        * valops.c (find_function_in_inferior): Likewise.
        (value_of_variable): Remove the block argument and remove
        frame/block handling (read_var_value does this, now).
        (address_of_variable): Remove the block argument and update call
        to value_of_variable.
        (value_maybe_namespace_elt): Update call to value_of_variable.
        * value.c (value_static_field): Likewise.
        * value.h (value_of_variable): Remove the block argument.
        (address_of_variable): Likewise.

gdb/testsuite/ChangeLog:
2015-03-02  Pierre-Marie de Rodat  <derodat@adacore.com>

        * gdb.base/nested-subp1.exp: New file.
        * gdb.base/nested-subp1.c: New file.
        * gdb.base/nested-subp2.exp: New file.
        * gdb.base/nested-subp2.c: New file.
        * gdb.base/nested-subp3.exp: New file.
        * gdb.base/nested-subp3.c: New file.

--
Pierre-Marie de Rodat
>From 53fef8afdbd25f4fd7a408c75b4133e58d5a761e Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Thu, 5 Feb 2015 17:00:06 +0100
Subject: [PATCH] Add proper handling for non-local references in nested
 subprograms

GDB's current behavior when dealing with non-local references in the
context of nested subprograms is approximative:

  - code using valops.c:value_of_variable read the first available stack
    frame that holds the corresponding variable (whereas there can be
    multiple candidates for this);

  - code directly relying on read_var_value will instead read non-local
    variables in frames where they are not even defined.

This change adds necessary information to symbols (the block they belong
to) and to blocks (the static link property, if any) so that GDB can
make the proper decisions when dealing with non-local variables.

gdb/ChangeLog:
2015-03-02  Pierre-Marie de Rodat  <derodat@adacore.com>

	* ada-lang.c (get_var_value): Update call to value_of_variable.
	* block.h (struct block): Add a static_link field.
	(BLOCK_STATIC_LINK): New accessor.
	* buildsym.c (finish_block_internal): Add a static_link
	argument.  Associate each symbol to the new block.  Initialize
	the static_link field in blocks.
	(finish_block): Add a static link argument and update call to
	finish_block_internal.
	(end_symtab_get_static_block): Update calls to finish_block.
	(end_symtab_with_blockvector): Update call to
	finish_block_internal.
	* buildsym.h: Pull gdbtypes.h.
	(struct context_stack): Add a static_link field.
	(finish_block): Add a static link argument.
	* coffread.c (coff_symtab_read): Update calls to finish_block.
	* dbxread.c (process_one_symbol): Likewise.
	* xcoffread.c (read_xcoff_symtab): Likewise.
	* jit.c (finalize_symtab): Initialize to NULL the static link
	field for the new block.
	* dwarf2loc.c (block_op_get_frame_base): New.
	(dwarf2_block_frame_base_locexpr_funcs): Implement the
	get_frame_base method.
	(dwarf2_block_frame_base_loclist_funcs): Likewise.
	(dwarf2locexpr_baton_eval): Add a frame argument and use it
	instead of the selected frame in order to evaluate the
	expression.
	(dwarf2_evaluate_property): Add a frame argument.  Update call
	to dwarf2_locexpr_baton_eval to provide a frame in available and
	to handle the absence of address stack.
	* dwarf2loc.h (dwarf2_evaluate_property): Add a frame argument.
	* dwarf2read.c (attr_to_dynamic_prop): Add a forward
	declaration.
	(read_func_scope): Record any available static link description.
	Update call to finish_block.
	(read_lexical_block_scope): Update call to finish_block.
	* eval.c (evaluate_subexp_standard): Update calls to
	value_of_variable.
	(evaluate_subexp_for_address): Likewise.
	(evaluate_subexp_with_coercion): Likewise.
	* f-valprint.c (info_common_command_for_block): Likewise.
	* findvar.c (follow_static_link): New.
	(get_hosting_frame): New.
	(default_read_var_value): Use get_hosting_frame to handle
	non-local references.
	* gdbtypes.c (resolve_dynamic_range): Update calls to
	dwarf2_evaluate_property.
	(resolve_dynamic_type_internal): Likewise.
	* python/py-type.c (typy_template_argument): Update call to
	value_of_variable.
	* symtab.h (struct symbol_block_ops): Add a get_frame_base
	method.
	(struct symbol): Add a block field.
	(SYMBOL_BLOCK): New accessor.
	* valarith.c (value_user_defined_cpp_op): Update call to
	value_of_variable.
	* valops.c (find_function_in_inferior): Likewise.
	(value_of_variable): Remove the block argument and remove
	frame/block handling (read_var_value does this, now).
	(address_of_variable): Remove the block argument and update call
	to value_of_variable.
	(value_maybe_namespace_elt): Update call to value_of_variable.
	* value.c (value_static_field): Likewise.
	* value.h (value_of_variable): Remove the block argument.
	(address_of_variable): Likewise.

gdb/testsuite/ChangeLog:
2015-03-02  Pierre-Marie de Rodat  <derodat@adacore.com>

	* gdb.base/nested-subp1.exp: New file.
	* gdb.base/nested-subp1.c: New file.
	* gdb.base/nested-subp2.exp: New file.
	* gdb.base/nested-subp2.c: New file.
	* gdb.base/nested-subp3.exp: New file.
	* gdb.base/nested-subp3.c: New file.
---
 gdb/ada-lang.c                          |   2 +-
 gdb/block.h                             |   6 ++
 gdb/buildsym.c                          |  26 ++++--
 gdb/buildsym.h                          |  14 ++-
 gdb/coffread.c                          |   4 +-
 gdb/dbxread.c                           |   7 +-
 gdb/dwarf2loc.c                         |  52 +++++++++--
 gdb/dwarf2loc.h                         |  11 ++-
 gdb/dwarf2read.c                        |  21 ++++-
 gdb/eval.c                              |  11 +--
 gdb/f-valprint.c                        |   2 +-
 gdb/findvar.c                           | 159 +++++++++++++++++++++++++++++++-
 gdb/gdbtypes.c                          |   6 +-
 gdb/jit.c                               |   1 +
 gdb/python/py-type.c                    |   2 +-
 gdb/symtab.h                            |  23 +++++
 gdb/testsuite/gdb.base/nested-subp1.c   |  35 +++++++
 gdb/testsuite/gdb.base/nested-subp1.exp |  58 ++++++++++++
 gdb/testsuite/gdb.base/nested-subp2.c   |  45 +++++++++
 gdb/testsuite/gdb.base/nested-subp2.exp |  67 ++++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.c   |  66 +++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.exp |  60 ++++++++++++
 gdb/valarith.c                          |   2 +-
 gdb/valops.c                            |  29 ++----
 gdb/value.c                             |   2 +-
 gdb/value.h                             |   6 +-
 gdb/xcoffread.c                         |   2 +-
 27 files changed, 649 insertions(+), 70 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/nested-subp1.c
 create mode 100644 gdb/testsuite/gdb.base/nested-subp1.exp
 create mode 100644 gdb/testsuite/gdb.base/nested-subp2.c
 create mode 100644 gdb/testsuite/gdb.base/nested-subp2.exp
 create mode 100644 gdb/testsuite/gdb.base/nested-subp3.c
 create mode 100644 gdb/testsuite/gdb.base/nested-subp3.exp

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 562627a..e1d4706 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -11259,7 +11259,7 @@ get_var_value (char *name, char *err_msg)
         error (("%s"), err_msg);
     }
 
-  return value_of_variable (syms[0].sym, syms[0].block);
+  return value_of_variable (syms[0].sym);
 }
 
 /* Value of integer variable named NAME in the current environment.  If
diff --git a/gdb/block.h b/gdb/block.h
index e45f445..3c7c7de 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -70,6 +70,11 @@ struct block
 
   struct symbol *function;
 
+  /* For nested functions, the expression that computes the frame base of the
+     lexically enclosing function.  */
+
+  struct dynamic_prop *static_link;
+
   /* The `struct block' for the containing block, or 0 if none.
 
      The superblock of a top-level local block (i.e. a function in the
@@ -116,6 +121,7 @@ struct global_block
 #define BLOCK_START(bl)		(bl)->startaddr
 #define BLOCK_END(bl)		(bl)->endaddr
 #define BLOCK_FUNCTION(bl)	(bl)->function
+#define BLOCK_STATIC_LINK(bl)	(bl)->static_link
 #define BLOCK_SUPERBLOCK(bl)	(bl)->superblock
 #define BLOCK_DICT(bl)		(bl)->dict
 #define BLOCK_NAMESPACE(bl)   (bl)->language_specific.cplus_specific.namespace
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index bb3ee26..e282ad8 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -331,7 +331,8 @@ free_pending_blocks (void)
    file).  Put the block on the list of pending blocks.  */
 
 static struct block *
-finish_block_internal (struct symbol *symbol, struct pending **listhead,
+finish_block_internal (struct symbol *symbol, struct dynamic_prop *static_link,
+		       struct pending **listhead,
 		       struct pending_block *old_blocks,
 		       CORE_ADDR start, CORE_ADDR end,
 		       int is_global, int expandable)
@@ -347,6 +348,16 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
 	   ? allocate_global_block (&objfile->objfile_obstack)
 	   : allocate_block (&objfile->objfile_obstack));
 
+  /* Associate each symbol to this block.  */
+
+  for (next = *listhead; next != NULL; next = next->next)
+    {
+      int i;
+
+      for (i = 0; i < next->nsyms; ++i)
+	SYMBOL_BLOCK (next->symbol[i]) = block;
+    }
+
   if (symbol)
     {
       BLOCK_DICT (block) = dict_create_linear (&objfile->objfile_obstack,
@@ -422,6 +433,8 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
       BLOCK_FUNCTION (block) = NULL;
     }
 
+  BLOCK_STATIC_LINK (block) = static_link;
+
   /* Now "free" the links of the list, and empty the list.  */
 
   for (next = *listhead; next; next = next1)
@@ -512,11 +525,12 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
 }
 
 struct block *
-finish_block (struct symbol *symbol, struct pending **listhead,
+finish_block (struct symbol *symbol, struct dynamic_prop *static_link,
+	      struct pending **listhead,
 	      struct pending_block *old_blocks,
 	      CORE_ADDR start, CORE_ADDR end)
 {
-  return finish_block_internal (symbol, listhead, old_blocks,
+  return finish_block_internal (symbol, static_link, listhead, old_blocks,
 				start, end, 0, 0);
 }
 
@@ -1218,7 +1232,7 @@ end_symtab_get_static_block (CORE_ADDR end_addr, int expandable, int required)
       struct context_stack *cstk = pop_context ();
 
       /* Make a block for the local symbols within.  */
-      finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+      finish_block (cstk->name, NULL, &local_symbols, cstk->old_blocks,
 		    cstk->start_addr, end_addr);
 
       if (context_stack_depth > 0)
@@ -1289,7 +1303,7 @@ end_symtab_get_static_block (CORE_ADDR end_addr, int expandable, int required)
   else
     {
       /* Define the STATIC_BLOCK.  */
-      return finish_block_internal (NULL, &file_symbols, NULL,
+      return finish_block_internal (NULL, NULL, &file_symbols, NULL,
 				    last_source_start_addr, end_addr,
 				    0, expandable);
     }
@@ -1317,7 +1331,7 @@ end_symtab_with_blockvector (struct block *static_block,
   end_addr = BLOCK_END (static_block);
 
   /* Create the GLOBAL_BLOCK and build the blockvector.  */
-  finish_block_internal (NULL, &global_symbols, NULL,
+  finish_block_internal (NULL, NULL, &global_symbols, NULL,
 			 last_source_start_addr, end_addr,
 			 1, expandable);
   blockvector = make_blockvector ();
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index f98203e..87ba893 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -19,6 +19,8 @@
 #if !defined (BUILDSYM_H)
 #define BUILDSYM_H 1
 
+#include "gdbtypes.h"
+
 struct objfile;
 struct symbol;
 struct addrmap;
@@ -141,6 +143,11 @@ struct context_stack
 
     struct symbol *name;
 
+    /* Expression that computes the frame base of the lexically enclosing
+       function, if any.  NULL otherwise.  */
+
+    struct dynamic_prop *static_link;
+
     /* PC where this context starts */
 
     CORE_ADDR start_addr;
@@ -192,9 +199,10 @@ extern struct symbol *find_symbol_in_list (struct pending *list,
 					   char *name, int length);
 
 extern struct block *finish_block (struct symbol *symbol,
-                                   struct pending **listhead,
-                                   struct pending_block *old_blocks,
-                                   CORE_ADDR start, CORE_ADDR end);
+				   struct dynamic_prop *static_link,
+				   struct pending **listhead, struct
+				   pending_block *old_blocks, CORE_ADDR start,
+				   CORE_ADDR end);
 
 extern void record_block_range (struct block *,
                                 CORE_ADDR start, CORE_ADDR end_inclusive);
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 20c8c5e..10219f2 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1129,7 +1129,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
 		enter_linenos (fcn_line_ptr, fcn_first_line,
 			       fcn_last_line, objfile);
 
-	      finish_block (new->name, &local_symbols,
+	      finish_block (new->name, NULL, &local_symbols,
 			    new->old_blocks, new->start_addr,
 			    fcn_cs_saved.c_value
 			    + fcn_aux_saved.x_sym.x_misc.x_fsize
@@ -1173,7 +1173,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
 		    cs->c_value + ANOFFSET (objfile->section_offsets,
 					    SECT_OFF_TEXT (objfile));
 		  /* Make a block for the local symbols within.  */
-		  finish_block (0, &local_symbols, new->old_blocks,
+		  finish_block (0, NULL, &local_symbols, new->old_blocks,
 				new->start_addr, tmpaddr);
 		}
 	      /* Now pop locals of block just finished.  */
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 6d9bacc..4dc6af2 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2782,7 +2782,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 	  new = pop_context ();
 
 	  /* Make a block for the local symbols within.  */
-	  block = finish_block (new->name, &local_symbols, new->old_blocks,
+	  block = finish_block (new->name, NULL,
+				&local_symbols, new->old_blocks,
 				new->start_addr, new->start_addr + valu);
 
 	  /* For C++, set the block's scope.  */
@@ -2883,7 +2884,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  new->start_addr = valu;
 		}
 	      /* Make a block for the local symbols within.  */
-	      finish_block (0, &local_symbols, new->old_blocks,
+	      finish_block (0, NULL, &local_symbols, new->old_blocks,
 			    new->start_addr, valu);
 	    }
 	}
@@ -3185,7 +3186,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 
 		  new = pop_context ();
 		  /* Make a block for the local symbols within.  */
-		  block = finish_block (new->name, &local_symbols,
+		  block = finish_block (new->name, NULL, &local_symbols,
 					new->old_blocks, new->start_addr,
 					valu);
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index aa569ee..68e4818 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -381,12 +381,42 @@ locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
   *start = symbaton->data;
 }
 
+/* Implement the struct symbol_block_ops::get_frame_base method */
+
+static CORE_ADDR
+block_op_get_frame_base (struct symbol *framefunc, struct frame_info *frame)
+{
+  if (SYMBOL_BLOCK_OPS (framefunc)->find_frame_base_location != NULL)
+    {
+      struct gdbarch *gdbarch = get_frame_arch (frame);
+      struct type *type = builtin_type (gdbarch)->builtin_data_ptr;
+      struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (framefunc);
+      const gdb_byte *start;
+      size_t length;
+      struct value *result;
+
+      SYMBOL_BLOCK_OPS (framefunc)->find_frame_base_location
+        (framefunc, get_frame_pc (frame), &start, &length);
+      result = dwarf2_evaluate_loc_desc (type, frame, start, length,
+					 dlbaton->per_cu);
+
+      /* The DW_AT_frame_base attribute contains a location description which
+	 computes the base address itself.  However, the call to
+	 dwarf2_evaluate_loc_desc returns a value representing a variable at
+	 that address.  The frame base address is thus this variable's address.
+	 */
+      return value_address (result);
+    }
+  return 0;
+}
+
 /* Vector for inferior functions as represented by LOC_BLOCK, if the inferior
    function uses DWARF expression for its DW_AT_frame_base.  */
 
 const struct symbol_block_ops dwarf2_block_frame_base_locexpr_funcs =
 {
-  locexpr_find_frame_base_location
+  locexpr_find_frame_base_location,
+  block_op_get_frame_base
 };
 
 /* Implement find_frame_base_location method for LOC_BLOCK functions using
@@ -406,7 +436,8 @@ loclist_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
 
 const struct symbol_block_ops dwarf2_block_frame_base_loclist_funcs =
 {
-  loclist_find_frame_base_location
+  loclist_find_frame_base_location,
+  block_op_get_frame_base
 };
 
 /* See dwarf2loc.h.  */
@@ -2396,13 +2427,14 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame,
 }
 
 /* Evaluates a dwarf expression and stores the result in VAL, expecting
-   that the dwarf expression only produces a single CORE_ADDR.  ADDR is a
-   context (location of a variable) and might be needed to evaluate the
-   location expression.
+   that the dwarf expression only produces a single CORE_ADDR.  FRAME is the
+   frame in which the expression is evaluated.  ADDR is a context (location of
+   a variable) and might be needed to evaluate the location expression.
    Returns 1 on success, 0 otherwise.   */
 
 static int
 dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
+			   struct frame_info *frame,
 			   CORE_ADDR addr,
 			   CORE_ADDR *valp)
 {
@@ -2417,7 +2449,7 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
   ctx = new_dwarf_expr_context ();
   cleanup = make_cleanup_free_dwarf_expr_context (ctx);
 
-  baton.frame = get_selected_frame (NULL);
+  baton.frame = frame;
   baton.per_cu = dlbaton->per_cu;
   baton.obj_address = addr;
 
@@ -2461,19 +2493,24 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 
 int
 dwarf2_evaluate_property (const struct dynamic_prop *prop,
+			  struct frame_info *frame,
 			  struct property_addr_info *addr_stack,
 			  CORE_ADDR *value)
 {
   if (prop == NULL)
     return 0;
 
+  if (frame == NULL && has_stack_frames ())
+    frame = get_selected_frame (NULL);
+
   switch (prop->kind)
     {
     case PROP_LOCEXPR:
       {
 	const struct dwarf2_property_baton *baton = prop->data.baton;
 
-	if (dwarf2_locexpr_baton_eval (&baton->locexpr, addr_stack->addr,
+	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame,
+				       addr_stack ? addr_stack->addr : 0,
 				       value))
 	  {
 	    if (baton->referenced_type)
@@ -2490,7 +2527,6 @@ dwarf2_evaluate_property (const struct dynamic_prop *prop,
     case PROP_LOCLIST:
       {
 	struct dwarf2_property_baton *baton = prop->data.baton;
-	struct frame_info *frame = get_selected_frame (NULL);
 	CORE_ADDR pc = get_frame_address_in_block (frame);
 	const gdb_byte *data;
 	struct value *val;
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index 0932456..234e5ef 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -119,12 +119,19 @@ struct property_addr_info
   struct property_addr_info *next;
 };
 
-/* Converts a dynamic property into a static one.  ADDR_STACK is the stack
-   of addresses that might be needed to evaluate the property.
+/* Converts a dynamic property into a static one.  FRAME is the frame in which
+   the property is evaluated; if NULL, the selected frame (if any) is used
+   instead.
+
+   ADDR_STACK is the stack of addresses that might be needed to evaluate the
+   property. When evaluating a property that is not related to a type, it can
+   be NULL.
+
    Returns 1 if PROP could be converted and the static value is passed back
    into VALUE, otherwise returns 0.  */
 
 int dwarf2_evaluate_property (const struct dynamic_prop *prop,
+			      struct frame_info *frame,
 			      struct property_addr_info *addr_stack,
 			      CORE_ADDR *value);
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index ac78165..a86b1d6 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1720,6 +1720,10 @@ static void load_full_type_unit (struct dwarf2_per_cu_data *per_cu);
 
 static void read_signatured_type (struct signatured_type *);
 
+static int attr_to_dynamic_prop (const struct attribute *attr,
+				 struct die_info *die, struct dwarf2_cu *cu,
+				 struct dynamic_prop *prop);
+
 /* memory allocation interface */
 
 static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *);
@@ -11353,6 +11357,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (attr)
     dwarf2_symbol_mark_computed (attr, new->name, cu, 1);
 
+  /* If there is a location for the static link, record it.  */
+  new->static_link = NULL;
+  attr = dwarf2_attr (die, DW_AT_static_link, cu);
+  if (attr)
+    {
+      new->static_link = obstack_alloc (&objfile->objfile_obstack,
+					sizeof (*new->static_link));
+      attr_to_dynamic_prop (attr, die, cu, new->static_link);
+    }
+
   cu->list_in_scope = &local_symbols;
 
   if (die->child != NULL)
@@ -11403,7 +11417,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 
   new = pop_context ();
   /* Make a block for the local symbols within.  */
-  block = finish_block (new->name, &local_symbols, new->old_blocks,
+  block = finish_block (new->name, &new->static_link,
+			&local_symbols, new->old_blocks,
                         lowpc, highpc);
 
   /* For C++, set the block's scope.  */
@@ -11486,8 +11501,8 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (local_symbols != NULL || using_directives != NULL)
     {
       struct block *block
-        = finish_block (0, &local_symbols, new->old_blocks, new->start_addr,
-                        highpc);
+        = finish_block (0, NULL, &local_symbols, new->old_blocks,
+			new->start_addr, highpc);
 
       /* Note that recording ranges after traversing children, as we
          do here, means that recording a parent's ranges entails
diff --git a/gdb/eval.c b/gdb/eval.c
index bb2a0da..f011bfc 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -767,8 +767,7 @@ evaluate_subexp_standard (struct type *expect_type,
 
 	TRY_CATCH (except, RETURN_MASK_ERROR)
 	  {
-	    ret = value_of_variable (exp->elts[pc + 2].symbol,
-				     exp->elts[pc + 1].block);
+	    ret = value_of_variable (exp->elts[pc + 2].symbol);
 	  }
 
 	if (except.reason < 0)
@@ -1208,7 +1207,7 @@ evaluate_subexp_standard (struct type *expect_type,
 	    /* Is it a high_level symbol?  */
 	    sym = find_pc_function (addr);
 	    if (sym != NULL) 
-	      method = value_of_variable (sym, 0);
+	      method = value_of_variable (sym);
 	  }
 
 	/* If we found a method with symbol information, check to see
@@ -1701,7 +1700,7 @@ evaluate_subexp_standard (struct type *expect_type,
 							     noside);
 		}
 	      else
-		argvec[0] = value_of_variable (symp, get_selected_block (0));
+		argvec[0] = value_of_variable (symp);
 	    }
 	  else
 	    {
@@ -2895,7 +2894,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos,
 	    value_zero (type, not_lval);
 	}
       else
-	return address_of_variable (var, exp->elts[pc + 1].block);
+	return address_of_variable (var);
 
     case OP_SCOPE:
       tem = longest_to_int (exp->elts[pc + 2].longconst);
@@ -2963,7 +2962,7 @@ evaluate_subexp_with_coercion (struct expression *exp,
 	  && CAST_IS_CONVERSION (exp->language_defn))
 	{
 	  (*pos) += 4;
-	  val = address_of_variable (var, exp->elts[pc + 1].block);
+	  val = address_of_variable (var);
 	  return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
 			     val);
 	}
diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c
index c2aca71..8303e05 100644
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -450,7 +450,7 @@ info_common_command_for_block (const struct block *block, const char *comname,
 
 	    TRY_CATCH (except, RETURN_MASK_ERROR)
 	      {
-		val = value_of_variable (common->contents[index], block);
+		val = value_of_variable (common->contents[index]);
 		value_print (val, gdb_stdout, &opts);
 	      }
 
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 128bf5e..c0a6dce 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -32,6 +32,7 @@
 #include "block.h"
 #include "objfiles.h"
 #include "language.h"
+#include "dwarf2loc.h"
 
 /* Basic byte-swapping routines.  All 'extract' functions return a
    host-format integer from a target-format integer at ADDR which is
@@ -409,6 +410,160 @@ minsym_lookup_iterator_cb (struct objfile *objfile, void *cb_data)
   return (data->result.minsym != NULL);
 }
 
+/* Given static link expression and the frame it lives in, look for the frame
+   the static links points to and return it.  Return NULL if we could not find
+   such a frame.   */
+
+static struct frame_info *
+follow_static_link (struct frame_info *frame,
+		    const struct dynamic_prop *static_link)
+{
+  CORE_ADDR upper_frame_base;
+
+  if (!dwarf2_evaluate_property (static_link, frame, NULL, &upper_frame_base))
+    return NULL;
+
+  /* Now climb up the stack frame until we reach the frame we are interested
+     in.  */
+  for (; frame != NULL; frame = get_prev_frame (frame))
+    {
+      struct symbol *framefunc = get_frame_function (frame);
+
+      /* Protect ourselves against bad things such as circular call stacks.  */
+      QUIT;
+
+      /* If we don't know how to compute FRAME's base address, don't give up:
+	 maybe the frame we are looking for is upper in the stace frame.  */
+      if (framefunc != NULL
+	  && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base
+	  && (SYMBOL_BLOCK_OPS (framefunc)->get_frame_base (framefunc, frame)
+	      == upper_frame_base))
+	break;
+    }
+
+  return frame;
+}
+
+/* Assuming VAR is a symbol that can be reached from FRAME thanks to lexical
+   rules, look for the frame that is actually hosting VAR and return it.  If,
+   for some reason, we found no such frame, return NULL.
+
+   This kind of computation is necessary to correctly handle lexically nested
+   subprograms.
+
+   Note that in some cases, we know what scope VAR comes from but we cannot
+   reach the specific frame that hosts the instance of VAR we are looking for.
+   For backward compatibility purposes (with old compilers), we then look for
+   the first frame that can host it.  */
+
+static struct frame_info *
+get_hosting_frame (struct symbol *var, struct frame_info *frame)
+{
+  const struct block *var_block = SYMBOL_BLOCK (var);
+  const struct block *frame_block;
+
+  if (!symbol_read_needs_frame (var))
+    return NULL;
+
+  /* Some symbols for local variables have no block: this happens when they are
+     not produced by a debug information reader, for instance when GDB creates
+     synthetic symbols.  Without block information, we must assume they are
+     local to FRAME. In this case, there is nothing to do.  */
+  else if (var_block == NULL)
+    return frame;
+
+  /* We currently assume that all symbols with a location list need a frame.
+     This is true in practice because selecting the location description
+     requires to compute the CFA, hence requires a frame.  However we have
+     tests that embed global/static symbols with null location lists.
+     We want to get <optimized out> instead of <frame required> when evaluating
+     them so return a frame instead of raising an error.  */
+  else if (var_block == block_global_block (var_block)
+	   || var_block == block_static_block (var_block))
+    return frame;
+
+  /* We have to handle the "my_func::my_local_var" notation.  This requires us
+     to look for upper frames when we find no block for the current frame: here
+     and below, handle when frame_block == NULL.  */
+  if (frame != NULL)
+    frame_block = get_frame_block (frame, NULL);
+
+  /* Climb up the call stack until reaching the frame we are looking for.  */
+  while (frame != NULL && frame_block != var_block)
+    {
+      /* Protect ourselves against bad things such as circular call stacks.  */
+      QUIT;
+
+      if (frame_block == NULL)
+	{
+	  frame = get_prev_frame (frame);
+	  if (frame == NULL)
+	    break;
+	  frame_block = get_frame_block (frame, NULL);
+	}
+
+      /* If we failed to find the proper frame, fallback to the heuristic
+	 method below.  */
+      else if (frame_block == block_global_block (frame_block))
+	{
+	  frame = NULL;
+	  break;
+	}
+
+      /* Assuming we have a block for this frame: if we are at the subprogram
+	 level, the immediate upper lexical block is in an outer subprogram:
+	 follow the static link.  */
+      else if (BLOCK_FUNCTION (frame_block))
+	{
+	  const struct dynamic_prop *static_link
+	    = BLOCK_STATIC_LINK (frame_block);
+	  int could_climb_up = 0;
+
+	  if (static_link != NULL)
+	    {
+	      frame = follow_static_link (frame, static_link);
+	      if (frame != NULL)
+		{
+		  frame_block = get_frame_block (frame, NULL);
+		  could_climb_up = frame_block != NULL;
+		}
+	    }
+	  if (!could_climb_up)
+	    {
+	      frame = NULL;
+	      break;
+	    }
+	}
+
+      else
+	/* We must be in some subprogram nested lexical block.  Just get the
+	   outer block: both must share the same frame.  */
+	frame_block = BLOCK_SUPERBLOCK (frame_block);
+    }
+
+  /* Old compilers may not provide a static link, or they may provide an
+     invalid one.  For such cases, fallback on the old way to evaluate
+     non-local references: just climb up the call stack and pick the first
+     frame that contains the variable we are looking for.  */
+  if (frame == NULL)
+    {
+      frame = block_innermost_frame (var_block);
+      if (!frame)
+	{
+	  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"));
+	}
+    }
+
+  return frame;
+}
+
 /* A default implementation for the "la_read_var_value" hook in
    the language vector which should work in most situations.  */
 
@@ -426,8 +581,8 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
      set the returned value type description correctly.  */
   check_typedef (type);
 
-  if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
+  if (frame != NULL)
+    frame = get_hosting_frame (var, frame);
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index a80151c..f6daaab 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1831,7 +1831,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
   gdb_assert (TYPE_CODE (dyn_range_type) == TYPE_CODE_RANGE);
 
   prop = &TYPE_RANGE_DATA (dyn_range_type)->low;
-  if (dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       low_bound.kind = PROP_CONST;
       low_bound.data.const_val = value;
@@ -1843,7 +1843,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
     }
 
   prop = &TYPE_RANGE_DATA (dyn_range_type)->high;
-  if (dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       high_bound.kind = PROP_CONST;
       high_bound.data.const_val = value;
@@ -2076,7 +2076,7 @@ resolve_dynamic_type_internal (struct type *type,
 
   /* Resolve data_location attribute.  */
   prop = TYPE_DATA_LOCATION (resolved_type);
-  if (dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       TYPE_DATA_LOCATION_ADDR (resolved_type) = value;
       TYPE_DATA_LOCATION_KIND (resolved_type) = PROP_CONST;
diff --git a/gdb/jit.c b/gdb/jit.c
index 712d1e2..0609842 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -706,6 +706,7 @@ finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile)
 					      strlen (gdb_block_iter->name));
 
       BLOCK_FUNCTION (new_block) = block_name;
+      BLOCK_STATIC_LINK (new_block) = NULL;
 
       BLOCKVECTOR_BLOCK (bv, i) = new_block;
       if (begin > BLOCK_START (new_block))
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index a3da678..487aadb 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -952,7 +952,7 @@ typy_template_argument (PyObject *self, PyObject *args)
 
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
-      val = value_of_variable (sym, block);
+      val = value_of_variable (sym);
     }
   GDB_PY_HANDLE_EXCEPTION (except);
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 0eb3a5b..4183934 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -665,6 +665,24 @@ struct symbol_block_ops
      uninitialized in such case.  */
   void (*find_frame_base_location) (struct symbol *framefunc, CORE_ADDR pc,
 				    const gdb_byte **start, size_t *length);
+
+  /* Return the frame base address.  FRAME is the frame for which we want to
+     compute the base address while FRAMEFUNC is the symbol for the
+     corresponding function.
+
+     This method is designed to work with static links (nested subprograms
+     handling).  Static links are function properties whose evaluation return
+     the frame base address for the enclosing frame.  However, there are
+     multiple definitions for "frame base": the content of the frame base
+     register, the CFA as defined by DWARF unwinding information, ...
+
+     So this specific method is supposed to compute the frame base address such
+     as for nested subprograms, the static link computes the same address.  For
+     instance, considering DWARF debugging information, the static link is
+     computed with DW_AT_static_link and this method must be used to compute
+     the corresponding DW_AT_frame_base attribute.  */
+  CORE_ADDR (*get_frame_base) (struct symbol *framefunc,
+			       struct frame_info *frame);
 };
 
 /* Functions used with LOC_REGISTER and LOC_REGPARM_ADDR.  */
@@ -711,6 +729,10 @@ struct symbol
 
   struct type *type;
 
+  /* The block this symbol lies in.  */
+
+  struct block *block;
+
   /* The owner of this symbol.
      Which one to use is defined by symbol.is_objfile_owned.  */
 
@@ -797,6 +819,7 @@ extern const struct symbol_impl *symbol_impls;
 #define SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION(symbol) \
   (symbol)->is_cplus_template_function
 #define SYMBOL_TYPE(symbol)		(symbol)->type
+#define SYMBOL_BLOCK(symbol)		(symbol)->block
 #define SYMBOL_LINE(symbol)		(symbol)->line
 #define SYMBOL_COMPUTED_OPS(symbol)	(SYMBOL_IMPL (symbol).ops_computed)
 #define SYMBOL_BLOCK_OPS(symbol)	(SYMBOL_IMPL (symbol).ops_block)
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..fc469fd
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.c
@@ -0,0 +1,35 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2015 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/>.  */
+
+int foo (int i1)
+{
+  int nested (int i2)
+  {
+    /* Here with i1 and i2, we can test that GDB can fetch both a local and a
+       non-local variable in the most simple nested subprogram situation: the
+       parent block instance is accessible as the directly upper frame.  */
+    return i1 * i2; /* STOP */
+  }
+
+  return nested (i1 + 1);
+}
+
+int
+main ()
+{
+  return !foo (1);
+}
diff --git a/gdb/testsuite/gdb.base/nested-subp1.exp b/gdb/testsuite/gdb.base/nested-subp1.exp
new file mode 100644
index 0000000..e2b8ed1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.exp
@@ -0,0 +1,58 @@
+# Copyright 2015 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/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested subprogram related functionality.
+#
+
+standard_testfile
+
+
+set testcase "nested-subp1"
+
+if { [gdb_compile "${srcdir}/${subdir}/${testcase}.c" \
+                  [standard_output_file "${testcase}"] \
+                  "${testcase}" \
+                  [list debug "additional_flags=-std=gnu99"]] != "" } {
+    return -1
+}
+
+
+# Run until the variables we are interested in are visible.
+
+clean_restart "${testcase}"
+if ![runto_main] {
+    perror "could not run to main"
+    continue
+}
+
+set bp_location [gdb_get_line_number "STOP" "${testcase}.c"]
+gdb_test "break ${testcase}.c:${bp_location}" \
+         "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
+         "breakpoint to the STOP marker"
+gdb_test "continue" \
+         "Breakpoint \[0-9\]+, nested .*" \
+         "continue to the STOP marker"
+
+
+# Check we get correct values for both local and non-local variable references.
+
+gdb_test "print i1" "1"
+gdb_test "print i2" "2"
diff --git a/gdb/testsuite/gdb.base/nested-subp2.c b/gdb/testsuite/gdb.base/nested-subp2.c
new file mode 100644
index 0000000..bfda0d2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.c
@@ -0,0 +1,45 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2015 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/>.  */
+
+void iter_str (const char *str, void (*callback) (char c))
+{
+  for (; *str != '\0'; ++str)
+    callback (*str);
+}
+
+int length_str (const char *str)
+{
+  int count = 0;
+
+  void increment (char c)
+  {
+    /* Here with COUNT, we can test that GDB can read a non-local variable even
+       though it's not directly in the upper stack frame.  */
+    count += 1; /* STOP */
+  }
+
+  iter_str (str, &increment);
+  return count;
+}
+
+int
+main ()
+{
+  if (length_str ("foo") == 3)
+    return 0;
+  return 1;
+}
diff --git a/gdb/testsuite/gdb.base/nested-subp2.exp b/gdb/testsuite/gdb.base/nested-subp2.exp
new file mode 100644
index 0000000..320061f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.exp
@@ -0,0 +1,67 @@
+# Copyright 2015 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/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested subprogram related functionality.
+#
+
+standard_testfile
+
+
+set testcase "nested-subp2"
+
+if { [gdb_compile "${srcdir}/${subdir}/${testcase}.c" \
+                  [standard_output_file "${testcase}"] \
+                  "${testcase}" \
+                  [list debug "additional_flags=-std=gnu99"]] != "" } {
+    return -1
+}
+
+
+# Run until the variables we are interested in are visible.
+
+clean_restart "${testcase}"
+if ![runto_main] {
+    perror "could not run to main"
+    continue
+}
+
+set bp_location [gdb_get_line_number "STOP" "${testcase}.c"]
+gdb_test "break ${testcase}.c:${bp_location}" \
+         "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
+         "breakpoint to the STOP marker"
+gdb_test "continue" \
+         "Breakpoint \[0-9\]+, increment .*" \
+         "continue to the STOP marker"
+
+
+# Check we get correct values for both local and non-local variable references.
+
+gdb_test "print c"     "102 'f'"
+gdb_test "print count" "0"
+
+
+# Same but a little later: make sure we were looking at the proper places.
+
+gdb_test "continue" \
+         "Breakpoint \[0-9\]+, increment .*" \
+         "continue to the STOP marker"
+gdb_test "print c"     "111 'o'"
+gdb_test "print count" "1"
diff --git a/gdb/testsuite/gdb.base/nested-subp3.c b/gdb/testsuite/gdb.base/nested-subp3.c
new file mode 100644
index 0000000..aea10f2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.c
@@ -0,0 +1,66 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2015 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/>.  */
+
+#include <stdlib.h>
+
+typedef void (*callback_t) (void);
+
+void process (callback_t cb);
+void parent (int first, callback_t cb);
+
+void
+ignore (int unused)
+{
+  (void) unused;
+}
+
+void
+process (callback_t cb)
+{
+  parent (0, cb);
+}
+
+void
+parent (int first, callback_t cb)
+{
+  void child (void)
+  {
+    /* When reaching this, there are two block instances for PARENT on the
+       stack: the one that is right in the upper frame is not the one actually
+       used for non-local references, so GDB has to follow the static link in
+       order to get the correct instance, and thus in order to read the proper
+       variables.
+
+       As a simple check, we can verify that under GDB, the following is true:
+       parent_first == first (which should be one: see the IF block below).  */
+    const int parent_first = first;
+    ignore (parent_first); /* STOP */
+    ignore (first);
+  }
+
+  if (first)
+    process (&child);
+  else
+    cb ();
+}
+
+int
+main ()
+{
+  parent (1, NULL);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/nested-subp3.exp b/gdb/testsuite/gdb.base/nested-subp3.exp
new file mode 100644
index 0000000..3630b55
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.exp
@@ -0,0 +1,60 @@
+# Copyright 2015 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/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested subprogram related functionality.
+#
+
+standard_testfile
+
+
+set testcase "nested-subp3"
+
+if { [gdb_compile "${srcdir}/${subdir}/${testcase}.c" \
+                  [standard_output_file "${testcase}"] \
+                  "${testcase}" \
+                  [list debug "additional_flags=-std=gnu99"]] != "" } {
+    return -1
+}
+
+
+# Run until the variables we are interested in are visible.
+
+clean_restart "${testcase}"
+if ![runto_main] {
+    perror "could not run to main"
+    continue
+}
+
+set bp_location [gdb_get_line_number "STOP" "${testcase}.c"]
+gdb_test "break ${testcase}.c:${bp_location}" \
+         "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
+         "breakpoint to the STOP marker"
+gdb_test "continue" \
+         "Breakpoint \[0-9\]+, child .*" \
+         "continue to the STOP marker"
+
+
+# Check we get correct values for both local and non-local variable references.
+
+# Note that in order to get the following test passing, one has to use a
+# patched GCC: see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53927>.
+gdb_test "print first"        "1"
+gdb_test "print parent_first" "1"
diff --git a/gdb/valarith.c b/gdb/valarith.c
index f33515c..f2162b7 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -305,7 +305,7 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
          expect a reference as its first argument
          rather the explicit structure.  */
       args[0] = value_ind (args[0]);
-      return value_of_variable (symp, 0);
+      return value_of_variable (symp);
     }
 
   error (_("Could not find %s."), operator);
diff --git a/gdb/valops.c b/gdb/valops.c
index 23a4b37..33d82ca 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -141,7 +141,7 @@ find_function_in_inferior (const char *name, struct objfile **objf_p)
       if (objf_p)
 	*objf_p = symbol_objfile (sym);
 
-      return value_of_variable (sym, NULL);
+      return value_of_variable (sym);
     }
   else
     {
@@ -1288,33 +1288,18 @@ value_repeat (struct value *arg1, int count)
 }
 
 struct value *
-value_of_variable (struct symbol *var, const struct block *b)
+value_of_variable (struct symbol *var)
 {
-  struct frame_info *frame;
+  struct frame_info *frame = NULL;
 
-  if (!symbol_read_needs_frame (var))
-    frame = NULL;
-  else if (!b)
+  if (symbol_read_needs_frame (var))
     frame = get_selected_frame (_("No frame selected."));
-  else
-    {
-      frame = block_innermost_frame (b);
-      if (!frame)
-	{
-	  if (BLOCK_FUNCTION (b) && !block_inlined_p (b)
-	      && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)))
-	    error (_("No frame is currently executing in block %s."),
-		   SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)));
-	  else
-	    error (_("No frame is currently executing in specified block"));
-	}
-    }
 
   return read_var_value (var, frame);
 }
 
 struct value *
-address_of_variable (struct symbol *var, const struct block *b)
+address_of_variable (struct symbol *var)
 {
   struct type *type = SYMBOL_TYPE (var);
   struct value *val;
@@ -1322,7 +1307,7 @@ address_of_variable (struct symbol *var, const struct block *b)
   /* Evaluate it first; if the result is a memory address, we're fine.
      Lazy evaluation pays off here.  */
 
-  val = value_of_variable (var, b);
+  val = value_of_variable (var);
   type = value_type (val);
 
   if ((VALUE_LVAL (val) == lval_memory && value_lazy (val))
@@ -3575,7 +3560,7 @@ value_maybe_namespace_elt (const struct type *curtype,
 	   && (SYMBOL_CLASS (sym) == LOC_TYPEDEF))
     result = allocate_value (SYMBOL_TYPE (sym));
   else
-    result = value_of_variable (sym, get_selected_block (0));
+    result = value_of_variable (sym);
 
   if (want_address)
     result = value_addr (result);
diff --git a/gdb/value.c b/gdb/value.c
index 9445f25..31565d7 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2916,7 +2916,7 @@ value_static_field (struct type *type, int fieldno)
 	    }
 	}
       else
-	retval = value_of_variable (sym, NULL);
+	retval = value_of_variable (sym);
       break;
     }
     default:
diff --git a/gdb/value.h b/gdb/value.h
index 21baa32..c77a864 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -657,11 +657,9 @@ extern struct value *value_from_register (struct type *type, int regnum,
 extern CORE_ADDR address_from_register (int regnum,
 					struct frame_info *frame);
 
-extern struct value *value_of_variable (struct symbol *var,
-					const struct block *b);
+extern struct value *value_of_variable (struct symbol *var);
 
-extern struct value *address_of_variable (struct symbol *var,
-					  const struct block *b);
+extern struct value *address_of_variable (struct symbol *var);
 
 extern struct value *value_of_register (int regnum, struct frame_info *frame);
 
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 6015711..d319188 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1388,7 +1388,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 		  break;
 		}
 
-	      finish_block (new->name, &local_symbols, new->old_blocks,
+	      finish_block (new->name, NULL, &local_symbols, new->old_blocks,
 			    new->start_addr,
 			    (fcn_cs_saved.c_value
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
-- 
2.3.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]