public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Add proper handling for non-local references in nested subprograms
@ 2015-03-02 14:36 Pierre-Marie de Rodat
  2015-03-10 15:26 ` Pedro Alves
  0 siblings, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-03-02 14:36 UTC (permalink / raw)
  To: GDB Patches

[-- Attachment #1: Type: text/plain, Size: 5250 bytes --]

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

[-- Attachment #2: 0001-Add-proper-handling-for-non-local-references-in-nest.patch --]
[-- Type: text/x-diff, Size: 49315 bytes --]

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


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested subprograms
  2015-03-02 14:36 [PATCH] Add proper handling for non-local references in nested subprograms Pierre-Marie de Rodat
@ 2015-03-10 15:26 ` Pedro Alves
  2015-03-20 12:24   ` [PATCH] Add proper handling for non-local references in nested functions Pierre-Marie de Rodat
  0 siblings, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-03-10 15:26 UTC (permalink / raw)
  To: Pierre-Marie de Rodat, GDB Patches

Hi Pierre-Marie,

I would have helped this reader to include an example of "non-local references
in nested subprograms" in the mail body :-)  Given the reference to
"subprograms" in the subject, I assumed this was an Ada-specific
patch.  I happened to skim the patch anyway, until I saw at the end
that this also handles C nested functions.  Nice!  :-)

On 03/02/2015 02:36 PM, Pierre-Marie de Rodat wrote:
> 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. :-)

Right, that's a problem.  We've been moving in the opposite direction...
The block knows which symbols it has inside.  When we look up symbols,
we always know which block we're searching the symbols in...  If
you need to know which block a symbol look up found a symbol in,
there's the "block_found" for that.  That's obviously an ugly hack, but
it's there and so you can use it.  If someone is motivated to clean this
up, it'd be better to make the symbol lookup functions return a
structure that included both symbol and block (and maybe more), in
the spirit of struct bound_minimal_symbol:

/* Several lookup functions return both a minimal symbol and the
   objfile in which it is found.  This structure is used in these
   cases.  */

struct bound_minimal_symbol
{
  /* The minimal symbol that was found, or NULL if no minimal symbol
     was found.  */

  struct minimal_symbol *minsym;

  /* If MINSYM is not NULL, then this is the objfile in which the
     symbol is defined.  */

  struct objfile *objfile;
};

For the block->static_link case, maybe put the static link chain
in a separate hash indexed by block?

> 
>      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?

Ah, yeah, something like that.  :-)

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-03-10 15:26 ` Pedro Alves
@ 2015-03-20 12:24   ` Pierre-Marie de Rodat
  2015-05-29 12:28     ` Pedro Alves
  0 siblings, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-03-20 12:24 UTC (permalink / raw)
  To: Pedro Alves, GDB Patches

[-- Attachment #1: Type: text/plain, Size: 8638 bytes --]

Pedro,

On 03/10/2015 04:25 PM, Pedro Alves wrote:
> I would have helped this reader to include an example of "non-local references
> in nested subprograms" in the mail body :-)  Given the reference to
> "subprograms" in the subject, I assumed this was an Ada-specific
> patch.  I happened to skim the patch anyway, until I saw at the end
> that this also handles C nested functions.  Nice!  :-)

Oh indeed, sorry about that! Being used to "subprogram" in the Ada 
world, I thought it was a better match, but never mind: I've replaced 
all occurences with "function" instead. Thanks for having had a look at 
the patch anyway. ;-)

> Right, that's a problem.  We've been moving in the opposite direction...
> The block knows which symbols it has inside.  When we look up symbols,
> we always know which block we're searching the symbols in...  If
> you need to know which block a symbol look up found a symbol in,
> there's the "block_found" for that.  That's obviously an ugly hack, but
> it's there and so you can use it.

I knew about the "block_found" alternative: I nevertheless tried to 
avoid it because I believed it was a better design to attach this 
information to symbols themselves... but of course runtime performance 
matters too. The updated patch switched to the "block_found" way: it 
makes the patch more complex but indeed it does not make the the symbol 
structure grow.

I left TODO's in the patch, though: in the Python user interface (for 
instance in Frame.read_var), we sometimes accept gdb.Symbol objects and 
end up reading the corresponding variables. In such cases, we cannot use 
block_found since the lookup was done possibly a long time before; on 
the other hand there's almost always a gdb.Block argument around, so I 
guess we expect Python developpers to keep track of blocks corresponding 
to their symbols... which sounds wrong to me. It's okay for performance 
not to store blocks in GDB internal symbols data structures but on the 
other hand I don't think we should expose this design tweak in a public API.

I did not try it because it implies a kind of API change: what about 
storing the origin block in gdb.Symbol instances? My guess is that the 
size of gdb.Symbol is not as critical as for struct symbol. The block 
arguments in the Python API would then be used only when a string is 
passed instead of a gdb.Symbol. This would also fix the problem we still 
have for gdb.Symbol.value, which does not take any block argument. Thoughts?

> If someone is motivated to clean this up, it'd be better to make the
> symbol lookup functions return a structure that included both symbol
> and block (and maybe more), in the spirit of struct
> bound_minimal_symbol:

This would look cleaner indeed. It's a big change itself though so if 
most consider this as a good idea I don't mind doing it... although it 
would be for another commit!

> For the block->static_link case, maybe put the static link chain
> in a separate hash indexed by block?

This is what I did in the updated patch: I don't think there's a 
realistic use case for gdbarch-owned block having a static link so I 
added a hashed table to all objfiles. It's indexed by blocks and 
contains static links for these (if they have one). Then we perform 
lookups when reading variables...

Thank you for your review, Pedro! :-)

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

         * ada-lang.c (ada_read_var_value): Add a VAR_BLOCK argument and 
pass
         it to default_read_var_value.
         * block.c (block_static_link): New accessor.
         * block.h (block_static_link): Declare it.
         * buildsym.c (finish_block_internal): Add a static_link
         argument.  If there is a static link, associate it to the new
         block.
         (finish_block): Add a static link argument and pass it to
         finish_block_internal.
         (end_symtab_get_static_block): Update calls to finish_block and
         to finish_block_internal.
         (end_symtab_with_blockvector): Update call to
         finish_block_internal.
         * buildsym.h: Forward-declare struct dynamic_prop.
         (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.
         * compile/compile-c-symbols.c (convert_one_symbol): Add a
         VAR_BLOCK parameter and pass it to calls to read_var_value.
         (convert_symbol_sym): Pass the block corresponding to SYM to the
         call to convert_one_symbol.
         * compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
         call to read_var_value.
         * 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.
         * findvar.c (follow_static_link): New.
         (get_hosting_frame): New.
         (default_read_var_value): Add a VAR_BLOCK argument.  Use
         get_hosting_frame to handle non-local references.
         (read_var_value): Add a VAR_BLOCK argument and pass it to the
         LA_READ_VAR_VALUE method.
         * gdbtypes.c (resolve_dynamic_range): Update calls to
         dwarf2_evaluate_property.
         (resolve_dynamic_type_internal): Likewise.
         * infcmd.c (finish_command_continuation): Update call to
         read_var_value.
         * infrun.c (insert_exception_resume_breakpoint): Likewise.
         * language.h (struct language_defn): Add a VAR_BLOCK argument to
         the LA_READ_VAR_VALUE method.
         * objfiles.c (objfile_register_static_link): New.
         (objfile_lookup_static_link): New.
         (free_objfile): Free the STATIC_LINKS hashed map if needed.
         * objfiles.h: Include hashtab.h.
         (struct objfile): Add a STATIC_LINKS field.
         (objfile_register_static_link): New.
         (objfile_lookup_static_link): New.
         * printcmd.c (print_variable_and_value): Update call to
         read_var_value.
         * python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
         * python/py-frame.c (frapy_read_var): Pass the block found to
         read_var_value.
         * python/py-framefilter.c (extract_sym): Add a SYM_BLOCK
         parameter and set the pointed value to NULL (TODO).
         (enumerate_args): Update call to extract_sym.
         (enumerate_locals): Update calls to extract_sym and to
         read_var_value.
         * python/py-symbol.c (sympy_value): Update call to
         read_var_value (TODO).
         * stack.c (read_frame_local): Update call to read_var_value.
         (read_frame_arg): Likewise.
         (return_command): Likewise.
         * symtab.h (struct symbol_block_ops): Add a get_frame_base
         method.
         (struct symbol): Add a block field.
         (SYMBOL_BLOCK): New accessor.
         * valops.c (find_function_in_inferior): Pass the block found to
         value_of_variable.
         (value_of_variable): Remove frame/block handling and pass the
         block argument to read_var_value, which does this job now.
         (value_struct_elt_for_reference): Update calls to
         read_var_value.
         (value_of_this): Pass the block found to read_var_value.
         * value.c (value_static_field): Likewise.
         * value.h (read_var_value): Add a VAR_BLOCK argument.
         (default_read_var_value): Likewise.

gdb/testsuite/ChangeLog:
2015-03-20  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

[-- Attachment #2: 0001-DWARF-handle-non-local-references-in-nested-function.patch --]
[-- Type: text/x-diff, Size: 65580 bytes --]

From 24b0a788e642e892b5efb467bed627c7585662a7 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] DWARF: handle non-local references in nested functions

GDB's current behavior when dealing with non-local references in the
context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
references.

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

	* ada-lang.c (ada_read_var_value): Add a VAR_BLOCK argument and pass
	it to default_read_var_value.
	* block.c (block_static_link): New accessor.
	* block.h (block_static_link): Declare it.
	* buildsym.c (finish_block_internal): Add a static_link
	argument.  If there is a static link, associate it to the new
	block.
	(finish_block): Add a static link argument and pass it to
	finish_block_internal.
	(end_symtab_get_static_block): Update calls to finish_block and
	to finish_block_internal.
	(end_symtab_with_blockvector): Update call to
	finish_block_internal.
	* buildsym.h: Forward-declare struct dynamic_prop.
	(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.
	* compile/compile-c-symbols.c (convert_one_symbol): Add a
	VAR_BLOCK parameter and pass it to calls to read_var_value.
	(convert_symbol_sym): Pass the block corresponding to SYM to the
	call to convert_one_symbol.
	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
	call to read_var_value.
	* 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.
	* findvar.c (follow_static_link): New.
	(get_hosting_frame): New.
	(default_read_var_value): Add a VAR_BLOCK argument.  Use
	get_hosting_frame to handle non-local references.
	(read_var_value): Add a VAR_BLOCK argument and pass it to the
	LA_READ_VAR_VALUE method.
	* gdbtypes.c (resolve_dynamic_range): Update calls to
	dwarf2_evaluate_property.
	(resolve_dynamic_type_internal): Likewise.
	* infcmd.c (finish_command_continuation): Update call to
	read_var_value.
	* infrun.c (insert_exception_resume_breakpoint): Likewise.
	* language.h (struct language_defn): Add a VAR_BLOCK argument to
	the LA_READ_VAR_VALUE method.
	* objfiles.c (objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	(free_objfile): Free the STATIC_LINKS hashed map if needed.
	* objfiles.h: Include hashtab.h.
	(struct objfile): Add a STATIC_LINKS field.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	* printcmd.c (print_variable_and_value): Update call to
	read_var_value.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
	* python/py-frame.c (frapy_read_var): Pass the block found to
	read_var_value.
	* python/py-framefilter.c (extract_sym): Add a SYM_BLOCK
	parameter and set the pointed value to NULL (TODO).
	(enumerate_args): Update call to extract_sym.
	(enumerate_locals): Update calls to extract_sym and to
	read_var_value.
	* python/py-symbol.c (sympy_value): Update call to
	read_var_value (TODO).
	* stack.c (read_frame_local): Update call to read_var_value.
	(read_frame_arg): Likewise.
	(return_command): Likewise.
	* symtab.h (struct symbol_block_ops): Add a get_frame_base
	method.
	(struct symbol): Add a block field.
	(SYMBOL_BLOCK): New accessor.
	* valops.c (find_function_in_inferior): Pass the block found to
	value_of_variable.
	(value_of_variable): Remove frame/block handling and pass the
	block argument to read_var_value, which does this job now.
	(value_struct_elt_for_reference): Update calls to
	read_var_value.
	(value_of_this): Pass the block found to read_var_value.
	* value.c (value_static_field): Likewise.
	* value.h (read_var_value): Add a VAR_BLOCK argument.
	(default_read_var_value): Likewise.

gdb/testsuite/ChangeLog:
2015-03-20  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                          |   5 +-
 gdb/block.c                             |  13 +++
 gdb/block.h                             |   2 +
 gdb/buildsym.c                          |  17 ++--
 gdb/buildsym.h                          |  14 ++-
 gdb/coffread.c                          |   4 +-
 gdb/compile/compile-c-symbols.c         |  18 ++--
 gdb/compile/compile-loc2c.c             |   2 +-
 gdb/dbxread.c                           |   8 +-
 gdb/dwarf2loc.c                         |  52 ++++++++--
 gdb/dwarf2loc.h                         |  11 ++-
 gdb/dwarf2read.c                        |  19 +++-
 gdb/findvar.c                           | 168 +++++++++++++++++++++++++++++++-
 gdb/gdbtypes.c                          |   6 +-
 gdb/infcmd.c                            |   2 +-
 gdb/infrun.c                            |   2 +-
 gdb/language.h                          |  12 ++-
 gdb/objfiles.c                          |  36 +++++++
 gdb/objfiles.h                          |  18 ++++
 gdb/printcmd.c                          |   6 +-
 gdb/python/py-finishbreakpoint.c        |   2 +-
 gdb/python/py-frame.c                   |   5 +-
 gdb/python/py-framefilter.c             |  28 ++++--
 gdb/python/py-symbol.c                  |   5 +-
 gdb/stack.c                             |   8 +-
 gdb/symtab.h                            |  18 ++++
 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/valops.c                            |  33 ++-----
 gdb/value.c                             |   3 +-
 gdb/value.h                             |   2 +
 gdb/xcoffread.c                         |   4 +-
 36 files changed, 758 insertions(+), 96 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 124e370..a88d7c1 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13625,7 +13625,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
 /* Implement the "la_read_var_value" language_defn method for Ada.  */
 
 static struct value *
-ada_read_var_value (struct symbol *var, struct frame_info *frame)
+ada_read_var_value (struct symbol *var, const struct block *var_block,
+		    struct frame_info *frame)
 {
   const struct block *frame_block = NULL;
   struct symbol *renaming_sym = NULL;
@@ -13641,7 +13642,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
 
   /* This is a typical case where we expect the default_read_var_value
      function to work.  */
-  return default_read_var_value (var, frame);
+  return default_read_var_value (var, var_block, frame);
 }
 
 const struct language_defn ada_language_defn = {
diff --git a/gdb/block.c b/gdb/block.c
index 00a7012..db2e868 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -428,6 +428,19 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
   gb->compunit_symtab = cu;
 }
 
+struct dynamic_prop *
+block_static_link (const struct block *block)
+{
+  struct objfile *objfile = block_objfile (block);
+
+  /* Only objfile-owned blocks that materialize top function scopes can have
+     static links.  */
+  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
+    return NULL;
+
+  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
+}
+
 /* Return the compunit of the global block.  */
 
 static struct compunit_symtab *
diff --git a/gdb/block.h b/gdb/block.h
index bdc5888..5f0ccf3 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -190,6 +190,8 @@ extern struct block *allocate_global_block (struct obstack *obstack);
 extern void set_block_compunit_symtab (struct block *,
 				       struct compunit_symtab *);
 
+extern struct dynamic_prop *block_static_link (const struct block *block);
+
 /* A block iterator.  This structure should be treated as though it
    were opaque; it is only defined here because we want to support
    stack allocation of iterators.  */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 2a24a25..a2be2cb 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)
@@ -422,6 +423,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
       BLOCK_FUNCTION (block) = NULL;
     }
 
+  if (static_link != NULL)
+    objfile_register_static_link (objfile, block, static_link);
+
   /* Now "free" the links of the list, and empty the list.  */
 
   for (next = *listhead; next; next = next1)
@@ -512,11 +516,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 +1223,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 +1294,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 +1322,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..8828ad2 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -39,6 +39,8 @@ struct compunit_symtab;
 struct block;
 struct pending_block;
 
+struct dynamic_prop;
+
 #ifndef EXTERN
 #define	EXTERN extern
 #endif
@@ -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 28f7b18..894271c 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 (newobj->name, &local_symbols,
+	      finish_block (newobj->name, NULL, &local_symbols,
 			    newobj->old_blocks, newobj->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, newobj->old_blocks,
+		  finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 				newobj->start_addr, tmpaddr);
 		}
 	      /* Now pop locals of block just finished.  */
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 15efeff..88fc65e 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -135,16 +135,16 @@ symbol_substitution_name (struct symbol *sym)
   return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
 }
 
-/* Convert a given symbol, SYM, to the compiler's representation.
-   CONTEXT is the compiler instance.  IS_GLOBAL is true if the
-   symbol came from the global scope.  IS_LOCAL is true if the symbol
-   came from a local scope.  (Note that the two are not strictly
-   inverses because the symbol might have come from the static
-   scope.)  */
+/* Convert a given symbol, SYM (located in VAR_BLOCK, if any), to the
+   compiler's representation.  CONTEXT is the compiler instance.  IS_GLOBAL is
+   true if the symbol came from the global scope.  IS_LOCAL is true if the
+   symbol came from a local scope.  (Note that the two are not strictly
+   inverses because the symbol might have come from the static scope.)  */
 
 static void
 convert_one_symbol (struct compile_c_instance *context,
 		    struct symbol *sym,
+		    const struct block *var_block,
 		    int is_global,
 		    int is_local)
 {
@@ -248,7 +248,7 @@ convert_one_symbol (struct compile_c_instance *context,
 			 SYMBOL_PRINT_NAME (sym));
 	      }
 
-	    val = read_var_value (sym, frame);
+	    val = read_var_value (sym, var_block, frame);
 	    if (VALUE_LVAL (val) != lval_memory)
 	      error (_("Symbol \"%s\" cannot be used for compilation "
 		       "evaluation as its address has not been found."),
@@ -341,7 +341,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
 	    fprintf_unfiltered (gdb_stdout,
 				"gcc_convert_symbol \"%s\": global symbol\n",
 				identifier);
-	  convert_one_symbol (context, global_sym, 1, 0);
+	  convert_one_symbol (context, global_sym, NULL, 1, 0);
 	}
     }
 
@@ -349,7 +349,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
     fprintf_unfiltered (gdb_stdout,
 			"gcc_convert_symbol \"%s\": local symbol\n",
 			identifier);
-  convert_one_symbol (context, sym, 0, is_local_symbol);
+  convert_one_symbol (context, sym, found_block, 0, is_local_symbol);
 }
 
 /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 6a3615d..192671b 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -632,7 +632,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
 		 "there is no selected frame"),
 	       SYMBOL_PRINT_NAME (sym));
 
-      val = read_var_value (sym, frame);
+      val = read_var_value (sym, NULL, frame);
       if (VALUE_LVAL (val) != lval_memory)
 	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		 "as its address has not been found."),
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index c8f974f..1b92fed 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2782,8 +2782,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 	  newobj = pop_context ();
 
 	  /* Make a block for the local symbols within.  */
-	  block = finish_block (newobj->name, &local_symbols,
-				newobj->old_blocks,
+	  block = finish_block (newobj->name, NULL,
+				&local_symbols, newobj->old_blocks,
 				newobj->start_addr, newobj->start_addr + valu);
 
 	  /* For C++, set the block's scope.  */
@@ -2884,7 +2884,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj->start_addr = valu;
 		}
 	      /* Make a block for the local symbols within.  */
-	      finish_block (0, &local_symbols, newobj->old_blocks,
+	      finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 			    newobj->start_addr, valu);
 	    }
 	}
@@ -3186,7 +3186,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 
 		  newobj = pop_context ();
 		  /* Make a block for the local symbols within.  */
-		  block = finish_block (newobj->name, &local_symbols,
+		  block = finish_block (newobj->name, NULL, &local_symbols,
 					newobj->old_blocks, newobj->start_addr,
 					valu);
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index e674933..f0b8a14 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.  */
@@ -2397,13 +2428,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)
 {
@@ -2418,7 +2450,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;
 
@@ -2462,19 +2494,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)
@@ -2491,7 +2528,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 c185d51..8a1a3c7 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1728,6 +1728,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 *);
@@ -11363,6 +11367,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (attr)
     dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
 
+  /* If there is a location for the static link, record it.  */
+  newobj->static_link = NULL;
+  attr = dwarf2_attr (die, DW_AT_static_link, cu);
+  if (attr)
+    {
+      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
+					sizeof (*newobj->static_link));
+      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
+    }
+
   cu->list_in_scope = &local_symbols;
 
   if (die->child != NULL)
@@ -11413,7 +11427,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 
   newobj = pop_context ();
   /* Make a block for the local symbols within.  */
-  block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+  block = finish_block (newobj->name, &newobj->static_link,
+			&local_symbols, newobj->old_blocks,
                         lowpc, highpc);
 
   /* For C++, set the block's scope.  */
@@ -11496,7 +11511,7 @@ 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, newobj->old_blocks,
+        = finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 			newobj->start_addr, highpc);
 
       /* Note that recording ranges after traversing children, as we
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 128bf5e..5443b70 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,11 +410,166 @@ 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
+   functions.
+
+   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, const struct block *var_block,
+		   struct frame_info *frame)
+{
+  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 function
+	 level, the immediate upper lexical block is in an outer function:
+	 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 function 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.  */
 
 struct value *
-default_read_var_value (struct symbol *var, struct frame_info *frame)
+default_read_var_value (struct symbol *var, const struct block *var_block,
+			struct frame_info *frame)
 {
   struct value *v;
   struct type *type = SYMBOL_TYPE (var);
@@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
   check_typedef (type);
 
   if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
+    gdb_assert (frame != NULL);
+
+  if (frame != NULL)
+    frame = get_hosting_frame (var, var_block, frame);
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
@@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
 /* Calls VAR's language la_read_var_value hook with the given arguments.  */
 
 struct value *
-read_var_value (struct symbol *var, struct frame_info *frame)
+read_var_value (struct symbol *var, const struct block *var_block,
+		struct frame_info *frame)
 {
   const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
 
   gdb_assert (lang != NULL);
   gdb_assert (lang->la_read_var_value != NULL);
 
-  return lang->la_read_var_value (var, frame);
+  return lang->la_read_var_value (var, var_block, frame);
 }
 
 /* Install default attributes for register values.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 4cbbe95..93faca2 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1835,7 +1835,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;
@@ -1847,7 +1847,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;
@@ -2080,7 +2080,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/infcmd.c b/gdb/infcmd.c
index 0211b5d..cbdce47 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1671,7 +1671,7 @@ finish_command_continuation (void *arg, int err)
 	    {
 	      struct value *func;
 
-	      func = read_var_value (a->function, get_current_frame ());
+	      func = read_var_value (a->function, NULL, get_current_frame ());
 	      TRY
 		{
 		  /* print_return_value can throw an exception in some
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 0f8f531..1beed93 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6038,7 +6038,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
       struct breakpoint *bp;
 
       vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
-      value = read_var_value (vsym, frame);
+      value = read_var_value (vsym, NULL, frame);
       /* If the value was optimized out, revert to the old behavior.  */
       if (! value_optimized_out (value))
 	{
diff --git a/gdb/language.h b/gdb/language.h
index 436fd6e..1ab0699 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -241,13 +241,19 @@ struct language_defn
     void (*la_value_print) (struct value *, struct ui_file *,
 			    const struct value_print_options *);
 
-    /* Given a symbol VAR, and a stack frame id FRAME, read the value
-       of the variable an return (pointer to a) struct value containing
-       the value.
+    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
+       stack frame id FRAME, read the value of the variable and return (pointer
+       to a) struct value containing the value.
+
+       VAR_BLOCK is needed there's a possibility for VAR to be outside FRAME.
+       This is what happens if FRAME correspond to a nested function and VAR is
+       defined in the outer function.  If callers know that VAR is located in
+       FRAME, NULL can be passed as VAR_BLOCK.
 
        Throw an error if the variable cannot be found.  */
 
     struct value *(*la_read_var_value) (struct symbol *var,
+					const struct block *var_block,
 					struct frame_info *frame);
 
     /* PC is possibly an unknown languages trampoline.
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index ff20bc8..152626f 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -199,6 +199,37 @@ set_objfile_main_name (struct objfile *objfile,
   objfile->per_bfd->language_of_main = lang;
 }
 
+/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
+   Must not be called more than once for each BLOCK.  */
+
+void
+objfile_register_static_link (struct objfile *objfile,
+			      const struct block *block,
+			      struct dynamic_prop *static_link)
+{
+  void **slot;
+
+  if (objfile->static_links == NULL)
+    objfile->static_links = htab_create_alloc
+      (1, htab_hash_pointer, htab_eq_pointer, NULL, xcalloc, xfree);
+
+  slot = htab_find_slot (objfile->static_links, block, INSERT);
+  gdb_assert (*slot == NULL);
+  *slot = static_link;
+}
+
+/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
+   none was found.  */
+
+struct dynamic_prop *
+objfile_lookup_static_link (struct objfile *objfile,
+			    const struct block *block)
+{
+  if (objfile->static_links == NULL)
+    return NULL;
+  return htab_find (objfile->static_links, block);
+}
+
 \f
 
 /* Called via bfd_map_over_sections to build up the section table that
@@ -652,6 +683,11 @@ free_objfile (struct objfile *objfile)
   /* Rebuild section map next time we need it.  */
   get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
 
+  /* Free the map for static links.  There's no need to free static link
+     themselves since they were allocated on the objstack.  */
+  if (objfile->static_links != NULL)
+    htab_delete (objfile->static_links);
+
   /* The last thing we do is free the objfile struct itself.  */
   xfree (objfile);
 }
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a0dc69b..aa2e966 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -20,6 +20,7 @@
 #if !defined (OBJFILES_H)
 #define OBJFILES_H
 
+#include "hashtab.h"
 #include "gdb_obstack.h"	/* For obstack internals.  */
 #include "symfile.h"		/* For struct psymbol_allocation_list.  */
 #include "progspace.h"
@@ -412,6 +413,16 @@ struct objfile
        table, so we have to keep them here to relocate them
        properly.  */
     struct symbol *template_symbols;
+
+    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
+       block *) that have one.  For nested functions, the static link is the
+       expression that computes the frame base of the lexically enclosing
+       function.
+
+       Very few blocks have a static link, so it's more memory efficient to
+       store these here.  Static links must be allocated on the objfile's
+       obstack.  */
+    struct htab *static_links;
   };
 
 /* Defines for the objfile flag word.  */
@@ -719,4 +730,11 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
 extern void set_objfile_main_name (struct objfile *objfile,
 				   const char *name, enum language lang);
 
+extern void objfile_register_static_link (struct objfile *objfile,
+					  const struct block *block,
+					  struct dynamic_prop *static_link);
+
+extern struct dynamic_prop *objfile_lookup_static_link
+  (struct objfile *objfile, const struct block *block);
+
 #endif /* !defined (OBJFILES_H) */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 05c68a0..46a8c9d 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1990,7 +1990,11 @@ print_variable_and_value (const char *name, struct symbol *var,
       struct value *val;
       struct value_print_options opts;
 
-      val = read_var_value (var, frame);
+      /* READ_VAR_VALUE needs a block in order to deal with non-local
+	 references (i.e. to handlee nested functions). In this context, we
+	 print variables that are local to this frame, so we can avoid passing
+	 a block to it.  */
+      val = read_var_value (var, NULL, frame);
       get_user_print_options (&opts);
       opts.deref_ref = 1;
       common_val_print (val, stream, indent, &opts, current_language);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index 34e9643..9dca373 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -262,7 +262,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  func_value = read_var_value (function, frame);
+                  func_value = read_var_value (function, NULL, frame);
                   self_bpfinish->function_value =
                       value_to_value_object (func_value);
                   PyErr_Clear ();
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index cd6e859..270c570 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
   struct frame_info *frame;
   PyObject *sym_obj, *block_obj = NULL;
   struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
+  const struct block *block = NULL;
   struct value *val = NULL;
 
   if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
@@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
   else if (gdbpy_is_string (sym_obj))
     {
       char *var_name;
-      const struct block *block = NULL;
       struct cleanup *cleanup;
 
       var_name = python_string_to_target_string (sym_obj);
@@ -541,6 +541,7 @@ frapy_read_var (PyObject *self, PyObject *args)
 	  if (!block)
 	    block = get_frame_block (frame, NULL);
 	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  block = block_found;
 	}
       CATCH (except, RETURN_MASK_ALL)
 	{
@@ -572,7 +573,7 @@ frapy_read_var (PyObject *self, PyObject *args)
     {
       FRAPY_REQUIRE_VALID (self, frame);
 
-      val = read_var_value (var, frame);
+      val = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index e3336b1..397ac86 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -43,16 +43,17 @@ enum mi_print_types
    NAME is a  pass-through argument where the name of  the symbol will
    be written.  NAME is allocated in  this function, but the caller is
    responsible for clean up.  SYM is a pass-through argument where the
-   symbol will be written.  In the case of the API returning a string,
-   this will be set to NULL.  LANGUAGE is also a pass-through argument
-   denoting the language attributed to the Symbol.  In the case of SYM
-   being  NULL, this  will be  set to  the current  language.  Returns
-   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
-   EXT_LANG_BT_OK on success.  */
+   symbol will be written and  SYM_BLOCK is a pass-through argument to
+   write  the block where the symbol lies in.  In the case of the  API
+   returning a  string,  this will be set to NULL.  LANGUAGE is also a
+   pass-through  argument  denoting  the  language  attributed  to the
+   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
+   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
+   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
 
 static enum ext_lang_bt_status
 extract_sym (PyObject *obj, char **name, struct symbol **sym,
-	     const struct language_defn **language)
+	     struct block **sym_block, const struct language_defn **language)
 {
   PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
 
@@ -75,12 +76,17 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
 	python_language.  */
       *language = python_language;
       *sym = NULL;
+      *sym_block = NULL;
     }
   else
     {
       /* This type checks 'result' during the conversion so we
 	 just call it unconditionally and check the return.  */
       *sym = symbol_object_to_symbol (result);
+      /* TODO:  How should we find the corresponding block for this symbol?
+	 Should we lookup all blocks in the owning objfile?  Should we store
+	 the bloc kin the Symbol object?  */
+      *sym_block = NULL;
 
       Py_DECREF (result);
 
@@ -537,10 +543,11 @@ enumerate_args (PyObject *iter,
       const struct language_defn *language;
       char *sym_name;
       struct symbol *sym;
+      struct block *sym_block;
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  Py_DECREF (item);
@@ -736,12 +743,13 @@ enumerate_locals (PyObject *iter,
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
       struct symbol *sym;
+      struct block *sym_block;
       int local_indent = 8 + (8 * indent);
       struct cleanup *locals_cleanups;
 
       locals_cleanups = make_cleanup_py_decref (item);
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  do_cleanups (locals_cleanups);
@@ -769,7 +777,7 @@ enumerate_locals (PyObject *iter,
 	{
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, sym_block, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 4306f61..c8f7ecc 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -278,7 +278,10 @@ sympy_value (PyObject *self, PyObject *args)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO:  How should we find the corresponding block for this symbol?
+	 Should we lookup all blocks in the owning objfile?  Should we store
+	 the bloc kin the Symbol object?  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/stack.c b/gdb/stack.c
index 76a2360..ffaac3c 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -320,7 +320,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
 
   TRY
     {
-      argp->val = read_var_value (sym, frame);
+      argp->val = read_var_value (sym, NULL, frame);
     }
   CATCH (except, RETURN_MASK_ERROR)
     {
@@ -346,7 +346,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
     {
       TRY
 	{
-	  val = read_var_value (sym, frame);
+	  val = read_var_value (sym, NULL, frame);
 	}
       CATCH (except, RETURN_MASK_ERROR)
 	{
@@ -473,7 +473,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
 
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, NULL, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
@@ -2450,7 +2450,7 @@ return_command (char *retval_exp, int from_tty)
 	value_fetch_lazy (return_value);
 
       if (thisfun != NULL)
-	function = read_var_value (thisfun, thisframe);
+	function = read_var_value (thisfun, NULL, thisframe);
 
       rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
       if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 6a0b8da..c18bf9c 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 functions
+     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 fuctions, 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.  */
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..afae926
--- /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 function 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..d2a8013
--- /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 functions 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..9694959
--- /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 functions 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..0d2c50c
--- /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 functions 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/valops.c b/gdb/valops.c
index 66c63c1..b82eff2 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -132,6 +132,7 @@ find_function_in_inferior (const char *name, struct objfile **objf_p)
   sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
   if (sym != NULL)
     {
+      const struct block *b = block_found;
       if (SYMBOL_CLASS (sym) != LOC_BLOCK)
 	{
 	  error (_("\"%s\" exists in this program but is not a function."),
@@ -141,7 +142,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, b);
     }
   else
     {
@@ -1290,27 +1291,12 @@ value_repeat (struct value *arg1, int count)
 struct value *
 value_of_variable (struct symbol *var, const struct block *b)
 {
-  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);
+  return read_var_value (var, b, frame);
 }
 
 struct value *
@@ -3462,9 +3448,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 		return NULL;
 
 	      if (want_address)
-		return value_addr (read_var_value (s, 0));
+		return value_addr (read_var_value (s, 0, 0));
 	      else
-		return read_var_value (s, 0);
+		return read_var_value (s, 0, 0);
 	    }
 
 	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -3492,7 +3478,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 	      if (s == NULL)
 		return NULL;
 
-	      v = read_var_value (s, 0);
+	      v = read_var_value (s, 0, 0);
 	      if (!want_address)
 		result = v;
 	      else
@@ -3740,11 +3726,12 @@ value_of_this (const struct language_defn *lang)
   b = get_frame_block (frame, NULL);
 
   sym = lookup_language_this (lang, b);
+  b = block_found;
   if (sym == NULL)
     error (_("current stack frame does not contain a variable named `%s'"),
 	   lang->la_name_of_this);
 
-  return read_var_value (sym, frame);
+  return read_var_value (sym, b, frame);
 }
 
 /* Return the value of the local variable, if one exists.  Return NULL
diff --git a/gdb/value.c b/gdb/value.c
index cb56849..e33bab6 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2905,6 +2905,7 @@ value_static_field (struct type *type, int fieldno)
       const char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
       /* TYPE_FIELD_NAME (type, fieldno); */
       struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0);
+      const struct block *b = block_found;
 
       if (sym == NULL)
 	{
@@ -2922,7 +2923,7 @@ value_static_field (struct type *type, int fieldno)
 	    }
 	}
       else
-	retval = value_of_variable (sym, NULL);
+	retval = value_of_variable (sym, b);
       break;
     }
     default:
diff --git a/gdb/value.h b/gdb/value.h
index 21baa32..9f9e7c6 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -670,9 +670,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
 extern int symbol_read_needs_frame (struct symbol *);
 
 extern struct value *read_var_value (struct symbol *var,
+				     const struct block *var_block,
 				     struct frame_info *frame);
 
 extern struct value *default_read_var_value (struct symbol *var,
+					     const struct block *var_block,
 					     struct frame_info *frame);
 
 extern struct value *allocate_value (struct type *type);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 3cb6eda..e8265c8 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1388,8 +1388,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 		  break;
 		}
 
-	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-			    newobj->start_addr,
+	      finish_block (newobj->name, NULL, &local_symbols,
+			    newobj->old_blocks, newobj->start_addr,
 			    (fcn_cs_saved.c_value
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
 			     + ANOFFSET (objfile->section_offsets,
-- 
2.3.3


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-03-20 12:24   ` [PATCH] Add proper handling for non-local references in nested functions Pierre-Marie de Rodat
@ 2015-05-29 12:28     ` Pedro Alves
  2015-06-09 21:46       ` Pierre-Marie de Rodat
  0 siblings, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-05-29 12:28 UTC (permalink / raw)
  To: Pierre-Marie de Rodat, GDB Patches

On 03/20/2015 12:24 PM, Pierre-Marie de Rodat wrote:

>> > If someone is motivated to clean this up, it'd be better to make the
>> > symbol lookup functions return a structure that included both symbol
>> > and block (and maybe more), in the spirit of struct
>> > bound_minimal_symbol:
> This would look cleaner indeed. It's a big change itself though so if 
> most consider this as a good idea I don't mind doing it... although it 
> would be for another commit!

I would think it great if someone did that.  :-)

> 
>> > For the block->static_link case, maybe put the static link chain
>> > in a separate hash indexed by block?
> This is what I did in the updated patch: I don't think there's a 
> realistic use case for gdbarch-owned block having a static link so I 
> added a hashed table to all objfiles. It's indexed by blocks and 
> contains static links for these (if they have one). Then we perform 
> lookups when reading variables...
> 
> Thank you for your review, Pedro! :-)
> 

Thanks for the update, and sorry about the delay.

This overall looks very reasonable to me.  It's fine with me to
let the core changes in, and address Python API issues separately.

> diff --git a/gdb/block.c b/gdb/block.c
> index 00a7012..db2e868 100644
> --- a/gdb/block.c
> +++ b/gdb/block.c
> @@ -428,6 +428,19 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
>    gb->compunit_symtab = cu;
>  }
>  

Add:

/* See block.h.  */

> +struct dynamic_prop *
> +block_static_link (const struct block *block)
> +{

...

> diff --git a/gdb/block.h b/gdb/block.h
> index bdc5888..5f0ccf3 100644
> --- a/gdb/block.h
> +++ b/gdb/block.h
> @@ -190,6 +190,8 @@ extern struct block *allocate_global_block (struct obstack *obstack);
>  extern void set_block_compunit_symtab (struct block *,
>  				       struct compunit_symtab *);
>  
> +extern struct dynamic_prop *block_static_link (const struct block *block);
> +

It'd be great if you could skim over the patch add any missing
function intro comments.  You've already done a good job at that,
I think only here and there missed it.

> diff --git a/gdb/language.h b/gdb/language.h
> index 436fd6e..1ab0699 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -241,13 +241,19 @@ struct language_defn
>      void (*la_value_print) (struct value *, struct ui_file *,
>  			    const struct value_print_options *);
>  
> -    /* Given a symbol VAR, and a stack frame id FRAME, read the value
> -       of the variable an return (pointer to a) struct value containing
> -       the value.
> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
> +       stack frame id FRAME, read the value of the variable and return (pointer
> +       to a) struct value containing the value.
> +
> +       VAR_BLOCK is needed there's a possibility for VAR to be outside FRAME.

I think an "if" is missing after "needed".

> +       This is what happens if FRAME correspond to a nested function and VAR is
> +       defined in the outer function.  If callers know that VAR is located in
> +       FRAME, NULL can be passed as VAR_BLOCK.



> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -1990,7 +1990,11 @@ print_variable_and_value (const char *name, struct symbol *var,
>        struct value *val;
>        struct value_print_options opts;
>  
> -      val = read_var_value (var, frame);
> +      /* READ_VAR_VALUE needs a block in order to deal with non-local
> +	 references (i.e. to handlee nested functions). In this context, we

typo "handle".  Double space after period.


> +# Please email any bugs, comments, and/or additions to this file to:
> +# bug-gdb@gnu.org

It no longer makes sense to add this email address to tests.  Please
drop it (here and elsewhere).

> +void iter_str (const char *str, void (*callback) (char c))

Could you make this follow GNU formatting?  That is:

void
iter_str (const char *str, void (*callback) (char c))

Here and elsewhere.

> +int
> +main ()

int
main (void)

(more cases).

> +
> +# 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"

Please make this XFAIL instead of FAIL with unpatched GCC.

Otherwise looks good to me.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-05-29 12:28     ` Pedro Alves
@ 2015-06-09 21:46       ` Pierre-Marie de Rodat
  2015-07-22  9:16         ` Pierre-Marie de Rodat
  0 siblings, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-06-09 21:46 UTC (permalink / raw)
  To: Pedro Alves, GDB Patches

Pedro,

On 05/29/2015 02:28 PM, Pedro Alves wrote:
>> This would look cleaner indeed. It's a big change itself though so if
>> most consider this as a good idea I don't mind doing it... although it
>> would be for another commit!
>
> I would think it great if someone did that.  :-)

Okay... I may give it a try, then. ;-)

> Thanks for the update, and sorry about the delay.

No problem. I probably won't be able to resume my work on this until 
July, so more delay is to be expected. :-/ The good news is that then, 
my GCC patches to fix the corresponding DWARF may be integrated. :-)

> This overall looks very reasonable to me.  It's fine with me to
> let the core changes in, and address Python API issues separately.

Understood, thanks.

> Add:
>
> /* See block.h.  */

I will.

> It'd be great if you could skim over the patch add any missing
> function intro comments.  You've already done a good job at that,
> I think only here and there missed it.

Will double-check and fix.

>> +       VAR_BLOCK is needed there's a possibility for VAR to be outside FRAME.
>
> I think an "if" is missing after "needed".

Absolutely.

>> -      val = read_var_value (var, frame);
>> +      /* READ_VAR_VALUE needs a block in order to deal with non-local
>> +	 references (i.e. to handlee nested functions). In this context, we
>
> typo "handle".  Double space after period.

Will fix.

>> +# Please email any bugs, comments, and/or additions to this file to:
>> +# bug-gdb@gnu.org
>
> It no longer makes sense to add this email address to tests.  Please
> drop it (here and elsewhere).

Sure.

>> +void iter_str (const char *str, void (*callback) (char c))
>
> Could you make this follow GNU formatting?  That is:
>
> void
> iter_str (const char *str, void (*callback) (char c))
>
> Here and elsewhere.

I will.

>> +
>> +# 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"
>
> Please make this XFAIL instead of FAIL with unpatched GCC.
>
> Otherwise looks good to me.

Ok. Thank you again for the review!

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-06-09 21:46       ` Pierre-Marie de Rodat
@ 2015-07-22  9:16         ` Pierre-Marie de Rodat
  2015-07-22 14:26           ` Doug Evans
  2015-07-23  1:36           ` Kevin Buettner
  0 siblings, 2 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-22  9:16 UTC (permalink / raw)
  To: Pedro Alves, GDB Patches

[-- Attachment #1: Type: text/plain, Size: 1244 bytes --]

On 06/09/2015 11:46 PM, Pierre-Marie de Rodat wrote:
> On 05/29/2015 02:28 PM, Pedro Alves wrote:
>>> This would look cleaner indeed. It's a big change itself though so if
>>> most consider this as a good idea I don't mind doing it... although it
>>> would be for another commit!
>>
>> I would think it great if someone did that.  :-)
>
> Okay... I may give it a try, then. ;-)

Here it is! 
<https://sourceware.org/ml/gdb-patches/2015-07/msg00607.html> I just 
rebased my work on non-local references on top of this cleanup and 
performed the changes you asked me to do. Just a question:

>> It'd be great if you could skim over the patch add any missing
>> function intro comments.  You've already done a good job at that,
>> I think only here and there missed it.

What I usually do is to put comments in front of function definitions 
and leave function declarations without them in the header. It's 
generally what I observe in the sources, but since sometimes the 
documentation is in the header file, it happens that I do the same: I 
try to stay consistent with nearby code. ;-) Please tell me if you want 
me to do something different.

Regtested again on x86_64-linux: no regression. Ok to push? Thank you!

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-DWARF-handle-non-local-references-in-nested-function.patch --]
[-- Type: text/x-diff, Size: 64789 bytes --]

From 8cf3a675c44dcccd54f64db47b7baea637c250ea 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] DWARF: handle non-local references in nested functions

GDB's current behavior when dealing with non-local references in the
context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
references.

gdb/ChangeLog:

	* ada-lang.c (ada_read_var_value): Add a VAR_BLOCK argument and pass
	it to default_read_var_value.
	* block.c (block_static_link): New accessor.
	* block.h (block_static_link): Declare it.
	* buildsym.c (finish_block_internal): Add a static_link
	argument.  If there is a static link, associate it to the new
	block.
	(finish_block): Add a static link argument and pass it to
	finish_block_internal.
	(end_symtab_get_static_block): Update calls to finish_block and
	to finish_block_internal.
	(end_symtab_with_blockvector): Update call to
	finish_block_internal.
	* buildsym.h: Forward-declare struct dynamic_prop.
	(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.
	* compile/compile-c-symbols.c (convert_one_symbol): Add a
	VAR_BLOCK parameter and pass it to calls to read_var_value.
	(convert_symbol_sym): Pass the block corresponding to SYM to the
	call to convert_one_symbol.
	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
	call to read_var_value.
	* 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.
	* findvar.c (follow_static_link): New.
	(get_hosting_frame): New.
	(default_read_var_value): Add a VAR_BLOCK argument.  Use
	get_hosting_frame to handle non-local references.
	(read_var_value): Add a VAR_BLOCK argument and pass it to the
	LA_READ_VAR_VALUE method.
	* gdbtypes.c (resolve_dynamic_range): Update calls to
	dwarf2_evaluate_property.
	(resolve_dynamic_type_internal): Likewise.
	* infcmd.c (finish_command_continuation): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* infrun.c (insert_exception_resume_breakpoint): Likewise.
	* language.h (struct language_defn): Add a VAR_BLOCK argument to
	the LA_READ_VAR_VALUE method.
	* objfiles.c (objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	(free_objfile): Free the STATIC_LINKS hashed map if needed.
	* objfiles.h: Include hashtab.h.
	(struct objfile): Add a STATIC_LINKS field.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	* printcmd.c (print_variable_and_value): Update call to
	read_var_value.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
	* python/py-frame.c (frapy_read_var): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* python/py-framefilter.c (extract_sym): Add a SYM_BLOCK
	parameter and set the pointed value to NULL (TODO).
	(enumerate_args): Update call to extract_sym.
	(enumerate_locals): Update calls to extract_sym and to
	read_var_value.
	* python/py-symbol.c (sympy_value): Update call to
	read_var_value (TODO).
	* stack.c (read_frame_local): Update call to read_var_value.
	(read_frame_arg): Likewise.
	(return_command): Likewise.
	* symtab.h (struct symbol_block_ops): Add a get_frame_base
	method.
	(struct symbol): Add a block field.
	(SYMBOL_BLOCK): New accessor.
	* valops.c (value_of_variable): Remove frame/block handling and
	pass the block argument to read_var_value, which does this job
	now.
	(value_struct_elt_for_reference): Update calls to
	read_var_value.
	(value_of_this): Pass the block found to read_var_value.
	* value.h (read_var_value): Add a VAR_BLOCK argument.
	(default_read_var_value): Likewise.

gdb/testsuite/ChangeLog:

	* 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                          |   5 +-
 gdb/block.c                             |  15 +++
 gdb/block.h                             |   6 ++
 gdb/buildsym.c                          |  17 ++--
 gdb/buildsym.h                          |  14 ++-
 gdb/coffread.c                          |   4 +-
 gdb/compile/compile-c-symbols.c         |  19 ++--
 gdb/compile/compile-loc2c.c             |   2 +-
 gdb/dbxread.c                           |   8 +-
 gdb/dwarf2loc.c                         |  52 ++++++++--
 gdb/dwarf2loc.h                         |  11 ++-
 gdb/dwarf2read.c                        |  19 +++-
 gdb/findvar.c                           | 168 +++++++++++++++++++++++++++++++-
 gdb/gdbtypes.c                          |   7 +-
 gdb/infcmd.c                            |   2 +-
 gdb/infrun.c                            |   7 +-
 gdb/language.h                          |  12 ++-
 gdb/objfiles.c                          |  36 +++++++
 gdb/objfiles.h                          |  18 ++++
 gdb/printcmd.c                          |   6 +-
 gdb/python/py-finishbreakpoint.c        |   2 +-
 gdb/python/py-frame.c                   |   9 +-
 gdb/python/py-framefilter.c             |  28 ++++--
 gdb/python/py-symbol.c                  |   5 +-
 gdb/stack.c                             |   8 +-
 gdb/symtab.h                            |  18 ++++
 gdb/testsuite/gdb.base/nested-subp1.c   |  37 +++++++
 gdb/testsuite/gdb.base/nested-subp1.exp |  55 +++++++++++
 gdb/testsuite/gdb.base/nested-subp2.c   |  48 +++++++++
 gdb/testsuite/gdb.base/nested-subp2.exp |  64 ++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.c   |  66 +++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.exp |  55 +++++++++++
 gdb/valops.c                            |  35 ++-----
 gdb/value.h                             |   2 +
 gdb/xcoffread.c                         |   4 +-
 35 files changed, 763 insertions(+), 101 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 ded195f..5c43a7a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13750,7 +13750,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
 /* Implement the "la_read_var_value" language_defn method for Ada.  */
 
 static struct value *
-ada_read_var_value (struct symbol *var, struct frame_info *frame)
+ada_read_var_value (struct symbol *var, const struct block *var_block,
+		    struct frame_info *frame)
 {
   const struct block *frame_block = NULL;
   struct symbol *renaming_sym = NULL;
@@ -13766,7 +13767,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
 
   /* This is a typical case where we expect the default_read_var_value
      function to work.  */
-  return default_read_var_value (var, frame);
+  return default_read_var_value (var, var_block, frame);
 }
 
 const struct language_defn ada_language_defn = {
diff --git a/gdb/block.c b/gdb/block.c
index f7621aa..f4b8e4f 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
   gb->compunit_symtab = cu;
 }
 
+/* See block.h.  */
+
+struct dynamic_prop *
+block_static_link (const struct block *block)
+{
+  struct objfile *objfile = block_objfile (block);
+
+  /* Only objfile-owned blocks that materialize top function scopes can have
+     static links.  */
+  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
+    return NULL;
+
+  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
+}
+
 /* Return the compunit of the global block.  */
 
 static struct compunit_symtab *
diff --git a/gdb/block.h b/gdb/block.h
index d8ad343..6e7d247 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -190,6 +190,12 @@ extern struct block *allocate_global_block (struct obstack *obstack);
 extern void set_block_compunit_symtab (struct block *,
 				       struct compunit_symtab *);
 
+/* Return a property to evaluate the static link associated to BLOCK.  Note
+   that only objfile-owned and function-level blocks can have a static link.
+   Return NULL if there is no such property.  */
+
+extern struct dynamic_prop *block_static_link (const struct block *block);
+
 /* A block iterator.  This structure should be treated as though it
    were opaque; it is only defined here because we want to support
    stack allocation of iterators.  */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 2a24a25..a2be2cb 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)
@@ -422,6 +423,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
       BLOCK_FUNCTION (block) = NULL;
     }
 
+  if (static_link != NULL)
+    objfile_register_static_link (objfile, block, static_link);
+
   /* Now "free" the links of the list, and empty the list.  */
 
   for (next = *listhead; next; next = next1)
@@ -512,11 +516,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 +1223,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 +1294,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 +1322,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..8828ad2 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -39,6 +39,8 @@ struct compunit_symtab;
 struct block;
 struct pending_block;
 
+struct dynamic_prop;
+
 #ifndef EXTERN
 #define	EXTERN extern
 #endif
@@ -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 7722cdb..e41e9a5 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1144,7 +1144,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
 		enter_linenos (fcn_line_ptr, fcn_first_line,
 			       fcn_last_line, objfile);
 
-	      finish_block (newobj->name, &local_symbols,
+	      finish_block (newobj->name, NULL, &local_symbols,
 			    newobj->old_blocks, newobj->start_addr,
 			    fcn_cs_saved.c_value
 			    + fcn_aux_saved.x_sym.x_misc.x_fsize
@@ -1188,7 +1188,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, newobj->old_blocks,
+		  finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 				newobj->start_addr, tmpaddr);
 		}
 	      /* Now pop locals of block just finished.  */
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 5f27583..f1dfccf 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -134,16 +134,16 @@ symbol_substitution_name (struct symbol *sym)
   return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
 }
 
-/* Convert a given symbol, SYM, to the compiler's representation.
-   CONTEXT is the compiler instance.  IS_GLOBAL is true if the
-   symbol came from the global scope.  IS_LOCAL is true if the symbol
-   came from a local scope.  (Note that the two are not strictly
-   inverses because the symbol might have come from the static
-   scope.)  */
+/* Convert a given symbol, SYM (located in VAR_BLOCK, if any), to the
+   compiler's representation.  CONTEXT is the compiler instance.  IS_GLOBAL is
+   true if the symbol came from the global scope.  IS_LOCAL is true if the
+   symbol came from a local scope.  (Note that the two are not strictly
+   inverses because the symbol might have come from the static scope.)  */
 
 static void
 convert_one_symbol (struct compile_c_instance *context,
 		    struct symbol *sym,
+		    const struct block *var_block,
 		    int is_global,
 		    int is_local)
 {
@@ -247,7 +247,7 @@ convert_one_symbol (struct compile_c_instance *context,
 			 SYMBOL_PRINT_NAME (sym));
 	      }
 
-	    val = read_var_value (sym, frame);
+	    val = read_var_value (sym, var_block, frame);
 	    if (VALUE_LVAL (val) != lval_memory)
 	      error (_("Symbol \"%s\" cannot be used for compilation "
 		       "evaluation as its address has not been found."),
@@ -339,7 +339,8 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
 	    fprintf_unfiltered (gdb_stdlog,
 				"gcc_convert_symbol \"%s\": global symbol\n",
 				identifier);
-	  convert_one_symbol (context, global_sym.symbol, 1, 0);
+	  convert_one_symbol (context, global_sym.symbol, global_sym.block, 1,
+			      0);
 	}
     }
 
@@ -347,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
     fprintf_unfiltered (gdb_stdlog,
 			"gcc_convert_symbol \"%s\": local symbol\n",
 			identifier);
-  convert_one_symbol (context, sym, 0, is_local_symbol);
+  convert_one_symbol (context, sym, block, 0, is_local_symbol);
 }
 
 /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 6f53814..18ca4ae 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
 		 "there is no selected frame"),
 	       SYMBOL_PRINT_NAME (sym));
 
-      val = read_var_value (sym, frame);
+      val = read_var_value (sym, NULL, frame);
       if (VALUE_LVAL (val) != lval_memory)
 	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		 "as its address has not been found."),
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 6098b35..32893f6 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2766,8 +2766,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 	  newobj = pop_context ();
 
 	  /* Make a block for the local symbols within.  */
-	  block = finish_block (newobj->name, &local_symbols,
-				newobj->old_blocks,
+	  block = finish_block (newobj->name, NULL,
+				&local_symbols, newobj->old_blocks,
 				newobj->start_addr, newobj->start_addr + valu);
 
 	  /* For C++, set the block's scope.  */
@@ -2868,7 +2868,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj->start_addr = valu;
 		}
 	      /* Make a block for the local symbols within.  */
-	      finish_block (0, &local_symbols, newobj->old_blocks,
+	      finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 			    newobj->start_addr, valu);
 	    }
 	}
@@ -3165,7 +3165,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 
 		  newobj = pop_context ();
 		  /* Make a block for the local symbols within.  */
-		  block = finish_block (newobj->name, &local_symbols,
+		  block = finish_block (newobj->name, NULL, &local_symbols,
 					newobj->old_blocks, newobj->start_addr,
 					valu);
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index c75767e..edfa220 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 f3630ac..2415656 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -122,12 +122,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 f440956..e20aead 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1736,6 +1736,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 *);
@@ -11393,6 +11397,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (attr)
     dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
 
+  /* If there is a location for the static link, record it.  */
+  newobj->static_link = NULL;
+  attr = dwarf2_attr (die, DW_AT_static_link, cu);
+  if (attr)
+    {
+      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
+					sizeof (*newobj->static_link));
+      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
+    }
+
   cu->list_in_scope = &local_symbols;
 
   if (die->child != NULL)
@@ -11443,7 +11457,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 
   newobj = pop_context ();
   /* Make a block for the local symbols within.  */
-  block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+  block = finish_block (newobj->name, &newobj->static_link,
+			&local_symbols, newobj->old_blocks,
                         lowpc, highpc);
 
   /* For C++, set the block's scope.  */
@@ -11529,7 +11544,7 @@ 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, newobj->old_blocks,
+        = finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 			newobj->start_addr, highpc);
 
       /* Note that recording ranges after traversing children, as we
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 2079b4b..2f2f092 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,11 +410,166 @@ 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
+   functions.
+
+   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, const struct block *var_block,
+		   struct frame_info *frame)
+{
+  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 function
+	 level, the immediate upper lexical block is in an outer function:
+	 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 function 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.  */
 
 struct value *
-default_read_var_value (struct symbol *var, struct frame_info *frame)
+default_read_var_value (struct symbol *var, const struct block *var_block,
+			struct frame_info *frame)
 {
   struct value *v;
   struct type *type = SYMBOL_TYPE (var);
@@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
   check_typedef (type);
 
   if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
+    gdb_assert (frame != NULL);
+
+  if (frame != NULL)
+    frame = get_hosting_frame (var, var_block, frame);
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
@@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
 /* Calls VAR's language la_read_var_value hook with the given arguments.  */
 
 struct value *
-read_var_value (struct symbol *var, struct frame_info *frame)
+read_var_value (struct symbol *var, const struct block *var_block,
+		struct frame_info *frame)
 {
   const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
 
   gdb_assert (lang != NULL);
   gdb_assert (lang->la_read_var_value != NULL);
 
-  return lang->la_read_var_value (var, frame);
+  return lang->la_read_var_value (var, var_block, frame);
 }
 
 /* Install default attributes for register values.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index be761e6..fe6af7c 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1874,7 +1874,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;
@@ -1886,7 +1886,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;
@@ -2128,7 +2128,8 @@ resolve_dynamic_type_internal (struct type *type,
 
   /* Resolve data_location attribute.  */
   prop = TYPE_DATA_LOCATION (resolved_type);
-  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (prop != NULL
+      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       TYPE_DYN_PROP_ADDR (prop) = value;
       TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4948d27..2872292 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1660,7 +1660,7 @@ finish_command_continuation (void *arg, int err)
 	    {
 	      struct value *func;
 
-	      func = read_var_value (a->function, get_current_frame ());
+	      func = read_var_value (a->function, NULL, get_current_frame ());
 	      TRY
 		{
 		  /* print_return_value can throw an exception in some
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9a46242..0844823 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6082,14 +6082,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
 {
   TRY
     {
-      struct symbol *vsym;
+      struct symbol_in_block vsym;
       struct value *value;
       CORE_ADDR handler;
       struct breakpoint *bp;
 
-      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
-			    NULL).symbol;
-      value = read_var_value (vsym, frame);
+      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+      value = read_var_value (vsym.symbol, vsym.block, frame);
       /* If the value was optimized out, revert to the old behavior.  */
       if (! value_optimized_out (value))
 	{
diff --git a/gdb/language.h b/gdb/language.h
index 2675b82..ea8442f 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -241,13 +241,19 @@ struct language_defn
     void (*la_value_print) (struct value *, struct ui_file *,
 			    const struct value_print_options *);
 
-    /* Given a symbol VAR, and a stack frame id FRAME, read the value
-       of the variable an return (pointer to a) struct value containing
-       the value.
+    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
+       stack frame id FRAME, read the value of the variable and return (pointer
+       to a) struct value containing the value.
+
+       VAR_BLOCK is needed if there's a possibility for VAR to be outside
+       FRAME.  This is what happens if FRAME correspond to a nested function
+       and VAR is defined in the outer function.  If callers know that VAR is
+       located in FRAME, NULL can be passed as VAR_BLOCK.
 
        Throw an error if the variable cannot be found.  */
 
     struct value *(*la_read_var_value) (struct symbol *var,
+					const struct block *var_block,
 					struct frame_info *frame);
 
     /* PC is possibly an unknown languages trampoline.
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index c6f9f00..7fbf702 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -199,6 +199,37 @@ set_objfile_main_name (struct objfile *objfile,
   objfile->per_bfd->language_of_main = lang;
 }
 
+/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
+   Must not be called more than once for each BLOCK.  */
+
+void
+objfile_register_static_link (struct objfile *objfile,
+			      const struct block *block,
+			      struct dynamic_prop *static_link)
+{
+  void **slot;
+
+  if (objfile->static_links == NULL)
+    objfile->static_links = htab_create_alloc
+      (1, htab_hash_pointer, htab_eq_pointer, NULL, xcalloc, xfree);
+
+  slot = htab_find_slot (objfile->static_links, block, INSERT);
+  gdb_assert (*slot == NULL);
+  *slot = static_link;
+}
+
+/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
+   none was found.  */
+
+struct dynamic_prop *
+objfile_lookup_static_link (struct objfile *objfile,
+			    const struct block *block)
+{
+  if (objfile->static_links == NULL)
+    return NULL;
+  return htab_find (objfile->static_links, block);
+}
+
 \f
 
 /* Called via bfd_map_over_sections to build up the section table that
@@ -653,6 +684,11 @@ free_objfile (struct objfile *objfile)
   /* Rebuild section map next time we need it.  */
   get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
 
+  /* Free the map for static links.  There's no need to free static link
+     themselves since they were allocated on the objstack.  */
+  if (objfile->static_links != NULL)
+    htab_delete (objfile->static_links);
+
   /* The last thing we do is free the objfile struct itself.  */
   xfree (objfile);
 }
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a0dc69b..aa2e966 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -20,6 +20,7 @@
 #if !defined (OBJFILES_H)
 #define OBJFILES_H
 
+#include "hashtab.h"
 #include "gdb_obstack.h"	/* For obstack internals.  */
 #include "symfile.h"		/* For struct psymbol_allocation_list.  */
 #include "progspace.h"
@@ -412,6 +413,16 @@ struct objfile
        table, so we have to keep them here to relocate them
        properly.  */
     struct symbol *template_symbols;
+
+    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
+       block *) that have one.  For nested functions, the static link is the
+       expression that computes the frame base of the lexically enclosing
+       function.
+
+       Very few blocks have a static link, so it's more memory efficient to
+       store these here.  Static links must be allocated on the objfile's
+       obstack.  */
+    struct htab *static_links;
   };
 
 /* Defines for the objfile flag word.  */
@@ -719,4 +730,11 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
 extern void set_objfile_main_name (struct objfile *objfile,
 				   const char *name, enum language lang);
 
+extern void objfile_register_static_link (struct objfile *objfile,
+					  const struct block *block,
+					  struct dynamic_prop *static_link);
+
+extern struct dynamic_prop *objfile_lookup_static_link
+  (struct objfile *objfile, const struct block *block);
+
 #endif /* !defined (OBJFILES_H) */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f51e25c..553cc71 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
       struct value *val;
       struct value_print_options opts;
 
-      val = read_var_value (var, frame);
+      /* READ_VAR_VALUE needs a block in order to deal with non-local
+	 references (i.e. to handle nested functions).  In this context, we
+	 print variables that are local to this frame, so we can avoid passing
+	 a block to it.  */
+      val = read_var_value (var, NULL, frame);
       get_user_print_options (&opts);
       opts.deref_ref = 1;
       common_val_print (val, stream, indent, &opts, current_language);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index e3d4867..345642e 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  func_value = read_var_value (function, frame);
+                  func_value = read_var_value (function, NULL, frame);
                   self_bpfinish->function_value =
                       value_to_value_object (func_value);
                   PyErr_Clear ();
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 7290056..fa7937a 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
   struct frame_info *frame;
   PyObject *sym_obj, *block_obj = NULL;
   struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
+  const struct block *block = NULL;
   struct value *val = NULL;
 
   if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
@@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
   else if (gdbpy_is_string (sym_obj))
     {
       char *var_name;
-      const struct block *block = NULL;
       struct cleanup *cleanup;
 
       var_name = python_string_to_target_string (sym_obj);
@@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
 
       TRY
 	{
+	  struct symbol_in_block lookup_sym;
 	  FRAPY_REQUIRE_VALID (self, frame);
 
 	  if (!block)
 	    block = get_frame_block (frame, NULL);
-	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  var = lookup_sym.symbol;
+	  block = lookup_sym.block;
 	}
       CATCH (except, RETURN_MASK_ALL)
 	{
@@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
     {
       FRAPY_REQUIRE_VALID (self, frame);
 
-      val = read_var_value (var, frame);
+      val = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index e3336b1..397ac86 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -43,16 +43,17 @@ enum mi_print_types
    NAME is a  pass-through argument where the name of  the symbol will
    be written.  NAME is allocated in  this function, but the caller is
    responsible for clean up.  SYM is a pass-through argument where the
-   symbol will be written.  In the case of the API returning a string,
-   this will be set to NULL.  LANGUAGE is also a pass-through argument
-   denoting the language attributed to the Symbol.  In the case of SYM
-   being  NULL, this  will be  set to  the current  language.  Returns
-   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
-   EXT_LANG_BT_OK on success.  */
+   symbol will be written and  SYM_BLOCK is a pass-through argument to
+   write  the block where the symbol lies in.  In the case of the  API
+   returning a  string,  this will be set to NULL.  LANGUAGE is also a
+   pass-through  argument  denoting  the  language  attributed  to the
+   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
+   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
+   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
 
 static enum ext_lang_bt_status
 extract_sym (PyObject *obj, char **name, struct symbol **sym,
-	     const struct language_defn **language)
+	     struct block **sym_block, const struct language_defn **language)
 {
   PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
 
@@ -75,12 +76,17 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
 	python_language.  */
       *language = python_language;
       *sym = NULL;
+      *sym_block = NULL;
     }
   else
     {
       /* This type checks 'result' during the conversion so we
 	 just call it unconditionally and check the return.  */
       *sym = symbol_object_to_symbol (result);
+      /* TODO:  How should we find the corresponding block for this symbol?
+	 Should we lookup all blocks in the owning objfile?  Should we store
+	 the bloc kin the Symbol object?  */
+      *sym_block = NULL;
 
       Py_DECREF (result);
 
@@ -537,10 +543,11 @@ enumerate_args (PyObject *iter,
       const struct language_defn *language;
       char *sym_name;
       struct symbol *sym;
+      struct block *sym_block;
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  Py_DECREF (item);
@@ -736,12 +743,13 @@ enumerate_locals (PyObject *iter,
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
       struct symbol *sym;
+      struct block *sym_block;
       int local_indent = 8 + (8 * indent);
       struct cleanup *locals_cleanups;
 
       locals_cleanups = make_cleanup_py_decref (item);
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  do_cleanups (locals_cleanups);
@@ -769,7 +777,7 @@ enumerate_locals (PyObject *iter,
 	{
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, sym_block, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 401e7e9..b58e59d 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -278,7 +278,10 @@ sympy_value (PyObject *self, PyObject *args)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO: How should we find the corresponding block for this symbol?
+	 Should we lookup all blocks in the owning objfile?  Should we store
+	 the block in the Symbol object?  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/stack.c b/gdb/stack.c
index b4cfdbd..5a18a06 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
 
   TRY
     {
-      argp->val = read_var_value (sym, frame);
+      argp->val = read_var_value (sym, NULL, frame);
     }
   CATCH (except, RETURN_MASK_ERROR)
     {
@@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
     {
       TRY
 	{
-	  val = read_var_value (sym, frame);
+	  val = read_var_value (sym, NULL, frame);
 	}
       CATCH (except, RETURN_MASK_ERROR)
 	{
@@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
 
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, NULL, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
@@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
 	value_fetch_lazy (return_value);
 
       if (thisfun != NULL)
-	function = read_var_value (thisfun, thisframe);
+	function = read_var_value (thisfun, NULL, thisframe);
 
       rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
       if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 73026b3..509537b 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 functions
+     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 fuctions, 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.  */
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..967eb2f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.c
@@ -0,0 +1,37 @@
+/* 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 function 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..9720f5b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a6449e34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.c
@@ -0,0 +1,48 @@
+/* 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..a107d1c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.exp
@@ -0,0 +1,64 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a51f417
--- /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);
+
+extern void process (callback_t cb);
+extern 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..8f9b522
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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.
+
+gdb_test "print first"        "1"
+gdb_test "print parent_first" "1"
diff --git a/gdb/valops.c b/gdb/valops.c
index d326f93..94182c5 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1288,27 +1288,12 @@ value_repeat (struct value *arg1, int count)
 struct value *
 value_of_variable (struct symbol *var, const struct block *b)
 {
-  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);
+  return read_var_value (var, b, frame);
 }
 
 struct value *
@@ -3459,9 +3444,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 		return NULL;
 
 	      if (want_address)
-		return value_addr (read_var_value (s, 0));
+		return value_addr (read_var_value (s, 0, 0));
 	      else
-		return read_var_value (s, 0);
+		return read_var_value (s, 0, 0);
 	    }
 
 	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -3489,7 +3474,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 	      if (s == NULL)
 		return NULL;
 
-	      v = read_var_value (s, 0);
+	      v = read_var_value (s, 0, 0);
 	      if (!want_address)
 		result = v;
 	      else
@@ -3725,7 +3710,7 @@ value_full_object (struct value *argp,
 struct value *
 value_of_this (const struct language_defn *lang)
 {
-  struct symbol *sym;
+  struct symbol_in_block sym;
   const struct block *b;
   struct frame_info *frame;
 
@@ -3736,12 +3721,12 @@ value_of_this (const struct language_defn *lang)
 
   b = get_frame_block (frame, NULL);
 
-  sym = lookup_language_this (lang, b).symbol;
-  if (sym == NULL)
+  sym = lookup_language_this (lang, b);
+  if (sym.symbol == NULL)
     error (_("current stack frame does not contain a variable named `%s'"),
 	   lang->la_name_of_this);
 
-  return read_var_value (sym, frame);
+  return read_var_value (sym.symbol, sym.block, frame);
 }
 
 /* Return the value of the local variable, if one exists.  Return NULL
diff --git a/gdb/value.h b/gdb/value.h
index 7ff6aa8..c35a876 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -670,9 +670,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
 extern int symbol_read_needs_frame (struct symbol *);
 
 extern struct value *read_var_value (struct symbol *var,
+				     const struct block *var_block,
 				     struct frame_info *frame);
 
 extern struct value *default_read_var_value (struct symbol *var,
+					     const struct block *var_block,
 					     struct frame_info *frame);
 
 extern struct value *allocate_value (struct type *type);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index b5b2a1d..dea24a4 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1388,8 +1388,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 		  break;
 		}
 
-	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-			    newobj->start_addr,
+	      finish_block (newobj->name, NULL, &local_symbols,
+			    newobj->old_blocks, newobj->start_addr,
 			    (fcn_cs_saved.c_value
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
 			     + ANOFFSET (objfile->section_offsets,
-- 
2.4.5


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-22  9:16         ` Pierre-Marie de Rodat
@ 2015-07-22 14:26           ` Doug Evans
  2015-07-22 15:14             ` Pierre-Marie de Rodat
  2015-07-22 17:58             ` Kevin Buettner
  2015-07-23  1:36           ` Kevin Buettner
  1 sibling, 2 replies; 40+ messages in thread
From: Doug Evans @ 2015-07-22 14:26 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Pedro Alves, GDB Patches

On Wed, Jul 22, 2015 at 2:16 AM, Pierre-Marie de Rodat
<derodat@adacore.com> wrote:
> On 06/09/2015 11:46 PM, Pierre-Marie de Rodat wrote:
>>
>> On 05/29/2015 02:28 PM, Pedro Alves wrote:
>>>>
>>>> This would look cleaner indeed. It's a big change itself though so if
>>>> most consider this as a good idea I don't mind doing it... although it
>>>> would be for another commit!
>>>
>>>
>>> I would think it great if someone did that.  :-)
>>
>>
>> Okay... I may give it a try, then. ;-)
>
>
> Here it is! <https://sourceware.org/ml/gdb-patches/2015-07/msg00607.html> I
> just rebased my work on non-local references on top of this cleanup and
> performed the changes you asked me to do. Just a question:
>
>>> It'd be great if you could skim over the patch add any missing
>>> function intro comments.  You've already done a good job at that,
>>> I think only here and there missed it.
>
>
> What I usually do is to put comments in front of function definitions and
> leave function declarations without them in the header. It's generally what
> I observe in the sources, but since sometimes the documentation is in the
> header file, it happens that I do the same: I try to stay consistent with
> nearby code. ;-) Please tell me if you want me to do something different.
>
> Regtested again on x86_64-linux: no regression. Ok to push? Thank you!

Hi.

Ditto.  Others may approve this, but give me a chance to review it too.

One thought that comes to mind when reading the patch is that
you introduce the term "static link", and it doesn't mean what
the casual reader will think it means.

E.g.,

+     This method is designed to work with static links (nested
functions
+     handling).  Static links are function properties whose
evaluation return
+     the frame base address for the enclosing frame.

I think we need something less ambiguous / more clear.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-22 14:26           ` Doug Evans
@ 2015-07-22 15:14             ` Pierre-Marie de Rodat
  2015-07-26 17:28               ` Doug Evans
  2015-07-22 17:58             ` Kevin Buettner
  1 sibling, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-22 15:14 UTC (permalink / raw)
  To: Doug Evans; +Cc: Pedro Alves, GDB Patches

On 07/22/2015 04:26 PM, Doug Evans wrote:
> One thought that comes to mind when reading the patch is that
> you introduce the term "static link", and it doesn't mean what
> the casual reader will think it means.
>
> E.g.,
>
> +     This method is designed to work with static links (nested
> functions
> +     handling).  Static links are function properties whose
> evaluation return
> +     the frame base address for the enclosing frame.
>
> I think we need something less ambiguous / more clear.

Having dived in nested functions, “static link” is currently wired in my 
mind to nested functions. ;-) What do you think it can be confused with? 
Statically linked libraries?

One advantage of “static link” is that it’s the term which the DWARF 
specification uses. GCC says “static chain” instead and I’ve read 
somewhere “activation record”, although it actually means: the record 
pointed to by the static chain.

I liked the one I used because of the DWARF specification vocabulary, 
but I’m open to changing it if it’s confusing.

Thanks in advance for the review!

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-22 14:26           ` Doug Evans
  2015-07-22 15:14             ` Pierre-Marie de Rodat
@ 2015-07-22 17:58             ` Kevin Buettner
  1 sibling, 0 replies; 40+ messages in thread
From: Kevin Buettner @ 2015-07-22 17:58 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, Pierre-Marie de Rodat, Pedro Alves

On Wed, 22 Jul 2015 07:26:02 -0700
Doug Evans <xdje42@gmail.com> wrote:

> One thought that comes to mind when reading the patch is that
> you introduce the term "static link", and it doesn't mean what
> the casual reader will think it means.
> 
> E.g.,
> 
> +     This method is designed to work with static links (nested
> functions
> +     handling).  Static links are function properties whose
> evaluation return
> +     the frame base address for the enclosing frame.
> 
> I think we need something less ambiguous / more clear.

Perhaps the term "static chain" is better?

That term, "static chain", has been around for a long while to
describe a technique for implementing lexically scoped functions. 
E.g, I've found it in one of my (very old) textbooks where it is used
in a discussion of the implementation of lexically scoped subprograms
in the ALGOL language.

On the other hand, DWARF has the DW_AT_static_link attribute.  Its
value is a "location description that computes the frame base of the
relevant instance of the subroutine that immediately encloses the
subroutine or entry point."

AFAICT, the terms "static link" and "static chain" mean the same thing
in the context of lexically scoped functions.  I think we should use
one of these phrases unless someone knows of yet another term which is
commonly used in this context.

Kevin

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-22  9:16         ` Pierre-Marie de Rodat
  2015-07-22 14:26           ` Doug Evans
@ 2015-07-23  1:36           ` Kevin Buettner
  2015-07-23 10:44             ` Pierre-Marie de Rodat
  1 sibling, 1 reply; 40+ messages in thread
From: Kevin Buettner @ 2015-07-23  1:36 UTC (permalink / raw)
  To: gdb-patches

On Wed, 22 Jul 2015 11:16:46 +0200
Pierre-Marie de Rodat <derodat@adacore.com> wrote:

> Here it is! 
> <https://sourceware.org/ml/gdb-patches/2015-07/msg00607.html> I just 
> rebased my work on non-local references on top of this cleanup and 
> performed the changes you asked me to do. Just a question:
[...]
> Regtested again on x86_64-linux: no regression. Ok to push? Thank you!

Hi Pierre-Marie,

I had to make the following change in order to obtain a clean build
using your patches:

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index e20aead..d6e3d55 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -11457,7 +11457,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 
   newobj = pop_context ();
   /* Make a block for the local symbols within.  */
-  block = finish_block (newobj->name, &newobj->static_link,
+  block = finish_block (newobj->name, newobj->static_link,
 			&local_symbols, newobj->old_blocks,
                         lowpc, highpc);
 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23  1:36           ` Kevin Buettner
@ 2015-07-23 10:44             ` Pierre-Marie de Rodat
  2015-07-23 13:44               ` Kevin Buettner
  2015-07-26 20:35               ` Doug Evans
  0 siblings, 2 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-23 10:44 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches; +Cc: Doug Evans

[-- Attachment #1: Type: text/plain, Size: 2053 bytes --]

Kevin,

On 07/23/2015 02:39 AM, Kevin Buettner wrote:
> I had to make the following change in order to obtain a clean build
> using your patches:
>
> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index e20aead..d6e3d55 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -11457,7 +11457,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>
>     newobj = pop_context ();
>     /* Make a block for the local symbols within.  */
> -  block = finish_block (newobj->name, &newobj->static_link,
> +  block = finish_block (newobj->name, newobj->static_link,
>   			&local_symbols, newobj->old_blocks,
>                           lowpc, highpc);

Huh, I actually have a warning I did not notice but not an error, so I 
guess you built GDB as C++. Anyway, this is a big mistake that should 
have broken the feature I intend to add: quite bad! Thank you very much 
for pointing me at it.

I had a look at why testsuite was clean even with this error, and I 
realized that all my testing was with the wrong compiler[1]: this part 
of the code was actually not exercized... So I picked the proper 
compiler and this time I saw this was not working! This time I fixed the 
feature, built in C++ mode just to be sure. Here's the updated patch:

   - I fixed yacc parsers in all languages so that block information 
from symbol lookups are properly transmitted to returned expressions.

   - I fixed the usage of hash table to save static link (I do mappings 
in objfiles.c, not sets so my usage of htab was invalid).

So this time, tested both with a GCC release and a patched GCC: no 
regression on x86_64-linux. I kept the "static link" terminology because 
I'm waiting for a consensus before changing everything. ;-)


[1] In nested functions, an unpatched GCC creates local variables that 
are references to the non-local ones, so the feature works at the user 
level, but not using the static link machinery. The aim of my change is 
to make GDB work even without these "fake" local reference variables.

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-DWARF-handle-non-local-references-in-nested-function.patch --]
[-- Type: text/x-diff, Size: 70714 bytes --]

From 2e65051fd50bb99985bbc2c8ed13c67514e9cc08 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] DWARF: handle non-local references in nested functions

GDB's current behavior when dealing with non-local references in the
context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
references.

gdb/ChangeLog:

	* ada-lang.c (ada_read_var_value): Add a VAR_BLOCK argument and pass
	it to default_read_var_value.
	* block.c (block_static_link): New accessor.
	* block.h (block_static_link): Declare it.
	* buildsym.c (finish_block_internal): Add a static_link
	argument.  If there is a static link, associate it to the new
	block.
	(finish_block): Add a static link argument and pass it to
	finish_block_internal.
	(end_symtab_get_static_block): Update calls to finish_block and
	to finish_block_internal.
	(end_symtab_with_blockvector): Update call to
	finish_block_internal.
	* buildsym.h: Forward-declare struct dynamic_prop.
	(struct context_stack): Add a static_link field.
	(finish_block): Add a static link argument.
	* c-exp.y: Remove an obsolete
	comment (evaluation of variables already start from the selected
	frame, and now they climb *up* the call stack) and propagate the
	block information to the produced expression.
	* d-exp.y: Likewise.
	* f-exp.y: Likewise.
	* go-exp.y: Likewise.
	* jv-exp.y: Likewise.
	* m2-exp.y: Likewise.
	* p-exp.y: Likewise.
	* coffread.c (coff_symtab_read): Update calls to finish_block.
	* dbxread.c (process_one_symbol): Likewise.
	* xcoffread.c (read_xcoff_symtab): Likewise.
	* compile/compile-c-symbols.c (convert_one_symbol): Add a
	VAR_BLOCK parameter and pass it to calls to read_var_value.
	(convert_symbol_sym): Pass the block corresponding to SYM to the
	call to convert_one_symbol.
	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
	call to read_var_value.
	* 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.
	* findvar.c (follow_static_link): New.
	(get_hosting_frame): New.
	(default_read_var_value): Add a VAR_BLOCK argument.  Use
	get_hosting_frame to handle non-local references.
	(read_var_value): Add a VAR_BLOCK argument and pass it to the
	LA_READ_VAR_VALUE method.
	* gdbtypes.c (resolve_dynamic_range): Update calls to
	dwarf2_evaluate_property.
	(resolve_dynamic_type_internal): Likewise.
	* infcmd.c (finish_command_continuation): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* infrun.c (insert_exception_resume_breakpoint): Likewise.
	* language.h (struct language_defn): Add a VAR_BLOCK argument to
	the LA_READ_VAR_VALUE method.
	* objfiles.c (objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	(free_objfile): Free the STATIC_LINKS hashed map if needed.
	* objfiles.h: Include hashtab.h.
	(struct objfile): Add a STATIC_LINKS field.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	* printcmd.c (print_variable_and_value): Update call to
	read_var_value.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
	* python/py-frame.c (frapy_read_var): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* python/py-framefilter.c (extract_sym): Add a SYM_BLOCK
	parameter and set the pointed value to NULL (TODO).
	(enumerate_args): Update call to extract_sym.
	(enumerate_locals): Update calls to extract_sym and to
	read_var_value.
	* python/py-symbol.c (sympy_value): Update call to
	read_var_value (TODO).
	* stack.c (read_frame_local): Update call to read_var_value.
	(read_frame_arg): Likewise.
	(return_command): Likewise.
	* symtab.h (struct symbol_block_ops): Add a get_frame_base
	method.
	(struct symbol): Add a block field.
	(SYMBOL_BLOCK): New accessor.
	* valops.c (value_of_variable): Remove frame/block handling and
	pass the block argument to read_var_value, which does this job
	now.
	(value_struct_elt_for_reference): Update calls to
	read_var_value.
	(value_of_this): Pass the block found to read_var_value.
	* value.h (read_var_value): Add a VAR_BLOCK argument.
	(default_read_var_value): Likewise.

gdb/testsuite/ChangeLog:

	* 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                          |   5 +-
 gdb/block.c                             |  15 +++
 gdb/block.h                             |   6 ++
 gdb/buildsym.c                          |  17 ++--
 gdb/buildsym.h                          |  14 ++-
 gdb/c-exp.y                             |   5 +-
 gdb/coffread.c                          |   4 +-
 gdb/compile/compile-c-symbols.c         |  19 ++--
 gdb/compile/compile-loc2c.c             |   2 +-
 gdb/d-exp.y                             |   4 +-
 gdb/dbxread.c                           |   8 +-
 gdb/dwarf2loc.c                         |  52 ++++++++--
 gdb/dwarf2loc.h                         |  11 ++-
 gdb/dwarf2read.c                        |  19 +++-
 gdb/f-exp.y                             |   5 +-
 gdb/findvar.c                           | 168 +++++++++++++++++++++++++++++++-
 gdb/gdbtypes.c                          |   7 +-
 gdb/go-exp.y                            |   5 +-
 gdb/infcmd.c                            |   2 +-
 gdb/infrun.c                            |   7 +-
 gdb/jv-exp.y                            |   4 +-
 gdb/language.h                          |  12 ++-
 gdb/m2-exp.y                            |   5 +-
 gdb/objfiles.c                          |  76 +++++++++++++++
 gdb/objfiles.h                          |  18 ++++
 gdb/p-exp.y                             |   5 +-
 gdb/printcmd.c                          |   6 +-
 gdb/python/py-finishbreakpoint.c        |   2 +-
 gdb/python/py-frame.c                   |   9 +-
 gdb/python/py-framefilter.c             |  28 ++++--
 gdb/python/py-symbol.c                  |   5 +-
 gdb/stack.c                             |   8 +-
 gdb/symtab.h                            |  18 ++++
 gdb/testsuite/gdb.base/nested-subp1.c   |  37 +++++++
 gdb/testsuite/gdb.base/nested-subp1.exp |  55 +++++++++++
 gdb/testsuite/gdb.base/nested-subp2.c   |  48 +++++++++
 gdb/testsuite/gdb.base/nested-subp2.exp |  64 ++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.c   |  66 +++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.exp |  55 +++++++++++
 gdb/valops.c                            |  35 ++-----
 gdb/value.h                             |   2 +
 gdb/xcoffread.c                         |   4 +-
 42 files changed, 810 insertions(+), 127 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 ded195f..5c43a7a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13750,7 +13750,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
 /* Implement the "la_read_var_value" language_defn method for Ada.  */
 
 static struct value *
-ada_read_var_value (struct symbol *var, struct frame_info *frame)
+ada_read_var_value (struct symbol *var, const struct block *var_block,
+		    struct frame_info *frame)
 {
   const struct block *frame_block = NULL;
   struct symbol *renaming_sym = NULL;
@@ -13766,7 +13767,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
 
   /* This is a typical case where we expect the default_read_var_value
      function to work.  */
-  return default_read_var_value (var, frame);
+  return default_read_var_value (var, var_block, frame);
 }
 
 const struct language_defn ada_language_defn = {
diff --git a/gdb/block.c b/gdb/block.c
index f7621aa..f4b8e4f 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
   gb->compunit_symtab = cu;
 }
 
+/* See block.h.  */
+
+struct dynamic_prop *
+block_static_link (const struct block *block)
+{
+  struct objfile *objfile = block_objfile (block);
+
+  /* Only objfile-owned blocks that materialize top function scopes can have
+     static links.  */
+  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
+    return NULL;
+
+  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
+}
+
 /* Return the compunit of the global block.  */
 
 static struct compunit_symtab *
diff --git a/gdb/block.h b/gdb/block.h
index d8ad343..6e7d247 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -190,6 +190,12 @@ extern struct block *allocate_global_block (struct obstack *obstack);
 extern void set_block_compunit_symtab (struct block *,
 				       struct compunit_symtab *);
 
+/* Return a property to evaluate the static link associated to BLOCK.  Note
+   that only objfile-owned and function-level blocks can have a static link.
+   Return NULL if there is no such property.  */
+
+extern struct dynamic_prop *block_static_link (const struct block *block);
+
 /* A block iterator.  This structure should be treated as though it
    were opaque; it is only defined here because we want to support
    stack allocation of iterators.  */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 2a24a25..a2be2cb 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)
@@ -422,6 +423,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
       BLOCK_FUNCTION (block) = NULL;
     }
 
+  if (static_link != NULL)
+    objfile_register_static_link (objfile, block, static_link);
+
   /* Now "free" the links of the list, and empty the list.  */
 
   for (next = *listhead; next; next = next1)
@@ -512,11 +516,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 +1223,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 +1294,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 +1322,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..8828ad2 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -39,6 +39,8 @@ struct compunit_symtab;
 struct block;
 struct pending_block;
 
+struct dynamic_prop;
+
 #ifndef EXTERN
 #define	EXTERN extern
 #endif
@@ -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/c-exp.y b/gdb/c-exp.y
index b408215..3b7e572 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1070,10 +1070,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 7722cdb..e41e9a5 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1144,7 +1144,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
 		enter_linenos (fcn_line_ptr, fcn_first_line,
 			       fcn_last_line, objfile);
 
-	      finish_block (newobj->name, &local_symbols,
+	      finish_block (newobj->name, NULL, &local_symbols,
 			    newobj->old_blocks, newobj->start_addr,
 			    fcn_cs_saved.c_value
 			    + fcn_aux_saved.x_sym.x_misc.x_fsize
@@ -1188,7 +1188,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, newobj->old_blocks,
+		  finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 				newobj->start_addr, tmpaddr);
 		}
 	      /* Now pop locals of block just finished.  */
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 5f27583..f1dfccf 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -134,16 +134,16 @@ symbol_substitution_name (struct symbol *sym)
   return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
 }
 
-/* Convert a given symbol, SYM, to the compiler's representation.
-   CONTEXT is the compiler instance.  IS_GLOBAL is true if the
-   symbol came from the global scope.  IS_LOCAL is true if the symbol
-   came from a local scope.  (Note that the two are not strictly
-   inverses because the symbol might have come from the static
-   scope.)  */
+/* Convert a given symbol, SYM (located in VAR_BLOCK, if any), to the
+   compiler's representation.  CONTEXT is the compiler instance.  IS_GLOBAL is
+   true if the symbol came from the global scope.  IS_LOCAL is true if the
+   symbol came from a local scope.  (Note that the two are not strictly
+   inverses because the symbol might have come from the static scope.)  */
 
 static void
 convert_one_symbol (struct compile_c_instance *context,
 		    struct symbol *sym,
+		    const struct block *var_block,
 		    int is_global,
 		    int is_local)
 {
@@ -247,7 +247,7 @@ convert_one_symbol (struct compile_c_instance *context,
 			 SYMBOL_PRINT_NAME (sym));
 	      }
 
-	    val = read_var_value (sym, frame);
+	    val = read_var_value (sym, var_block, frame);
 	    if (VALUE_LVAL (val) != lval_memory)
 	      error (_("Symbol \"%s\" cannot be used for compilation "
 		       "evaluation as its address has not been found."),
@@ -339,7 +339,8 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
 	    fprintf_unfiltered (gdb_stdlog,
 				"gcc_convert_symbol \"%s\": global symbol\n",
 				identifier);
-	  convert_one_symbol (context, global_sym.symbol, 1, 0);
+	  convert_one_symbol (context, global_sym.symbol, global_sym.block, 1,
+			      0);
 	}
     }
 
@@ -347,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
     fprintf_unfiltered (gdb_stdlog,
 			"gcc_convert_symbol \"%s\": local symbol\n",
 			identifier);
-  convert_one_symbol (context, sym, 0, is_local_symbol);
+  convert_one_symbol (context, sym, block, 0, is_local_symbol);
 }
 
 /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 6f53814..18ca4ae 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
 		 "there is no selected frame"),
 	       SYMBOL_PRINT_NAME (sym));
 
-      val = read_var_value (sym, frame);
+      val = read_var_value (sym, NULL, frame);
       if (VALUE_LVAL (val) != lval_memory)
 	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		 "as its address has not been found."),
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index c95222b..336b671 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -1066,9 +1066,7 @@ push_variable (struct parser_state *ps, struct stoken name)
         }
 
       write_exp_elt_opcode (ps, OP_VAR_VALUE);
-      /* We want to use the selected frame, not another more inner frame
-         which happens to be in the same block.  */
-      write_exp_elt_block (ps, NULL);
+      write_exp_elt_block (ps, sym.block);
       write_exp_elt_sym (ps, sym.symbol);
       write_exp_elt_opcode (ps, OP_VAR_VALUE);
       return 1;
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 6098b35..32893f6 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2766,8 +2766,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 	  newobj = pop_context ();
 
 	  /* Make a block for the local symbols within.  */
-	  block = finish_block (newobj->name, &local_symbols,
-				newobj->old_blocks,
+	  block = finish_block (newobj->name, NULL,
+				&local_symbols, newobj->old_blocks,
 				newobj->start_addr, newobj->start_addr + valu);
 
 	  /* For C++, set the block's scope.  */
@@ -2868,7 +2868,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj->start_addr = valu;
 		}
 	      /* Make a block for the local symbols within.  */
-	      finish_block (0, &local_symbols, newobj->old_blocks,
+	      finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 			    newobj->start_addr, valu);
 	    }
 	}
@@ -3165,7 +3165,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 
 		  newobj = pop_context ();
 		  /* Make a block for the local symbols within.  */
-		  block = finish_block (newobj->name, &local_symbols,
+		  block = finish_block (newobj->name, NULL, &local_symbols,
 					newobj->old_blocks, newobj->start_addr,
 					valu);
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index c75767e..edfa220 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 f3630ac..2415656 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -122,12 +122,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 f440956..d6e3d55 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1736,6 +1736,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 *);
@@ -11393,6 +11397,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (attr)
     dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
 
+  /* If there is a location for the static link, record it.  */
+  newobj->static_link = NULL;
+  attr = dwarf2_attr (die, DW_AT_static_link, cu);
+  if (attr)
+    {
+      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
+					sizeof (*newobj->static_link));
+      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
+    }
+
   cu->list_in_scope = &local_symbols;
 
   if (die->child != NULL)
@@ -11443,7 +11457,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 
   newobj = pop_context ();
   /* Make a block for the local symbols within.  */
-  block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+  block = finish_block (newobj->name, newobj->static_link,
+			&local_symbols, newobj->old_blocks,
                         lowpc, highpc);
 
   /* For C++, set the block's scope.  */
@@ -11529,7 +11544,7 @@ 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, newobj->old_blocks,
+        = finish_block (0, NULL, &local_symbols, newobj->old_blocks,
 			newobj->start_addr, highpc);
 
       /* Note that recording ranges after traversing children, as we
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index c57f919..07892e0 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -521,10 +521,7 @@ variable:	name_not_typename
 				    innermost_block = sym.block;
 				}
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			      break;
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 2079b4b..38b9515 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,11 +410,166 @@ 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
+   functions.
+
+   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, const struct block *var_block,
+		   struct frame_info *frame)
+{
+  const struct block *frame_block = NULL;
+
+  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 function
+	 level, the immediate upper lexical block is in an outer function:
+	 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 function 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.  */
 
 struct value *
-default_read_var_value (struct symbol *var, struct frame_info *frame)
+default_read_var_value (struct symbol *var, const struct block *var_block,
+			struct frame_info *frame)
 {
   struct value *v;
   struct type *type = SYMBOL_TYPE (var);
@@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
   check_typedef (type);
 
   if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
+    gdb_assert (frame != NULL);
+
+  if (frame != NULL)
+    frame = get_hosting_frame (var, var_block, frame);
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
@@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
 /* Calls VAR's language la_read_var_value hook with the given arguments.  */
 
 struct value *
-read_var_value (struct symbol *var, struct frame_info *frame)
+read_var_value (struct symbol *var, const struct block *var_block,
+		struct frame_info *frame)
 {
   const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
 
   gdb_assert (lang != NULL);
   gdb_assert (lang->la_read_var_value != NULL);
 
-  return lang->la_read_var_value (var, frame);
+  return lang->la_read_var_value (var, var_block, frame);
 }
 
 /* Install default attributes for register values.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index be761e6..fe6af7c 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1874,7 +1874,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;
@@ -1886,7 +1886,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;
@@ -2128,7 +2128,8 @@ resolve_dynamic_type_internal (struct type *type,
 
   /* Resolve data_location attribute.  */
   prop = TYPE_DATA_LOCATION (resolved_type);
-  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (prop != NULL
+      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       TYPE_DYN_PROP_ADDR (prop) = value;
       TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index 1f43306..9fa1bbd 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -611,10 +611,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4948d27..2872292 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1660,7 +1660,7 @@ finish_command_continuation (void *arg, int err)
 	    {
 	      struct value *func;
 
-	      func = read_var_value (a->function, get_current_frame ());
+	      func = read_var_value (a->function, NULL, get_current_frame ());
 	      TRY
 		{
 		  /* print_return_value can throw an exception in some
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9a46242..0844823 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6082,14 +6082,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
 {
   TRY
     {
-      struct symbol *vsym;
+      struct symbol_in_block vsym;
       struct value *value;
       CORE_ADDR handler;
       struct breakpoint *bp;
 
-      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
-			    NULL).symbol;
-      value = read_var_value (vsym, frame);
+      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+      value = read_var_value (vsym.symbol, vsym.block, frame);
       /* If the value was optimized out, revert to the old behavior.  */
       if (! value_optimized_out (value))
 	{
diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
index 2e6de6f..bbdb330 100644
--- a/gdb/jv-exp.y
+++ b/gdb/jv-exp.y
@@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
 	}
 
       write_exp_elt_opcode (par_state, OP_VAR_VALUE);
-      /* We want to use the selected frame, not another more inner frame
-	 which happens to be in the same block.  */
-      write_exp_elt_block (par_state, NULL);
+      write_exp_elt_block (par_state, sym.block);
       write_exp_elt_sym (par_state, sym.symbol);
       write_exp_elt_opcode (par_state, OP_VAR_VALUE);
       return 1;
diff --git a/gdb/language.h b/gdb/language.h
index 2675b82..ea8442f 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -241,13 +241,19 @@ struct language_defn
     void (*la_value_print) (struct value *, struct ui_file *,
 			    const struct value_print_options *);
 
-    /* Given a symbol VAR, and a stack frame id FRAME, read the value
-       of the variable an return (pointer to a) struct value containing
-       the value.
+    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
+       stack frame id FRAME, read the value of the variable and return (pointer
+       to a) struct value containing the value.
+
+       VAR_BLOCK is needed if there's a possibility for VAR to be outside
+       FRAME.  This is what happens if FRAME correspond to a nested function
+       and VAR is defined in the outer function.  If callers know that VAR is
+       located in FRAME, NULL can be passed as VAR_BLOCK.
 
        Throw an error if the variable cannot be found.  */
 
     struct value *(*la_read_var_value) (struct symbol *var,
+					const struct block *var_block,
 					struct frame_info *frame);
 
     /* PC is possibly an unknown languages trampoline.
diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
index a203218..5c5652e 100644
--- a/gdb/m2-exp.y
+++ b/gdb/m2-exp.y
@@ -636,10 +636,7 @@ variable:	NAME
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index c6f9f00..95b4a97 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -199,6 +199,77 @@ set_objfile_main_name (struct objfile *objfile,
   objfile->per_bfd->language_of_main = lang;
 }
 
+/* Helper structure to map blocks to static link properties in hash tables.  */
+
+struct static_link_htab_entry
+{
+  const struct block *block;
+  struct dynamic_prop *static_link;
+};
+
+/* Return whether P1 (a struct static_link_htab_entry *) is a mapping from P2
+   (a struct block *).  */
+
+static int
+static_link_htab_entry_eq (const void *p1, const void *p2)
+{
+  const struct static_link_htab_entry *entry
+    = (const struct static_link_htab_entry *) p1;
+  const struct block *block = (const struct block *) p2;
+  return block == entry->block;
+}
+
+/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
+   Must not be called more than once for each BLOCK.  */
+
+void
+objfile_register_static_link (struct objfile *objfile,
+			      const struct block *block,
+			      struct dynamic_prop *static_link)
+{
+  void **slot;
+  struct static_link_htab_entry *entry;
+
+  if (objfile->static_links == NULL)
+    objfile->static_links = htab_create_alloc
+      (1, htab_hash_pointer, static_link_htab_entry_eq, NULL,
+       xcalloc, xfree);
+
+  /* Create a slot for the mapping, make sure it's the first mapping for this
+     block and then create the mapping itself.  */
+  slot = htab_find_slot (objfile->static_links, block, INSERT);
+  gdb_assert (*slot == NULL);
+
+  entry = (struct static_link_htab_entry *) obstack_alloc
+	    (&objfile->objfile_obstack, sizeof (*entry));
+  entry->block = block;
+  entry->static_link = static_link;
+  *slot = (void *) entry;
+}
+
+/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
+   none was found.  */
+
+struct dynamic_prop *
+objfile_lookup_static_link (struct objfile *objfile,
+			    const struct block *block)
+{
+  struct static_link_htab_entry *entry;
+
+  if (objfile->static_links == NULL)
+    return NULL;
+  entry
+    = (struct static_link_htab_entry *) htab_find (objfile->static_links,
+						   block);
+  if (entry == NULL)
+    return NULL;
+  else
+    {
+      gdb_assert (entry->block == block);
+      return entry->static_link;
+    }
+}
+
 \f
 
 /* Called via bfd_map_over_sections to build up the section table that
@@ -653,6 +724,11 @@ free_objfile (struct objfile *objfile)
   /* Rebuild section map next time we need it.  */
   get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
 
+  /* Free the map for static links.  There's no need to free static link
+     themselves since they were allocated on the objstack.  */
+  if (objfile->static_links != NULL)
+    htab_delete (objfile->static_links);
+
   /* The last thing we do is free the objfile struct itself.  */
   xfree (objfile);
 }
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a0dc69b..aa2e966 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -20,6 +20,7 @@
 #if !defined (OBJFILES_H)
 #define OBJFILES_H
 
+#include "hashtab.h"
 #include "gdb_obstack.h"	/* For obstack internals.  */
 #include "symfile.h"		/* For struct psymbol_allocation_list.  */
 #include "progspace.h"
@@ -412,6 +413,16 @@ struct objfile
        table, so we have to keep them here to relocate them
        properly.  */
     struct symbol *template_symbols;
+
+    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
+       block *) that have one.  For nested functions, the static link is the
+       expression that computes the frame base of the lexically enclosing
+       function.
+
+       Very few blocks have a static link, so it's more memory efficient to
+       store these here.  Static links must be allocated on the objfile's
+       obstack.  */
+    struct htab *static_links;
   };
 
 /* Defines for the objfile flag word.  */
@@ -719,4 +730,11 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
 extern void set_objfile_main_name (struct objfile *objfile,
 				   const char *name, enum language lang);
 
+extern void objfile_register_static_link (struct objfile *objfile,
+					  const struct block *block,
+					  struct dynamic_prop *static_link);
+
+extern struct dynamic_prop *objfile_lookup_static_link
+  (struct objfile *objfile, const struct block *block);
+
 #endif /* !defined (OBJFILES_H) */
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index a2f86d6..173d9fb 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -769,10 +769,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			      current_type = sym.symbol->type; }
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f51e25c..553cc71 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
       struct value *val;
       struct value_print_options opts;
 
-      val = read_var_value (var, frame);
+      /* READ_VAR_VALUE needs a block in order to deal with non-local
+	 references (i.e. to handle nested functions).  In this context, we
+	 print variables that are local to this frame, so we can avoid passing
+	 a block to it.  */
+      val = read_var_value (var, NULL, frame);
       get_user_print_options (&opts);
       opts.deref_ref = 1;
       common_val_print (val, stream, indent, &opts, current_language);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index e3d4867..345642e 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  func_value = read_var_value (function, frame);
+                  func_value = read_var_value (function, NULL, frame);
                   self_bpfinish->function_value =
                       value_to_value_object (func_value);
                   PyErr_Clear ();
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 7290056..fa7937a 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
   struct frame_info *frame;
   PyObject *sym_obj, *block_obj = NULL;
   struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
+  const struct block *block = NULL;
   struct value *val = NULL;
 
   if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
@@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
   else if (gdbpy_is_string (sym_obj))
     {
       char *var_name;
-      const struct block *block = NULL;
       struct cleanup *cleanup;
 
       var_name = python_string_to_target_string (sym_obj);
@@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
 
       TRY
 	{
+	  struct symbol_in_block lookup_sym;
 	  FRAPY_REQUIRE_VALID (self, frame);
 
 	  if (!block)
 	    block = get_frame_block (frame, NULL);
-	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  var = lookup_sym.symbol;
+	  block = lookup_sym.block;
 	}
       CATCH (except, RETURN_MASK_ALL)
 	{
@@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
     {
       FRAPY_REQUIRE_VALID (self, frame);
 
-      val = read_var_value (var, frame);
+      val = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index e3336b1..397ac86 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -43,16 +43,17 @@ enum mi_print_types
    NAME is a  pass-through argument where the name of  the symbol will
    be written.  NAME is allocated in  this function, but the caller is
    responsible for clean up.  SYM is a pass-through argument where the
-   symbol will be written.  In the case of the API returning a string,
-   this will be set to NULL.  LANGUAGE is also a pass-through argument
-   denoting the language attributed to the Symbol.  In the case of SYM
-   being  NULL, this  will be  set to  the current  language.  Returns
-   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
-   EXT_LANG_BT_OK on success.  */
+   symbol will be written and  SYM_BLOCK is a pass-through argument to
+   write  the block where the symbol lies in.  In the case of the  API
+   returning a  string,  this will be set to NULL.  LANGUAGE is also a
+   pass-through  argument  denoting  the  language  attributed  to the
+   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
+   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
+   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
 
 static enum ext_lang_bt_status
 extract_sym (PyObject *obj, char **name, struct symbol **sym,
-	     const struct language_defn **language)
+	     struct block **sym_block, const struct language_defn **language)
 {
   PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
 
@@ -75,12 +76,17 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
 	python_language.  */
       *language = python_language;
       *sym = NULL;
+      *sym_block = NULL;
     }
   else
     {
       /* This type checks 'result' during the conversion so we
 	 just call it unconditionally and check the return.  */
       *sym = symbol_object_to_symbol (result);
+      /* TODO:  How should we find the corresponding block for this symbol?
+	 Should we lookup all blocks in the owning objfile?  Should we store
+	 the bloc kin the Symbol object?  */
+      *sym_block = NULL;
 
       Py_DECREF (result);
 
@@ -537,10 +543,11 @@ enumerate_args (PyObject *iter,
       const struct language_defn *language;
       char *sym_name;
       struct symbol *sym;
+      struct block *sym_block;
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  Py_DECREF (item);
@@ -736,12 +743,13 @@ enumerate_locals (PyObject *iter,
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
       struct symbol *sym;
+      struct block *sym_block;
       int local_indent = 8 + (8 * indent);
       struct cleanup *locals_cleanups;
 
       locals_cleanups = make_cleanup_py_decref (item);
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  do_cleanups (locals_cleanups);
@@ -769,7 +777,7 @@ enumerate_locals (PyObject *iter,
 	{
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, sym_block, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 401e7e9..b58e59d 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -278,7 +278,10 @@ sympy_value (PyObject *self, PyObject *args)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO: How should we find the corresponding block for this symbol?
+	 Should we lookup all blocks in the owning objfile?  Should we store
+	 the block in the Symbol object?  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/stack.c b/gdb/stack.c
index b4cfdbd..5a18a06 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
 
   TRY
     {
-      argp->val = read_var_value (sym, frame);
+      argp->val = read_var_value (sym, NULL, frame);
     }
   CATCH (except, RETURN_MASK_ERROR)
     {
@@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
     {
       TRY
 	{
-	  val = read_var_value (sym, frame);
+	  val = read_var_value (sym, NULL, frame);
 	}
       CATCH (except, RETURN_MASK_ERROR)
 	{
@@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
 
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, NULL, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
@@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
 	value_fetch_lazy (return_value);
 
       if (thisfun != NULL)
-	function = read_var_value (thisfun, thisframe);
+	function = read_var_value (thisfun, NULL, thisframe);
 
       rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
       if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 73026b3..509537b 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 functions
+     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 fuctions, 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.  */
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..967eb2f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.c
@@ -0,0 +1,37 @@
+/* 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 function 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..9720f5b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a6449e34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.c
@@ -0,0 +1,48 @@
+/* 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..a107d1c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.exp
@@ -0,0 +1,64 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a51f417
--- /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);
+
+extern void process (callback_t cb);
+extern 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..8f9b522
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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.
+
+gdb_test "print first"        "1"
+gdb_test "print parent_first" "1"
diff --git a/gdb/valops.c b/gdb/valops.c
index d326f93..94182c5 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1288,27 +1288,12 @@ value_repeat (struct value *arg1, int count)
 struct value *
 value_of_variable (struct symbol *var, const struct block *b)
 {
-  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);
+  return read_var_value (var, b, frame);
 }
 
 struct value *
@@ -3459,9 +3444,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 		return NULL;
 
 	      if (want_address)
-		return value_addr (read_var_value (s, 0));
+		return value_addr (read_var_value (s, 0, 0));
 	      else
-		return read_var_value (s, 0);
+		return read_var_value (s, 0, 0);
 	    }
 
 	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -3489,7 +3474,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 	      if (s == NULL)
 		return NULL;
 
-	      v = read_var_value (s, 0);
+	      v = read_var_value (s, 0, 0);
 	      if (!want_address)
 		result = v;
 	      else
@@ -3725,7 +3710,7 @@ value_full_object (struct value *argp,
 struct value *
 value_of_this (const struct language_defn *lang)
 {
-  struct symbol *sym;
+  struct symbol_in_block sym;
   const struct block *b;
   struct frame_info *frame;
 
@@ -3736,12 +3721,12 @@ value_of_this (const struct language_defn *lang)
 
   b = get_frame_block (frame, NULL);
 
-  sym = lookup_language_this (lang, b).symbol;
-  if (sym == NULL)
+  sym = lookup_language_this (lang, b);
+  if (sym.symbol == NULL)
     error (_("current stack frame does not contain a variable named `%s'"),
 	   lang->la_name_of_this);
 
-  return read_var_value (sym, frame);
+  return read_var_value (sym.symbol, sym.block, frame);
 }
 
 /* Return the value of the local variable, if one exists.  Return NULL
diff --git a/gdb/value.h b/gdb/value.h
index 7ff6aa8..c35a876 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -670,9 +670,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
 extern int symbol_read_needs_frame (struct symbol *);
 
 extern struct value *read_var_value (struct symbol *var,
+				     const struct block *var_block,
 				     struct frame_info *frame);
 
 extern struct value *default_read_var_value (struct symbol *var,
+					     const struct block *var_block,
 					     struct frame_info *frame);
 
 extern struct value *allocate_value (struct type *type);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index b5b2a1d..dea24a4 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1388,8 +1388,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 		  break;
 		}
 
-	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-			    newobj->start_addr,
+	      finish_block (newobj->name, NULL, &local_symbols,
+			    newobj->old_blocks, newobj->start_addr,
 			    (fcn_cs_saved.c_value
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
 			     + ANOFFSET (objfile->section_offsets,
-- 
2.4.5


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 10:44             ` Pierre-Marie de Rodat
@ 2015-07-23 13:44               ` Kevin Buettner
  2015-07-23 16:14                 ` Pierre-Marie de Rodat
  2015-07-26 20:35               ` Doug Evans
  1 sibling, 1 reply; 40+ messages in thread
From: Kevin Buettner @ 2015-07-23 13:44 UTC (permalink / raw)
  To: gdb-patches

On Thu, 23 Jul 2015 12:44:19 +0200
Pierre-Marie de Rodat <derodat@adacore.com> wrote:

> Kevin,
> 
> On 07/23/2015 02:39 AM, Kevin Buettner wrote:
> > I had to make the following change in order to obtain a clean build
> > using your patches:
> >
> > diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> > index e20aead..d6e3d55 100644
> > --- a/gdb/dwarf2read.c
> > +++ b/gdb/dwarf2read.c
> > @@ -11457,7 +11457,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
> >
> >     newobj = pop_context ();
> >     /* Make a block for the local symbols within.  */
> > -  block = finish_block (newobj->name, &newobj->static_link,
> > +  block = finish_block (newobj->name, newobj->static_link,
> >   			&local_symbols, newobj->old_blocks,
> >                           lowpc, highpc);
> 
> Huh, I actually have a warning I did not notice but not an error, so I 
> guess you built GDB as C++. Anyway, this is a big mistake that should 
> have broken the feature I intend to add: quite bad! Thank you very much 
> for pointing me at it.

I built it using GCC's C compiler, but with -Werror enabled. This flag
turns warnings into errors.

I'll test your new patch today.  I've encountered a GDB bug related to
examining variables with within a nested function.  I'm hoping that
your patch will fix it...

Kevin

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 13:44               ` Kevin Buettner
@ 2015-07-23 16:14                 ` Pierre-Marie de Rodat
  2015-07-23 17:22                   ` Kevin Buettner
  2015-07-23 18:06                   ` Kevin Buettner
  0 siblings, 2 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-23 16:14 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches

On 07/23/2015 03:44 PM, Kevin Buettner wrote:
> I built it using GCC's C compiler, but with -Werror enabled. This flag
> turns warnings into errors.

I see... Thank you.

> I'll test your new patch today.  I've encountered a GDB bug related to
> examining variables with within a nested function.  I'm hoping that
> your patch will fix it...

I am as well: keep me updated! ;-)

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 16:14                 ` Pierre-Marie de Rodat
@ 2015-07-23 17:22                   ` Kevin Buettner
  2015-07-23 17:33                     ` Pierre-Marie de Rodat
  2015-07-23 18:06                   ` Kevin Buettner
  1 sibling, 1 reply; 40+ messages in thread
From: Kevin Buettner @ 2015-07-23 17:22 UTC (permalink / raw)
  To: gdb-patches

On Thu, 23 Jul 2015 18:14:12 +0200
Pierre-Marie de Rodat <derodat@adacore.com> wrote:

> On 07/23/2015 03:44 PM, Kevin Buettner wrote:
>
> > I'll test your new patch today.  I've encountered a GDB bug related to
> > examining variables with within a nested function.  I'm hoping that
> > your patch will fix it...
> 
> I am as well: keep me updated! ;-)

I ran into another issue, both yesterday and today, when attempting to
apply your patch.  Apparently, it adds some test cases,
gdb.base/nested-subp1.c, gdb.base/nested-subp1.exp, etc. which already
exist.  As can be seen in the log below, I told patch to not assume -R
as well as to not apply the patch.  I'm using sources, current as of
yesterday, upon which I first applied your other patch,
0001-Replace-the-block_found-global-with-explicit-data-fl.patch.

Here's the log showing the issue I ran into:

[kev@pinnacle gdb]$ patch -p2 </tmp/0001-DWARF-handle-non-local-references-in-nested-function.patch 
patching file ada-lang.c
patching file block.c
patching file block.h
patching file buildsym.c
patching file buildsym.h
patching file c-exp.y
patching file coffread.c
patching file compile/compile-c-symbols.c
patching file compile/compile-loc2c.c
patching file d-exp.y
patching file dbxread.c
patching file dwarf2loc.c
patching file dwarf2loc.h
patching file dwarf2read.c
patching file f-exp.y
patching file findvar.c
patching file gdbtypes.c
patching file go-exp.y
patching file infcmd.c
patching file infrun.c
patching file jv-exp.y
patching file language.h
patching file m2-exp.y
patching file objfiles.c
patching file objfiles.h
patching file p-exp.y
patching file printcmd.c
patching file python/py-finishbreakpoint.c
patching file python/py-frame.c
patching file python/py-framefilter.c
patching file python/py-symbol.c
patching file stack.c
patching file symtab.h
The next patch would create the file testsuite/gdb.base/nested-subp1.c,
which already exists!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored
The next patch would create the file testsuite/gdb.base/nested-subp1.exp,
which already exists!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored
The next patch would create the file testsuite/gdb.base/nested-subp2.c,
which already exists!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored
The next patch would create the file testsuite/gdb.base/nested-subp2.exp,
which already exists!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored
The next patch would create the file testsuite/gdb.base/nested-subp3.c,
which already exists!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored
The next patch would create the file testsuite/gdb.base/nested-subp3.exp,
which already exists!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored
patching file valops.c
patching file value.h
patching file xcoffread.c

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 17:22                   ` Kevin Buettner
@ 2015-07-23 17:33                     ` Pierre-Marie de Rodat
  2015-07-23 17:51                       ` Kevin Buettner
  0 siblings, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-23 17:33 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches

On 07/23/2015 07:21 PM, Kevin Buettner wrote:
> I ran into another issue, both yesterday and today, when attempting to
> apply your patch.  Apparently, it adds some test cases,
> gdb.base/nested-subp1.c, gdb.base/nested-subp1.exp, etc. which already
> exist.  As can be seen in the log below, I told patch to not assume -R
> as well as to not apply the patch.  I'm using sources, current as of
> yesterday, upon which I first applied your other patch,
> 0001-Replace-the-block_found-global-with-explicit-data-fl.patch.

Huh, strange! I think you have a dirty source tree: I just fetched the 
upstream repository and I have this:

     $ git annotate fsf/master -- gdb/testsuite/gdb.base/nested-subp1.exp
     fatal: no such path gdb/testsuite/gdb.base/nested-subp1.exp in 
fsf/master

So I guess you should check the state of your source tree with "git status".

> Here's the log showing the issue I ran into:
>
> [kev@pinnacle gdb]$ patch -p2 </tmp/0001-DWARF-handle-non-local-references-in-nested-function.patch
> patching file ada-lang.c
> [...]
> The next patch would create the file testsuite/gdb.base/nested-subp1.c,
> which already exists!  Assume -R? [n] n
> Apply anyway? [n] n
> [...]

I would suggest you to use "git am" to import patches: this will keep 
track of which change comes from which commit. If you want a quick 
discussion for this matter, I'm on IRC (#gdb), by the way.

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 17:33                     ` Pierre-Marie de Rodat
@ 2015-07-23 17:51                       ` Kevin Buettner
  0 siblings, 0 replies; 40+ messages in thread
From: Kevin Buettner @ 2015-07-23 17:51 UTC (permalink / raw)
  To: gdb-patches

On Thu, 23 Jul 2015 19:33:52 +0200
Pierre-Marie de Rodat <derodat@adacore.com> wrote:

> On 07/23/2015 07:21 PM, Kevin Buettner wrote:
> > I ran into another issue, both yesterday and today, when attempting to
> > apply your patch.  Apparently, it adds some test cases,
> > gdb.base/nested-subp1.c, gdb.base/nested-subp1.exp, etc. which already
> > exist.  As can be seen in the log below, I told patch to not assume -R
> > as well as to not apply the patch.  I'm using sources, current as of
> > yesterday, upon which I first applied your other patch,
> > 0001-Replace-the-block_found-global-with-explicit-data-fl.patch.
> 
> Huh, strange! I think you have a dirty source tree: I just fetched the 
> upstream repository and I have this:
> 
>      $ git annotate fsf/master -- gdb/testsuite/gdb.base/nested-subp1.exp
>      fatal: no such path gdb/testsuite/gdb.base/nested-subp1.exp in 
> fsf/master
> 
> So I guess you should check the state of your source tree with "git status".

I think you're right.  Sorry for the false alarm!

> > Here's the log showing the issue I ran into:
> >
> > [kev@pinnacle gdb]$ patch -p2 </tmp/0001-DWARF-handle-non-local-references-in-nested-function.patch
> > patching file ada-lang.c
> > [...]
> > The next patch would create the file testsuite/gdb.base/nested-subp1.c,
> > which already exists!  Assume -R? [n] n
> > Apply anyway? [n] n
> > [...]
> 
> I would suggest you to use "git am" to import patches: this will keep 
> track of which change comes from which commit. If you want a quick 
> discussion for this matter, I'm on IRC (#gdb), by the way.

I'll look into this too.  Thanks!

Kevin

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 16:14                 ` Pierre-Marie de Rodat
  2015-07-23 17:22                   ` Kevin Buettner
@ 2015-07-23 18:06                   ` Kevin Buettner
  2015-07-23 18:23                     ` Kevin Buettner
  2015-07-24  9:26                     ` Pierre-Marie de Rodat
  1 sibling, 2 replies; 40+ messages in thread
From: Kevin Buettner @ 2015-07-23 18:06 UTC (permalink / raw)
  To: gdb-patches

On Thu, 23 Jul 2015 18:14:12 +0200
Pierre-Marie de Rodat <derodat@adacore.com> wrote:

> On 07/23/2015 03:44 PM, Kevin Buettner wrote:
>
> > I'll test your new patch today.  I've encountered a GDB bug related to
> > examining variables with within a nested function.  I'm hoping that
> > your patch will fix it...
> 
> I am as well: keep me updated! ;-)

Your patch did indeed fix my problem.

Given this test case (which I cobbled together while looking at another
matter)...

--- nested.c ---
int
main ()
{
  static int a = 1, b = 2, c = 3;
  int d = 4, e = 5, f = 6;

  void p (void)
  {
    c = 7;
    f = 8;
    __builtin_printf ("%d %d %d %d\n", b, c, e, f);
  }

  p ();

  a = 101; b = 102; c = 103;
  d = 104; e = 105; f = 106;

  p ();

  return 0;
}
--- end nested.c ---

...this is the behavior that I was seeing (without your patch):

Breakpoint 1, p () at nested.c:11
11          __builtin_printf ("%d %d %d %d\n", b, c, e, f);
(gdb) p a
$1 = 1
(gdb) p b
$2 = 2
(gdb) p c
$3 = 7
(gdb) p d
$4 = 32767
(gdb) p e
$5 = 5
(gdb) p f
$6 = 8

Note that the value of d is wrong.

Now, with your patch, this is what I see:

Breakpoint 1, p () at nested.c:11
11          __builtin_printf ("%d %d %d %d\n", b, c, e, f);
(gdb) p a
$1 = 1
(gdb) p b
$2 = 2
(gdb) p c
$3 = 7
(gdb) p d
$4 = 4
(gdb) p e
$5 = 5
(gdb) p f
$6 = 8

So, with your patch, the value of d is correct.

I don't know why, but with your patch from yesterday, I was still
seeing the faulty behavior.  (It is possible that I messed up with
my testing...)

Kevin

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 18:06                   ` Kevin Buettner
@ 2015-07-23 18:23                     ` Kevin Buettner
  2015-07-24 10:38                       ` Pierre-Marie de Rodat
  2015-07-24  9:26                     ` Pierre-Marie de Rodat
  1 sibling, 1 reply; 40+ messages in thread
From: Kevin Buettner @ 2015-07-23 18:23 UTC (permalink / raw)
  To: gdb-patches

Hi Pierre-Marie,

On Thu, 23 Jul 2015 11:06:53 -0700
Kevin Buettner <kevinb@redhat.com> wrote:

> --- nested.c ---
> int
> main ()
> {
>   static int a = 1, b = 2, c = 3;
>   int d = 4, e = 5, f = 6;
> 
>   void p (void)
>   {
>     c = 7;
>     f = 8;
>     __builtin_printf ("%d %d %d %d\n", b, c, e, f);
>   }
> 
>   p ();
> 
>   a = 101; b = 102; c = 103;
>   d = 104; e = 105; f = 106;
> 
>   p ();
> 
>   return 0;
> }
> --- end nested.c ---

I came across something else (for someone) to ponder while playing with
the above code.  I don't necessarily expect your current patch to handle
this case, but since you've been looking at nested subprograms, you may
have some insight into what's happening.

The situation is that I want to place a breakpoint on the function p().
How do I do this?

This is what I've tried:

1) Placing a breakpoint on p without qualification does not work:

(gdb) b p
Function "p" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n

2) Placing a breakpoint on main::p doesn't work:

(gdb) b main::p
Function "main::p" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n

3a) However, the completion mechanism seems to think that p is a viable
candidate for a breakpoint:

(gdb) b p
p           printf      printf@plt  

3b) But, as in (1), when we try it (by hitting <Enter> here), it
does not work:

Function "p" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n

4) Perhaps p will be visible if we run to a breakpoint in main?  (Nope.)

(gdb) b main
Breakpoint 1 at 0x400525: file nested.c, line 5.
(gdb) run
Starting program: /mesquite2/.ironwood2/1158876/nested 

Breakpoint 1, main () at nested.c:5
5         int d = 4, e = 5, f = 6;
(gdb) b p
Function "p" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) 

So, there it is.

I want to be perfectly clear that I do NOT want this issue to hold up
your patch.  I'm just throwing it out there in case you want to look
at it.

Kevin

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 18:06                   ` Kevin Buettner
  2015-07-23 18:23                     ` Kevin Buettner
@ 2015-07-24  9:26                     ` Pierre-Marie de Rodat
  1 sibling, 0 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-24  9:26 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches

On 07/23/2015 08:06 PM, Kevin Buettner wrote:
> Your patch did indeed fix my problem.
>
> Given this test case (which I cobbled together while looking at another
> matter)...
> [...]
> Breakpoint 1, p () at nested.c:11
> 11          __builtin_printf ("%d %d %d %d\n", b, c, e, f);
> (gdb) p a
> $1 = 1
> (gdb) p b
> $2 = 2
> (gdb) p c
> $3 = 7
> (gdb) p d
> $4 = 32767
> (gdb) p e
> $5 = 5
> (gdb) p f
> $6 = 8
>
> Note that the value of d is wrong.

Out of curiosity, I had a quick look and I understood what is going on 
(without my most recent patch) in this example:

a, b and c are static variables, so they aren't on the stack and thus 
GDB locates/prints them correctly. The e and f non-local variables are 
referenced from p and thus GCC materializes them as local references in 
the debug. info. for p, so GDB locates/prints the correctly.

d is both located on the outer frame and not referenced from p, so the 
only description GDB has is the outer scope variable... which is 
incorrectly used to locate/print the variable as of today.

> So, with your patch, the value of d is correct.
>
> I don't know why, but with your patch from yesterday, I was still
> seeing the faulty behavior.  (It is possible that I messed up with
> my testing...)

That's most likely because my previous patch was broken, as I said in 
the first mail I sent on Thursday. ;-)

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 18:23                     ` Kevin Buettner
@ 2015-07-24 10:38                       ` Pierre-Marie de Rodat
  2015-07-26 17:39                         ` Doug Evans
  0 siblings, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-24 10:38 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches

On 07/23/2015 08:22 PM, Kevin Buettner wrote:
> I came across something else (for someone) to ponder while playing with
> the above code.  I don't necessarily expect your current patch to handle
> this case, but since you've been looking at nested subprograms, you may
> have some insight into what's happening.
>
> The situation is that I want to place a breakpoint on the function p().
> How do I do this?

> 1) Placing a breakpoint on p without qualification does not work:
>
> (gdb) b p
> Function "p" not defined.
> Make breakpoint pending on future shared library load? (y or [n]) n

For the record, this works in Ada:

--  foo.adb
procedure Foo is
    procedure Nested is
    begin
       null;
    end Nested;
begin
    Nested;
end Foo;

# Program isn't even started.
(gdb) b nested
Breakpoint 1 at 0x401cca: file foo.adb, line 4.

Bottom line is: the difference between the C and the Ada examples 
resides in the partial symbols lookup: in the C example, only the outer 
function has a partial symbol while in the Ada example, Nested has one 
too. Why? Well, in dwarf2read.c:add_partial_subprogram there's a special 
case for Ada that recurses over the child DIE. Stopping investigation 
here. ;-)

> 4) Perhaps p will be visible if we run to a breakpoint in main?  (Nope.)
>
> (gdb) b main
> Breakpoint 1 at 0x400525: file nested.c, line 5.
> (gdb) run
> Starting program: /mesquite2/.ironwood2/1158876/nested

I had a quick look at how breakpoints resolution works: it sems that 
lookups don't take into account the block corresponding to the selected 
frame. So trying to put the breakpoint during execution looks pointless.

> I want to be perfectly clear that I do NOT want this issue to hold up
> your patch.  I'm just throwing it out there in case you want to look
> at it.

Sure. It was interesting to look at this, anyway.

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-22 15:14             ` Pierre-Marie de Rodat
@ 2015-07-26 17:28               ` Doug Evans
  0 siblings, 0 replies; 40+ messages in thread
From: Doug Evans @ 2015-07-26 17:28 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Pedro Alves, GDB Patches

Pierre-Marie de Rodat <derodat@adacore.com> writes:
> On 07/22/2015 04:26 PM, Doug Evans wrote:
>> One thought that comes to mind when reading the patch is that
>> you introduce the term "static link", and it doesn't mean what
>> the casual reader will think it means.
>>
>> E.g.,
>>
>> +     This method is designed to work with static links (nested
>> functions
>> +     handling).  Static links are function properties whose
>> evaluation return
>> +     the frame base address for the enclosing frame.
>>
>> I think we need something less ambiguous / more clear.
>
> Having dived in nested functions, “static link” is currently wired in
> my mind to nested functions. ;-) What do you think it can be confused
> with? Statically linked libraries?

Mostly that there's nothing in the reading of "static link" that tells me it
would be anything else. Obviously a casual reader will think it's
*probably* not that, but in the absence of any cues this reader is left
wondering where did this term come from.

> One advantage of “static link” is that it’s the term which the DWARF
> specification uses. GCC says “static chain” instead and I’ve read
> somewhere “activation record”, although it actually means: the record
> pointed to by the static chain.

Bleah, I wasn't aware of this term's usage in DWARF.
That's a good point.
I'd be ok with a comment in a couple of key locations that say
the term is derived from DW_AT_static_link.
[I know you mention it in at least one place, but IWBN
if it were mentioned in, e.g., the description of block_static_link.]

> I liked the one I used because of the DWARF specification vocabulary,
> but I’m open to changing it if it’s confusing.
>
> Thanks in advance for the review!

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-24 10:38                       ` Pierre-Marie de Rodat
@ 2015-07-26 17:39                         ` Doug Evans
  0 siblings, 0 replies; 40+ messages in thread
From: Doug Evans @ 2015-07-26 17:39 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Kevin Buettner, gdb-patches

Pierre-Marie de Rodat <derodat@adacore.com> writes:
> On 07/23/2015 08:22 PM, Kevin Buettner wrote:
>> I came across something else (for someone) to ponder while playing with
>> the above code.  I don't necessarily expect your current patch to handle
>> this case, but since you've been looking at nested subprograms, you may
>> have some insight into what's happening.
>>
>> The situation is that I want to place a breakpoint on the function p().
>> How do I do this?
>
>> 1) Placing a breakpoint on p without qualification does not work:
>>
>> (gdb) b p
>> Function "p" not defined.
>> Make breakpoint pending on future shared library load? (y or [n]) n
>
> For the record, this works in Ada:
>
> --  foo.adb
> procedure Foo is
>    procedure Nested is
>    begin
>       null;
>    end Nested;
> begin
>    Nested;
> end Foo;
>
> # Program isn't even started.
> (gdb) b nested
> Breakpoint 1 at 0x401cca: file foo.adb, line 4.
>
> Bottom line is: the difference between the C and the Ada examples
> resides in the partial symbols lookup: in the C example, only the
> outer function has a partial symbol while in the Ada example, Nested
> has one too. Why? Well, in dwarf2read.c:add_partial_subprogram there's
> a special case for Ada that recurses over the child DIE. Stopping
> investigation here. ;-)

Yeah, I can imagine that this is at least part of the reason.
We need to be as lazy as possible when reading partial syms
as it's a serious perf issue. OTOH sometimes we're too lazy
and then some things don't work.

Requiring hyperfast reading of partial syms is becoming
less important now that we have .gdb_index and soon something
in the DWARF standard. So I'm working on being more complete
in the partial sym reader.

>> 4) Perhaps p will be visible if we run to a breakpoint in main?  (Nope.)
>>
>> (gdb) b main
>> Breakpoint 1 at 0x400525: file nested.c, line 5.
>> (gdb) run
>> Starting program: /mesquite2/.ironwood2/1158876/nested
>
> I had a quick look at how breakpoints resolution works: it sems that
> lookups don't take into account the block corresponding to the
> selected frame. So trying to put the breakpoint during execution looks
> pointless.

Yeah. We could probably do better here.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-23 10:44             ` Pierre-Marie de Rodat
  2015-07-23 13:44               ` Kevin Buettner
@ 2015-07-26 20:35               ` Doug Evans
  2015-07-31 10:53                 ` Pierre-Marie de Rodat
  1 sibling, 1 reply; 40+ messages in thread
From: Doug Evans @ 2015-07-26 20:35 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Kevin Buettner, gdb-patches

Pierre-Marie de Rodat <derodat@adacore.com> writes:
> Kevin,
>
> On 07/23/2015 02:39 AM, Kevin Buettner wrote:
>> I had to make the following change in order to obtain a clean build
>> using your patches:
>>
>> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
>> index e20aead..d6e3d55 100644
>> --- a/gdb/dwarf2read.c
>> +++ b/gdb/dwarf2read.c
>> @@ -11457,7 +11457,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>>
>>     newobj = pop_context ();
>>     /* Make a block for the local symbols within.  */
>> -  block = finish_block (newobj->name, &newobj->static_link,
>> +  block = finish_block (newobj->name, newobj->static_link,
>>   			&local_symbols, newobj->old_blocks,
>>                           lowpc, highpc);
>
> Huh, I actually have a warning I did not notice but not an error, so I
> guess you built GDB as C++. Anyway, this is a big mistake that should
> have broken the feature I intend to add: quite bad! Thank you very
> much for pointing me at it.
>
> I had a look at why testsuite was clean even with this error, and I
> realized that all my testing was with the wrong compiler[1]: this part
> of the code was actually not exercized... So I picked the proper
> compiler and this time I saw this was not working! This time I fixed
> the feature, built in C++ mode just to be sure. Here's the updated
> patch:
>
>   - I fixed yacc parsers in all languages so that block information
> from symbol lookups are properly transmitted to returned expressions.
>
>   - I fixed the usage of hash table to save static link (I do mappings
> in objfiles.c, not sets so my usage of htab was invalid).
>
> So this time, tested both with a GCC release and a patched GCC: no
> regression on x86_64-linux. I kept the "static link" terminology
> because I'm waiting for a consensus before changing everything. ;-)
>
>
> [1] In nested functions, an unpatched GCC creates local variables that
> are references to the non-local ones, so the feature works at the user
> level, but not using the static link machinery. The aim of my change
> is to make GDB work even without these "fake" local reference
> variables.
>
> -- 
> Pierre-Marie de Rodat
>
> From 2e65051fd50bb99985bbc2c8ed13c67514e9cc08 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] DWARF: handle non-local references in nested functions
>
> GDB's current behavior when dealing with non-local references in the
> context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
> references.
>
> gdb/ChangeLog:
>
> 	* ada-lang.c (ada_read_var_value): Add a VAR_BLOCK argument and pass
> 	it to default_read_var_value.
> 	* block.c (block_static_link): New accessor.
> 	* block.h (block_static_link): Declare it.
> 	* buildsym.c (finish_block_internal): Add a static_link
> 	argument.  If there is a static link, associate it to the new
> 	block.
> 	(finish_block): Add a static link argument and pass it to
> 	finish_block_internal.
> 	(end_symtab_get_static_block): Update calls to finish_block and
> 	to finish_block_internal.
> 	(end_symtab_with_blockvector): Update call to
> 	finish_block_internal.
> 	* buildsym.h: Forward-declare struct dynamic_prop.
> 	(struct context_stack): Add a static_link field.
> 	(finish_block): Add a static link argument.
> 	* c-exp.y: Remove an obsolete
> 	comment (evaluation of variables already start from the selected
> 	frame, and now they climb *up* the call stack) and propagate the
> 	block information to the produced expression.
> 	* d-exp.y: Likewise.
> 	* f-exp.y: Likewise.
> 	* go-exp.y: Likewise.
> 	* jv-exp.y: Likewise.
> 	* m2-exp.y: Likewise.
> 	* p-exp.y: Likewise.
> 	* coffread.c (coff_symtab_read): Update calls to finish_block.
> 	* dbxread.c (process_one_symbol): Likewise.
> 	* xcoffread.c (read_xcoff_symtab): Likewise.
> 	* compile/compile-c-symbols.c (convert_one_symbol): Add a
> 	VAR_BLOCK parameter and pass it to calls to read_var_value.
> 	(convert_symbol_sym): Pass the block corresponding to SYM to the
> 	call to convert_one_symbol.
> 	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
> 	call to read_var_value.
> 	* 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.
> 	* findvar.c (follow_static_link): New.
> 	(get_hosting_frame): New.
> 	(default_read_var_value): Add a VAR_BLOCK argument.  Use
> 	get_hosting_frame to handle non-local references.
> 	(read_var_value): Add a VAR_BLOCK argument and pass it to the
> 	LA_READ_VAR_VALUE method.
> 	* gdbtypes.c (resolve_dynamic_range): Update calls to
> 	dwarf2_evaluate_property.
> 	(resolve_dynamic_type_internal): Likewise.
> 	* infcmd.c (finish_command_continuation): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* infrun.c (insert_exception_resume_breakpoint): Likewise.
> 	* language.h (struct language_defn): Add a VAR_BLOCK argument to
> 	the LA_READ_VAR_VALUE method.
> 	* objfiles.c (objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	(free_objfile): Free the STATIC_LINKS hashed map if needed.
> 	* objfiles.h: Include hashtab.h.
> 	(struct objfile): Add a STATIC_LINKS field.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	* printcmd.c (print_variable_and_value): Update call to
> 	read_var_value.
> 	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
> 	* python/py-frame.c (frapy_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* python/py-framefilter.c (extract_sym): Add a SYM_BLOCK
> 	parameter and set the pointed value to NULL (TODO).
> 	(enumerate_args): Update call to extract_sym.
> 	(enumerate_locals): Update calls to extract_sym and to
> 	read_var_value.
> 	* python/py-symbol.c (sympy_value): Update call to
> 	read_var_value (TODO).
> 	* stack.c (read_frame_local): Update call to read_var_value.
> 	(read_frame_arg): Likewise.
> 	(return_command): Likewise.
> 	* symtab.h (struct symbol_block_ops): Add a get_frame_base
> 	method.
> 	(struct symbol): Add a block field.
> 	(SYMBOL_BLOCK): New accessor.
> 	* valops.c (value_of_variable): Remove frame/block handling and
> 	pass the block argument to read_var_value, which does this job
> 	now.
> 	(value_struct_elt_for_reference): Update calls to
> 	read_var_value.
> 	(value_of_this): Pass the block found to read_var_value.
> 	* value.h (read_var_value): Add a VAR_BLOCK argument.
> 	(default_read_var_value): Likewise.
>
> gdb/testsuite/ChangeLog:
>
> 	* 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.
>...

Hi.

Several nits and questions inline.  grep for ====.

One thing I still want to do is take this patch and run it through
the perf testsuite.

Also, I still need to look at follow_static_link, get_hosting_frame closer.

Cool stuff though, there's clearly missing functionality we need here.

>
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index ded195f..5c43a7a 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -13750,7 +13750,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
>  /* Implement the "la_read_var_value" language_defn method for Ada.  */
>  
>  static struct value *
> -ada_read_var_value (struct symbol *var, struct frame_info *frame)
> +ada_read_var_value (struct symbol *var, const struct block *var_block,
> +		    struct frame_info *frame)
>  {
>    const struct block *frame_block = NULL;
>    struct symbol *renaming_sym = NULL;
> @@ -13766,7 +13767,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
>  
>    /* This is a typical case where we expect the default_read_var_value
>       function to work.  */
> -  return default_read_var_value (var, frame);
> +  return default_read_var_value (var, var_block, frame);
>  }
>  
>  const struct language_defn ada_language_defn = {
> diff --git a/gdb/block.c b/gdb/block.c
> index f7621aa..f4b8e4f 100644
> --- a/gdb/block.c
> +++ b/gdb/block.c
> @@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
>    gb->compunit_symtab = cu;
>  }
>  
> +/* See block.h.  */
> +
> +struct dynamic_prop *
> +block_static_link (const struct block *block)
> +{
> +  struct objfile *objfile = block_objfile (block);
> +
> +  /* Only objfile-owned blocks that materialize top function scopes can have
> +     static links.  */
> +  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
> +    return NULL;
> +
> +  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
> +}
> +
>  /* Return the compunit of the global block.  */
>  
>  static struct compunit_symtab *
> diff --git a/gdb/block.h b/gdb/block.h
> index d8ad343..6e7d247 100644
> --- a/gdb/block.h
> +++ b/gdb/block.h
> @@ -190,6 +190,12 @@ extern struct block *allocate_global_block (struct obstack *obstack);
>  extern void set_block_compunit_symtab (struct block *,
>  				       struct compunit_symtab *);
>  
> +/* Return a property to evaluate the static link associated to BLOCK.  Note
> +   that only objfile-owned and function-level blocks can have a static link.
> +   Return NULL if there is no such property.  */
> +

====
Add a comment here stating that the term "static_link" is derived from
DW_AT_static_link.

> +extern struct dynamic_prop *block_static_link (const struct block *block);
> +
>  /* A block iterator.  This structure should be treated as though it
>     were opaque; it is only defined here because we want to support
>     stack allocation of iterators.  */
> diff --git a/gdb/buildsym.c b/gdb/buildsym.c
> index 2a24a25..a2be2cb 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,

====
Move the static_link property here.
[Arguments to functions aren't in completely random order,
and here static_link is among the collection of random things
about the block like start,end. So it reads better to me if
static_link appears with start,end]

>  		       CORE_ADDR start, CORE_ADDR end,
>  		       int is_global, int expandable)
> @@ -422,6 +423,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
>        BLOCK_FUNCTION (block) = NULL;
>      }
>  
> +  if (static_link != NULL)
> +    objfile_register_static_link (objfile, block, static_link);
> +
>    /* Now "free" the links of the list, and empty the list.  */
>  
>    for (next = *listhead; next; next = next1)
> @@ -512,11 +516,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 +1223,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 +1294,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 +1322,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..8828ad2 100644
> --- a/gdb/buildsym.h
> +++ b/gdb/buildsym.h
> @@ -39,6 +39,8 @@ struct compunit_symtab;
>  struct block;
>  struct pending_block;
>  
> +struct dynamic_prop;
> +
>  #ifndef EXTERN
>  #define	EXTERN extern
>  #endif
> @@ -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/c-exp.y b/gdb/c-exp.y
> index b408215..3b7e572 100644
> --- a/gdb/c-exp.y
> +++ b/gdb/c-exp.y
> @@ -1070,10 +1070,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/coffread.c b/gdb/coffread.c
> index 7722cdb..e41e9a5 100644
> --- a/gdb/coffread.c
> +++ b/gdb/coffread.c
> @@ -1144,7 +1144,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
>  		enter_linenos (fcn_line_ptr, fcn_first_line,
>  			       fcn_last_line, objfile);
>  
> -	      finish_block (newobj->name, &local_symbols,
> +	      finish_block (newobj->name, NULL, &local_symbols,
>  			    newobj->old_blocks, newobj->start_addr,
>  			    fcn_cs_saved.c_value
>  			    + fcn_aux_saved.x_sym.x_misc.x_fsize
> @@ -1188,7 +1188,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, newobj->old_blocks,
> +		  finish_block (0, NULL, &local_symbols, newobj->old_blocks,
>  				newobj->start_addr, tmpaddr);
>  		}
>  	      /* Now pop locals of block just finished.  */
> diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
> index 5f27583..f1dfccf 100644
> --- a/gdb/compile/compile-c-symbols.c
> +++ b/gdb/compile/compile-c-symbols.c
> @@ -134,16 +134,16 @@ symbol_substitution_name (struct symbol *sym)
>    return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
>  }
>  
> -/* Convert a given symbol, SYM, to the compiler's representation.
> -   CONTEXT is the compiler instance.  IS_GLOBAL is true if the
> -   symbol came from the global scope.  IS_LOCAL is true if the symbol
> -   came from a local scope.  (Note that the two are not strictly
> -   inverses because the symbol might have come from the static
> -   scope.)  */
> +/* Convert a given symbol, SYM (located in VAR_BLOCK, if any), to the
> +   compiler's representation.  CONTEXT is the compiler instance.  IS_GLOBAL is
> +   true if the symbol came from the global scope.  IS_LOCAL is true if the
> +   symbol came from a local scope.  (Note that the two are not strictly
> +   inverses because the symbol might have come from the static scope.)  */
>  
>  static void
>  convert_one_symbol (struct compile_c_instance *context,
>  		    struct symbol *sym,
> +		    const struct block *var_block,
>  		    int is_global,
>  		    int is_local)
>  {
> @@ -247,7 +247,7 @@ convert_one_symbol (struct compile_c_instance *context,
>  			 SYMBOL_PRINT_NAME (sym));
>  	      }
>  
> -	    val = read_var_value (sym, frame);
> +	    val = read_var_value (sym, var_block, frame);
>  	    if (VALUE_LVAL (val) != lval_memory)
>  	      error (_("Symbol \"%s\" cannot be used for compilation "
>  		       "evaluation as its address has not been found."),
> @@ -339,7 +339,8 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
>  	    fprintf_unfiltered (gdb_stdlog,
>  				"gcc_convert_symbol \"%s\": global symbol\n",
>  				identifier);
> -	  convert_one_symbol (context, global_sym.symbol, 1, 0);
> +	  convert_one_symbol (context, global_sym.symbol, global_sym.block, 1,
> +			      0);
>  	}
>      }
>  
> @@ -347,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
>      fprintf_unfiltered (gdb_stdlog,
>  			"gcc_convert_symbol \"%s\": local symbol\n",
>  			identifier);
> -  convert_one_symbol (context, sym, 0, is_local_symbol);
> +  convert_one_symbol (context, sym, block, 0, is_local_symbol);
>  }
>  
>  /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
> diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
> index 6f53814..18ca4ae 100644
> --- a/gdb/compile/compile-loc2c.c
> +++ b/gdb/compile/compile-loc2c.c
> @@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  		 "there is no selected frame"),
>  	       SYMBOL_PRINT_NAME (sym));
>  
> -      val = read_var_value (sym, frame);
> +      val = read_var_value (sym, NULL, frame);
>        if (VALUE_LVAL (val) != lval_memory)
>  	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
>  		 "as its address has not been found."),
> diff --git a/gdb/d-exp.y b/gdb/d-exp.y
> index c95222b..336b671 100644
> --- a/gdb/d-exp.y
> +++ b/gdb/d-exp.y
> @@ -1066,9 +1066,7 @@ push_variable (struct parser_state *ps, struct stoken name)
>          }
>  
>        write_exp_elt_opcode (ps, OP_VAR_VALUE);
> -      /* We want to use the selected frame, not another more inner frame
> -         which happens to be in the same block.  */
> -      write_exp_elt_block (ps, NULL);
> +      write_exp_elt_block (ps, sym.block);
>        write_exp_elt_sym (ps, sym.symbol);
>        write_exp_elt_opcode (ps, OP_VAR_VALUE);
>        return 1;
> diff --git a/gdb/dbxread.c b/gdb/dbxread.c
> index 6098b35..32893f6 100644
> --- a/gdb/dbxread.c
> +++ b/gdb/dbxread.c
> @@ -2766,8 +2766,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  	  newobj = pop_context ();
>  
>  	  /* Make a block for the local symbols within.  */
> -	  block = finish_block (newobj->name, &local_symbols,
> -				newobj->old_blocks,
> +	  block = finish_block (newobj->name, NULL,
> +				&local_symbols, newobj->old_blocks,
>  				newobj->start_addr, newobj->start_addr + valu);
>  
>  	  /* For C++, set the block's scope.  */
> @@ -2868,7 +2868,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  		  newobj->start_addr = valu;
>  		}
>  	      /* Make a block for the local symbols within.  */
> -	      finish_block (0, &local_symbols, newobj->old_blocks,
> +	      finish_block (0, NULL, &local_symbols, newobj->old_blocks,
>  			    newobj->start_addr, valu);
>  	    }
>  	}
> @@ -3165,7 +3165,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  
>  		  newobj = pop_context ();
>  		  /* Make a block for the local symbols within.  */
> -		  block = finish_block (newobj->name, &local_symbols,
> +		  block = finish_block (newobj->name, NULL, &local_symbols,
>  					newobj->old_blocks, newobj->start_addr,
>  					valu);
>  
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index c75767e..edfa220 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;
> +}

====
If this is implemented on top of symbol_block_ops::find_frame_base_location,
do we need another method? Or can we just have a wrapper that calls
find_frame_base_location?
For one, I see block_op_get_frame_base being used for both
dwarf2_block_frame_base_locexpr_funcs and
dwarf2_block_frame_base_loclist_funcs.

> +
>  /* 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 f3630ac..2415656 100644
> --- a/gdb/dwarf2loc.h
> +++ b/gdb/dwarf2loc.h
> @@ -122,12 +122,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 f440956..d6e3d55 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -1736,6 +1736,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 *);
> @@ -11393,6 +11397,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>    if (attr)
>      dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
>  
> +  /* If there is a location for the static link, record it.  */
> +  newobj->static_link = NULL;
> +  attr = dwarf2_attr (die, DW_AT_static_link, cu);
> +  if (attr)
> +    {
> +      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
> +					sizeof (*newobj->static_link));
> +      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
> +    }
> +
>    cu->list_in_scope = &local_symbols;
>  
>    if (die->child != NULL)
> @@ -11443,7 +11457,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>  
>    newobj = pop_context ();
>    /* Make a block for the local symbols within.  */
> -  block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> +  block = finish_block (newobj->name, newobj->static_link,
> +			&local_symbols, newobj->old_blocks,
>                          lowpc, highpc);
>  
>    /* For C++, set the block's scope.  */
> @@ -11529,7 +11544,7 @@ 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, newobj->old_blocks,
> +        = finish_block (0, NULL, &local_symbols, newobj->old_blocks,
>  			newobj->start_addr, highpc);
>  
>        /* Note that recording ranges after traversing children, as we
> diff --git a/gdb/f-exp.y b/gdb/f-exp.y
> index c57f919..07892e0 100644
> --- a/gdb/f-exp.y
> +++ b/gdb/f-exp.y
> @@ -521,10 +521,7 @@ variable:	name_not_typename
>  				    innermost_block = sym.block;
>  				}
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			      break;
> diff --git a/gdb/findvar.c b/gdb/findvar.c
> index 2079b4b..38b9515 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,11 +410,166 @@ 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))

====
It gets harder and harder to reason about correctness the more
we blur lines between foo-independent and foo-dependent parts of gdb.
[In debug case "foo" == "debug-format".]

I guess to begin with, why are we calling a dwarf-specific function here
and what guarantees are in place (and easily discernable from reading
the code!) that the right thing will happen for non-dwarf targets?

> +    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.  */

====
Here's a good question.
gdb has other mechanisms to catch corrupt (e.g., circular) stacks
(e.g., UNWIND_INNER_ID). Is this QUIT here for protection or in case
of really large stacks (e.g., due to infinite recursion)?

> +      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

====
!= NULL

> +	  && (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
> +   functions.
> +
> +   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, const struct block *var_block,
> +		   struct frame_info *frame)
> +{
> +  const struct block *frame_block = NULL;
> +
> +  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 function
> +	 level, the immediate upper lexical block is in an outer function:
> +	 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 function 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.  */
>  
>  struct value *
> -default_read_var_value (struct symbol *var, struct frame_info *frame)
> +default_read_var_value (struct symbol *var, const struct block *var_block,
> +			struct frame_info *frame)
>  {
>    struct value *v;
>    struct type *type = SYMBOL_TYPE (var);
> @@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
>    check_typedef (type);
>  
>    if (symbol_read_needs_frame (var))
> -    gdb_assert (frame);
> +    gdb_assert (frame != NULL);
> +
> +  if (frame != NULL)
> +    frame = get_hosting_frame (var, var_block, frame);
>  
>    if (SYMBOL_COMPUTED_OPS (var) != NULL)
>      return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
> @@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
>  /* Calls VAR's language la_read_var_value hook with the given arguments.  */
>  
>  struct value *
> -read_var_value (struct symbol *var, struct frame_info *frame)
> +read_var_value (struct symbol *var, const struct block *var_block,
> +		struct frame_info *frame)
>  {
>    const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
>  
>    gdb_assert (lang != NULL);
>    gdb_assert (lang->la_read_var_value != NULL);
>  
> -  return lang->la_read_var_value (var, frame);
> +  return lang->la_read_var_value (var, var_block, frame);
>  }
>  
>  /* Install default attributes for register values.  */
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index be761e6..fe6af7c 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -1874,7 +1874,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;
> @@ -1886,7 +1886,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;
> @@ -2128,7 +2128,8 @@ resolve_dynamic_type_internal (struct type *type,
>  
>    /* Resolve data_location attribute.  */
>    prop = TYPE_DATA_LOCATION (resolved_type);
> -  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
> +  if (prop != NULL
> +      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
>      {
>        TYPE_DYN_PROP_ADDR (prop) = value;
>        TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
> diff --git a/gdb/go-exp.y b/gdb/go-exp.y
> index 1f43306..9fa1bbd 100644
> --- a/gdb/go-exp.y
> +++ b/gdb/go-exp.y
> @@ -611,10 +611,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 4948d27..2872292 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1660,7 +1660,7 @@ finish_command_continuation (void *arg, int err)
>  	    {
>  	      struct value *func;
>  
> -	      func = read_var_value (a->function, get_current_frame ());
> +	      func = read_var_value (a->function, NULL, get_current_frame ());
>  	      TRY
>  		{
>  		  /* print_return_value can throw an exception in some
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 9a46242..0844823 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -6082,14 +6082,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
>  {
>    TRY
>      {
> -      struct symbol *vsym;
> +      struct symbol_in_block vsym;
>        struct value *value;
>        CORE_ADDR handler;
>        struct breakpoint *bp;
>  
> -      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
> -			    NULL).symbol;
> -      value = read_var_value (vsym, frame);
> +      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
> +      value = read_var_value (vsym.symbol, vsym.block, frame);
>        /* If the value was optimized out, revert to the old behavior.  */
>        if (! value_optimized_out (value))
>  	{
> diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
> index 2e6de6f..bbdb330 100644
> --- a/gdb/jv-exp.y
> +++ b/gdb/jv-exp.y
> @@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
>  	}
>  
>        write_exp_elt_opcode (par_state, OP_VAR_VALUE);
> -      /* We want to use the selected frame, not another more inner frame
> -	 which happens to be in the same block.  */
> -      write_exp_elt_block (par_state, NULL);
> +      write_exp_elt_block (par_state, sym.block);
>        write_exp_elt_sym (par_state, sym.symbol);
>        write_exp_elt_opcode (par_state, OP_VAR_VALUE);
>        return 1;
> diff --git a/gdb/language.h b/gdb/language.h
> index 2675b82..ea8442f 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -241,13 +241,19 @@ struct language_defn
>      void (*la_value_print) (struct value *, struct ui_file *,
>  			    const struct value_print_options *);
>  
> -    /* Given a symbol VAR, and a stack frame id FRAME, read the value
> -       of the variable an return (pointer to a) struct value containing
> -       the value.
> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
> +       stack frame id FRAME, read the value of the variable and return (pointer
> +       to a) struct value containing the value.
> +
> +       VAR_BLOCK is needed if there's a possibility for VAR to be outside
> +       FRAME.  This is what happens if FRAME correspond to a nested function
> +       and VAR is defined in the outer function.  If callers know that VAR is
> +       located in FRAME, NULL can be passed as VAR_BLOCK.

====
"If callers know that VAR is located in FRAME or is global, ..." ?

>  
>         Throw an error if the variable cannot be found.  */
>  
>      struct value *(*la_read_var_value) (struct symbol *var,
> +					const struct block *var_block,
>  					struct frame_info *frame);
>  
>      /* PC is possibly an unknown languages trampoline.
> diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
> index a203218..5c5652e 100644
> --- a/gdb/m2-exp.y
> +++ b/gdb/m2-exp.y
> @@ -636,10 +636,7 @@ variable:	NAME
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/objfiles.c b/gdb/objfiles.c
> index c6f9f00..95b4a97 100644
> --- a/gdb/objfiles.c
> +++ b/gdb/objfiles.c
> @@ -199,6 +199,77 @@ set_objfile_main_name (struct objfile *objfile,
>    objfile->per_bfd->language_of_main = lang;
>  }
>  
> +/* Helper structure to map blocks to static link properties in hash tables.  */
> +
> +struct static_link_htab_entry
> +{
> +  const struct block *block;
> +  struct dynamic_prop *static_link;

====
It's too bad this isn't const struct dynamic_prop *static_link;
I'm guessing it can't be that without fixing some laxness elsewhere
(which I wouldn't impose on this patch), but can you check?

> +};
> +
> +/* Return whether P1 (a struct static_link_htab_entry *) is a mapping from P2
> +   (a struct block *).  */
> +
> +static int
> +static_link_htab_entry_eq (const void *p1, const void *p2)
> +{
> +  const struct static_link_htab_entry *entry
> +    = (const struct static_link_htab_entry *) p1;
> +  const struct block *block = (const struct block *) p2;

====
blank line here

Also, this is a non-standard implementation of an htab eq function.
Generally both p1 and p2 point to an element in the hash table.

I see hashtab.h has this:

/* Compare a table entry with a possible entry.  The entry already in
   the table always comes first, so the second element can be of a
   different type (but in this case htab_find and htab_find_slot
   cannot be used; instead the variants that accept a hash value
   must be used).  */
typedef int (*htab_eq) (const void *, const void *);

so this eq function is possibly ok, except I also see calls to
htab_find,htab_find_slot below. AIUC, one of these needs to change.

> +  return block == entry->block;
> +}
> +
> +/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
> +   Must not be called more than once for each BLOCK.  */
> +
> +void
> +objfile_register_static_link (struct objfile *objfile,
> +			      const struct block *block,
> +			      struct dynamic_prop *static_link)
> +{
> +  void **slot;
> +  struct static_link_htab_entry *entry;
> +
> +  if (objfile->static_links == NULL)
> +    objfile->static_links = htab_create_alloc
> +      (1, htab_hash_pointer, static_link_htab_entry_eq, NULL,
> +       xcalloc, xfree);
> +
> +  /* Create a slot for the mapping, make sure it's the first mapping for this
> +     block and then create the mapping itself.  */
> +  slot = htab_find_slot (objfile->static_links, block, INSERT);
> +  gdb_assert (*slot == NULL);
> +
> +  entry = (struct static_link_htab_entry *) obstack_alloc
> +	    (&objfile->objfile_obstack, sizeof (*entry));
> +  entry->block = block;
> +  entry->static_link = static_link;
> +  *slot = (void *) entry;
> +}
> +
> +/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
> +   none was found.  */
> +
> +struct dynamic_prop *
> +objfile_lookup_static_link (struct objfile *objfile,
> +			    const struct block *block)
> +{
> +  struct static_link_htab_entry *entry;
> +
> +  if (objfile->static_links == NULL)
> +    return NULL;
> +  entry
> +    = (struct static_link_htab_entry *) htab_find (objfile->static_links,
> +						   block);
> +  if (entry == NULL)
> +    return NULL;
> +  else

====
I don't know how others feel, but "else" clauses in particular situations
like this are just noise. How about removing it?

> +    {
> +      gdb_assert (entry->block == block);
> +      return entry->static_link;
> +    }
> +}
> +
>  \f
>  
>  /* Called via bfd_map_over_sections to build up the section table that
> @@ -653,6 +724,11 @@ free_objfile (struct objfile *objfile)
>    /* Rebuild section map next time we need it.  */
>    get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
>  
> +  /* Free the map for static links.  There's no need to free static link
> +     themselves since they were allocated on the objstack.  */
> +  if (objfile->static_links != NULL)
> +    htab_delete (objfile->static_links);
> +
>    /* The last thing we do is free the objfile struct itself.  */
>    xfree (objfile);
>  }
> diff --git a/gdb/objfiles.h b/gdb/objfiles.h
> index a0dc69b..aa2e966 100644
> --- a/gdb/objfiles.h
> +++ b/gdb/objfiles.h
> @@ -20,6 +20,7 @@
>  #if !defined (OBJFILES_H)
>  #define OBJFILES_H
>  
> +#include "hashtab.h"
>  #include "gdb_obstack.h"	/* For obstack internals.  */
>  #include "symfile.h"		/* For struct psymbol_allocation_list.  */
>  #include "progspace.h"
> @@ -412,6 +413,16 @@ struct objfile
>         table, so we have to keep them here to relocate them
>         properly.  */
>      struct symbol *template_symbols;
> +
> +    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
> +       block *) that have one.  For nested functions, the static link is the
> +       expression that computes the frame base of the lexically enclosing
> +       function.
> +
> +       Very few blocks have a static link, so it's more memory efficient to
> +       store these here.  Static links must be allocated on the objfile's
> +       obstack.  */
> +    struct htab *static_links;

====
s/struct htab */htab_t /

>    };
>  
>  /* Defines for the objfile flag word.  */
> @@ -719,4 +730,11 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
>  extern void set_objfile_main_name (struct objfile *objfile,
>  				   const char *name, enum language lang);
>  
> +extern void objfile_register_static_link (struct objfile *objfile,
> +					  const struct block *block,
> +					  struct dynamic_prop *static_link);
> +
> +extern struct dynamic_prop *objfile_lookup_static_link
> +  (struct objfile *objfile, const struct block *block);
> +
>  #endif /* !defined (OBJFILES_H) */
> diff --git a/gdb/p-exp.y b/gdb/p-exp.y
> index a2f86d6..173d9fb 100644
> --- a/gdb/p-exp.y
> +++ b/gdb/p-exp.y
> @@ -769,10 +769,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			      current_type = sym.symbol->type; }
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index f51e25c..553cc71 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
>        struct value *val;
>        struct value_print_options opts;
>  
> -      val = read_var_value (var, frame);
> +      /* READ_VAR_VALUE needs a block in order to deal with non-local
> +	 references (i.e. to handle nested functions).  In this context, we
> +	 print variables that are local to this frame, so we can avoid passing
> +	 a block to it.  */
> +      val = read_var_value (var, NULL, frame);
>        get_user_print_options (&opts);
>        opts.deref_ref = 1;
>        common_val_print (val, stream, indent, &opts, current_language);
> diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
> index e3d4867..345642e 100644
> --- a/gdb/python/py-finishbreakpoint.c
> +++ b/gdb/python/py-finishbreakpoint.c
> @@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>                    /* Ignore Python errors at this stage.  */
>                    self_bpfinish->return_type = type_to_type_object (ret_type);
>                    PyErr_Clear ();
> -                  func_value = read_var_value (function, frame);
> +                  func_value = read_var_value (function, NULL, frame);
>                    self_bpfinish->function_value =
>                        value_to_value_object (func_value);
>                    PyErr_Clear ();
> diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
> index 7290056..fa7937a 100644
> --- a/gdb/python/py-frame.c
> +++ b/gdb/python/py-frame.c
> @@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
>    struct frame_info *frame;
>    PyObject *sym_obj, *block_obj = NULL;
>    struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
> +  const struct block *block = NULL;
>    struct value *val = NULL;
>  
>    if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
> @@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
>    else if (gdbpy_is_string (sym_obj))
>      {
>        char *var_name;
> -      const struct block *block = NULL;
>        struct cleanup *cleanup;
>  
>        var_name = python_string_to_target_string (sym_obj);
> @@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
>  
>        TRY
>  	{
> +	  struct symbol_in_block lookup_sym;
>  	  FRAPY_REQUIRE_VALID (self, frame);
>  
>  	  if (!block)
>  	    block = get_frame_block (frame, NULL);
> -	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
> +	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
> +	  var = lookup_sym.symbol;
> +	  block = lookup_sym.block;
>  	}
>        CATCH (except, RETURN_MASK_ALL)
>  	{
> @@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
>      {
>        FRAPY_REQUIRE_VALID (self, frame);
>  
> -      val = read_var_value (var, frame);
> +      val = read_var_value (var, block, frame);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
> index e3336b1..397ac86 100644
> --- a/gdb/python/py-framefilter.c
> +++ b/gdb/python/py-framefilter.c
> @@ -43,16 +43,17 @@ enum mi_print_types
>     NAME is a  pass-through argument where the name of  the symbol will
>     be written.  NAME is allocated in  this function, but the caller is
>     responsible for clean up.  SYM is a pass-through argument where the
> -   symbol will be written.  In the case of the API returning a string,
> -   this will be set to NULL.  LANGUAGE is also a pass-through argument
> -   denoting the language attributed to the Symbol.  In the case of SYM
> -   being  NULL, this  will be  set to  the current  language.  Returns
> -   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
> -   EXT_LANG_BT_OK on success.  */
> +   symbol will be written and  SYM_BLOCK is a pass-through argument to
> +   write  the block where the symbol lies in.  In the case of the  API
> +   returning a  string,  this will be set to NULL.  LANGUAGE is also a
> +   pass-through  argument  denoting  the  language  attributed  to the
> +   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
> +   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
> +   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
>  
>  static enum ext_lang_bt_status
>  extract_sym (PyObject *obj, char **name, struct symbol **sym,
> -	     const struct language_defn **language)
> +	     struct block **sym_block, const struct language_defn **language)
>  {
>    PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
>  
> @@ -75,12 +76,17 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
>  	python_language.  */
>        *language = python_language;
>        *sym = NULL;
> +      *sym_block = NULL;
>      }
>    else
>      {
>        /* This type checks 'result' during the conversion so we
>  	 just call it unconditionally and check the return.  */
>        *sym = symbol_object_to_symbol (result);
> +      /* TODO:  How should we find the corresponding block for this symbol?
> +	 Should we lookup all blocks in the owning objfile?  Should we store
> +	 the bloc kin the Symbol object?  */
> +      *sym_block = NULL;
>  
>        Py_DECREF (result);
>  
> @@ -537,10 +543,11 @@ enumerate_args (PyObject *iter,
>        const struct language_defn *language;
>        char *sym_name;
>        struct symbol *sym;
> +      struct block *sym_block;
>        struct value *val;
>        enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
>  
> -      success = extract_sym (item, &sym_name, &sym, &language);
> +      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
>        if (success == EXT_LANG_BT_ERROR)
>  	{
>  	  Py_DECREF (item);
> @@ -736,12 +743,13 @@ enumerate_locals (PyObject *iter,
>        struct value *val;
>        enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
>        struct symbol *sym;
> +      struct block *sym_block;
>        int local_indent = 8 + (8 * indent);
>        struct cleanup *locals_cleanups;
>  
>        locals_cleanups = make_cleanup_py_decref (item);
>  
> -      success = extract_sym (item, &sym_name, &sym, &language);
> +      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
>        if (success == EXT_LANG_BT_ERROR)
>  	{
>  	  do_cleanups (locals_cleanups);
> @@ -769,7 +777,7 @@ enumerate_locals (PyObject *iter,
>  	{
>  	  TRY
>  	    {
> -	      val = read_var_value (sym, frame);
> +	      val = read_var_value (sym, sym_block, frame);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
> index 401e7e9..b58e59d 100644
> --- a/gdb/python/py-symbol.c
> +++ b/gdb/python/py-symbol.c
> @@ -278,7 +278,10 @@ sympy_value (PyObject *self, PyObject *args)
>        if (symbol_read_needs_frame (symbol) && frame_info == NULL)
>  	error (_("symbol requires a frame to compute its value"));
>  
> -      value = read_var_value (symbol, frame_info);
> +      /* TODO: How should we find the corresponding block for this symbol?
> +	 Should we lookup all blocks in the owning objfile?  Should we store
> +	 the block in the Symbol object?  */
> +      value = read_var_value (symbol, NULL, frame_info);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/stack.c b/gdb/stack.c
> index b4cfdbd..5a18a06 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
>  
>    TRY
>      {
> -      argp->val = read_var_value (sym, frame);
> +      argp->val = read_var_value (sym, NULL, frame);
>      }
>    CATCH (except, RETURN_MASK_ERROR)
>      {
> @@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
>      {
>        TRY
>  	{
> -	  val = read_var_value (sym, frame);
> +	  val = read_var_value (sym, NULL, frame);
>  	}
>        CATCH (except, RETURN_MASK_ERROR)
>  	{
> @@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
>  
>  	  TRY
>  	    {
> -	      val = read_var_value (sym, frame);
> +	      val = read_var_value (sym, NULL, frame);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> @@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
>  	value_fetch_lazy (return_value);
>  
>        if (thisfun != NULL)
> -	function = read_var_value (thisfun, thisframe);
> +	function = read_var_value (thisfun, NULL, thisframe);
>  
>        rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
>        if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index 73026b3..509537b 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 functions
> +     handling).  Static links are function properties whose evaluation return

====
s/return/returns/

> +     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 fuctions, 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.  */
> diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
> new file mode 100644
> index 0000000..967eb2f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp1.c
> @@ -0,0 +1,37 @@
> +/* 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 function 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..9720f5b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp1.exp
> @@ -0,0 +1,55 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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..a6449e34
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp2.c
> @@ -0,0 +1,48 @@
> +/* 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..a107d1c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp2.exp
> @@ -0,0 +1,64 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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..a51f417
> --- /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);
> +
> +extern void process (callback_t cb);
> +extern 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..8f9b522
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp3.exp
> @@ -0,0 +1,55 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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.
> +
> +gdb_test "print first"        "1"
> +gdb_test "print parent_first" "1"
> diff --git a/gdb/valops.c b/gdb/valops.c
> index d326f93..94182c5 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1288,27 +1288,12 @@ value_repeat (struct value *arg1, int count)
>  struct value *
>  value_of_variable (struct symbol *var, const struct block *b)
>  {
> -  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);
> +  return read_var_value (var, b, frame);
>  }
>  
>  struct value *
> @@ -3459,9 +3444,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
>  		return NULL;
>  
>  	      if (want_address)
> -		return value_addr (read_var_value (s, 0));
> +		return value_addr (read_var_value (s, 0, 0));
>  	      else
> -		return read_var_value (s, 0);
> +		return read_var_value (s, 0, 0);
>  	    }
>  
>  	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
> @@ -3489,7 +3474,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
>  	      if (s == NULL)
>  		return NULL;
>  
> -	      v = read_var_value (s, 0);
> +	      v = read_var_value (s, 0, 0);
>  	      if (!want_address)
>  		result = v;
>  	      else
> @@ -3725,7 +3710,7 @@ value_full_object (struct value *argp,
>  struct value *
>  value_of_this (const struct language_defn *lang)
>  {
> -  struct symbol *sym;
> +  struct symbol_in_block sym;
>    const struct block *b;
>    struct frame_info *frame;
>  
> @@ -3736,12 +3721,12 @@ value_of_this (const struct language_defn *lang)
>  
>    b = get_frame_block (frame, NULL);
>  
> -  sym = lookup_language_this (lang, b).symbol;
> -  if (sym == NULL)
> +  sym = lookup_language_this (lang, b);
> +  if (sym.symbol == NULL)
>      error (_("current stack frame does not contain a variable named `%s'"),
>  	   lang->la_name_of_this);
>  
> -  return read_var_value (sym, frame);
> +  return read_var_value (sym.symbol, sym.block, frame);
>  }
>  
>  /* Return the value of the local variable, if one exists.  Return NULL
> diff --git a/gdb/value.h b/gdb/value.h
> index 7ff6aa8..c35a876 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -670,9 +670,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
>  extern int symbol_read_needs_frame (struct symbol *);
>  
>  extern struct value *read_var_value (struct symbol *var,
> +				     const struct block *var_block,
>  				     struct frame_info *frame);
>  
>  extern struct value *default_read_var_value (struct symbol *var,
> +					     const struct block *var_block,
>  					     struct frame_info *frame);
>  
>  extern struct value *allocate_value (struct type *type);
> diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
> index b5b2a1d..dea24a4 100644
> --- a/gdb/xcoffread.c
> +++ b/gdb/xcoffread.c
> @@ -1388,8 +1388,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
>  		  break;
>  		}
>  
> -	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> -			    newobj->start_addr,
> +	      finish_block (newobj->name, NULL, &local_symbols,
> +			    newobj->old_blocks, newobj->start_addr,
>  			    (fcn_cs_saved.c_value
>  			     + fcn_aux_saved.x_sym.x_misc.x_fsize
>  			     + ANOFFSET (objfile->section_offsets,

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-26 20:35               ` Doug Evans
@ 2015-07-31 10:53                 ` Pierre-Marie de Rodat
  2015-08-10  8:34                   ` Pierre-Marie de Rodat
                                     ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-07-31 10:53 UTC (permalink / raw)
  To: Doug Evans; +Cc: Kevin Buettner, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 8557 bytes --]

On 07/26/2015 10:34 PM, Doug Evans wrote:
> Hi.
>
> Several nits and questions inline.  grep for ====.

Thank you for reviewing!

> One thing I still want to do is take this patch and run it through
> the perf testsuite.
>
> Also, I still need to look at follow_static_link, get_hosting_frame closer.

Okay.

> Cool stuff though, there's clearly missing functionality we need here.

Indeed, thanks! For the record, just like for the block_found business, 
I re-enabled Guile support in my builds and propagated the support for 
non-local references to the Guile API.

>> +/* Return a property to evaluate the static link associated to BLOCK.  Note
>> +   that only objfile-owned and function-level blocks can have a static link.
>> +   Return NULL if there is no such property.  */
>> +
>
> ====
> Add a comment here stating that the term "static_link" is derived from
> DW_AT_static_link.

Done. I also added one in objfiles.h, for struct objfile's static_links 
field.

>> -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,
>
> ====
> Move the static_link property here.
> [Arguments to functions aren't in completely random order,
> and here static_link is among the collection of random things
> about the block like start,end. So it reads better to me if
> static_link appears with start,end]

Fine by me: done and callers updated.

>> +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;
>> +}
>
> ====
> If this is implemented on top of symbol_block_ops::find_frame_base_location,
> do we need another method? Or can we just have a wrapper that calls
> find_frame_base_location?
> For one, I see block_op_get_frame_base being used for both
> dwarf2_block_frame_base_locexpr_funcs and
> dwarf2_block_frame_base_loclist_funcs.

Correct me if I'm wrong, but the problem here is that if we aren't 
handling a "DWARF-described function", then we cannot assume that the 
find_frame_base_location method yields a location description. Mhm... 
maybe I should change it to return a dynamic property instead, then: 
what do you think?

>> +/* 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))
>
> ====
> It gets harder and harder to reason about correctness the more
> we blur lines between foo-independent and foo-dependent parts of gdb.
> [In debug case "foo" == "debug-format".]

Agreed.

> I guess to begin with, why are we calling a dwarf-specific function here
> and what guarantees are in place (and easily discernable from reading
> the code!) that the right thing will happen for non-dwarf targets?

My interpretation is that even though dynamic properties seem to be used 
only with DWARF info., they should not be specific to it. In other 
words, dwarf2_evaluate_property should be called instead something like 
"evaluate_dynamic_prop" and moved elsewhere. After all, struct 
dynamic_prop isn't supposed to be itself DWARF-specific, and it is 
defined in gdbtypes.h.

>> +      /* Protect ourselves against bad things such as circular call stacks.  */
>
> ====
> Here's a good question.
> gdb has other mechanisms to catch corrupt (e.g., circular) stacks
> (e.g., UNWIND_INNER_ID). Is this QUIT here for protection or in case
> of really large stacks (e.g., due to infinite recursion)?
>
>> +      QUIT;

I wasn't aware of these mechanisms: thanks! Well, I had indeed circular 
stacks in mind, but this QUIT is also here to let users stop heavy 
computations in case of huge stacks (Joel advised me live to do this for 
this reason). So the comment is misleading and I have updated it. Thanks!

>> +      if (framefunc != NULL
>> +	  && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base
>
> ====
> != NULL

Done.

>> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
>> +       stack frame id FRAME, read the value of the variable and return (pointer
>> +       to a) struct value containing the value.
>> +
>> +       VAR_BLOCK is needed if there's a possibility for VAR to be outside
>> +       FRAME.  This is what happens if FRAME correspond to a nested function
>> +       and VAR is defined in the outer function.  If callers know that VAR is
>> +       located in FRAME, NULL can be passed as VAR_BLOCK.
>
> ====
> "If callers know that VAR is located in FRAME or is global, ..." ?

Indeed. I added "or is global/static" instead.

>> +struct static_link_htab_entry
>> +{
>> +  const struct block *block;
>> +  struct dynamic_prop *static_link;
>
> ====
> It's too bad this isn't const struct dynamic_prop *static_link;
> I'm guessing it can't be that without fixing some laxness elsewhere
> (which I wouldn't impose on this patch), but can you check?

I thought it would indeed bring a lot of changes everywhere... but it's 
not actually! I could add const qualifiers everywhere on dynamic 
properties in objfiles.* without trouble at all and added a coulpe in 
buildsym.* as well. Thanks for suggesting this!

>> +static int
>> +static_link_htab_entry_eq (const void *p1, const void *p2)
>> +{
>> +  const struct static_link_htab_entry *entry
>> +    = (const struct static_link_htab_entry *) p1;
>> +  const struct block *block = (const struct block *) p2;
>
> ====
> blank line here

Done.

> Also, this is a non-standard implementation of an htab eq function.
> Generally both p1 and p2 point to an element in the hash table.
>
> I see hashtab.h has this:
>
> /* Compare a table entry with a possible entry.  The entry already in
>     the table always comes first, so the second element can be of a
>     different type (but in this case htab_find and htab_find_slot
>     cannot be used; instead the variants that accept a hash value
>     must be used).  */
> typedef int (*htab_eq) (const void *, const void *);
>
> so this eq function is possibly ok, except I also see calls to
> htab_find,htab_find_slot below. AIUC, one of these needs to change.

Yeah... I spent some time before having something that actually worked 
(first time I used this container) and got it wrong wrt. to doc anyway. 
Now, I eventually understood that all hash table lookups must be done 
with struct static_link_htab_entry * instead of struct block *, so I 
could fix the htab_eq function to be commutative.

>> +  if (entry == NULL)
>> +    return NULL;
>> +  else
>
> ====
> I don't know how others feel, but "else" clauses in particular situations
> like this are just noise. How about removing it?

Sure, removed.

>> +    struct htab *static_links;
>
> ====
> s/struct htab */htab_t /

Done.

>> +
>> +  /* 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 functions
>> +     handling).  Static links are function properties whose evaluation return
>
> ====
> s/return/returns/

Fixed: thanks!

Updated patch is attached and tested again on x86_64-linux.

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-DWARF-handle-non-local-references-in-nested-function.patch --]
[-- Type: text/x-diff, Size: 78999 bytes --]

From 26961370aaa5343e0164ded82dc7531a44bebc6d 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] DWARF: handle non-local references in nested functions

GDB's current behavior when dealing with non-local references in the
context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
references.

gdb/ChangeLog:

	* ada-lang.c (ada_read_var_value): Add a var_block argument
	and pass it to default_read_var_value.
	* block.c (block_static_link): New accessor.
	* block.h (block_static_link): Declare it.
	* buildsym.c (finish_block_internal): Add a static_link
	argument.  If there is a static link, associate it to the new
	block.
	(finish_block): Add a static link argument and pass it to
	finish_block_internal.
	(end_symtab_get_static_block): Update calls to finish_block and
	to finish_block_internal.
	(end_symtab_with_blockvector): Update call to
	finish_block_internal.
	* buildsym.h: Forward-declare struct dynamic_prop.
	(struct context_stack): Add a static_link field.
	(finish_block): Add a static link argument.
	* c-exp.y: Remove an obsolete comment (evaluation of variables
	already start from the selected frame, and now they climb *up*
	the call stack) and propagate the block information to the
	produced expression.
	* d-exp.y: Likewise.
	* f-exp.y: Likewise.
	* go-exp.y: Likewise.
	* jv-exp.y: Likewise.
	* m2-exp.y: Likewise.
	* p-exp.y: Likewise.
	* coffread.c (coff_symtab_read): Update calls to finish_block.
	* dbxread.c (process_one_symbol): Likewise.
	* xcoffread.c (read_xcoff_symtab): Likewise.
	* compile/compile-c-symbols.c (convert_one_symbol): Promote the
	"sym" parameter to struct block_symbol, update its uses and pass
	its block to calls to read_var_value.
	(convert_symbol_sym): Update the calls to convert_one_symbol.
	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
	call to read_var_value.
	* 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.
	* findvar.c (follow_static_link): New.
	(get_hosting_frame): New.
	(default_read_var_value): Add a var_block argument.  Use
	get_hosting_frame to handle non-local references.
	(read_var_value): Add a var_block argument and pass it to the
	LA_READ_VAR_VALUE method.
	* gdbtypes.c (resolve_dynamic_range): Update calls to
	dwarf2_evaluate_property.
	(resolve_dynamic_type_internal): Likewise.
	* guile/scm-frame.c (gdbscm_frame_read_var): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* guile/scm-symbol.c (gdbscm_symbol_value): Update call to
	read_var_value (TODO).
	* infcmd.c (finish_command_continuation): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* infrun.c (insert_exception_resume_breakpoint): Likewise.
	* language.h (struct language_defn): Add a var_block argument to
	the LA_READ_VAR_VALUE method.
	* objfiles.c (struct static_link_htab_entry): New.
	(static_link_htab_entry_hash): New.
	(static_link_htab_entry_eq): New.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	(free_objfile): Free the STATIC_LINKS hashed map if needed.
	* objfiles.h: Include hashtab.h.
	(struct objfile): Add a static_links field.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	* printcmd.c (print_variable_and_value): Update call to
	read_var_value.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
	* python/py-frame.c (frapy_read_var): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* python/py-framefilter.c (extract_sym): Add a sym_block
	parameter and set the pointed value to NULL (TODO).
	(enumerate_args): Update call to extract_sym.
	(enumerate_locals): Update calls to extract_sym and to
	read_var_value.
	* python/py-symbol.c (sympy_value): Update call to
	read_var_value (TODO).
	* stack.c (read_frame_local): Update call to read_var_value.
	(read_frame_arg): Likewise.
	(return_command): Likewise.
	* symtab.h (struct symbol_block_ops): Add a get_frame_base
	method.
	(struct symbol): Add a block field.
	(SYMBOL_BLOCK): New accessor.
	* valops.c (value_of_variable): Remove frame/block handling and
	pass the block argument to read_var_value, which does this job
	now.
	(value_struct_elt_for_reference): Update calls to
	read_var_value.
	(value_of_this): Pass the block found to read_var_value.
	* value.h (read_var_value): Add a var_block argument.
	(default_read_var_value): Likewise.

gdb/testsuite/ChangeLog:

	* 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                          |   5 +-
 gdb/block.c                             |  15 +++
 gdb/block.h                             |  11 +++
 gdb/buildsym.c                          |  19 ++--
 gdb/buildsym.h                          |  15 ++-
 gdb/c-exp.y                             |   5 +-
 gdb/coffread.c                          |   6 +-
 gdb/compile/compile-c-symbols.c         |  74 +++++++-------
 gdb/compile/compile-loc2c.c             |   2 +-
 gdb/d-exp.y                             |   4 +-
 gdb/dbxread.c                           |   8 +-
 gdb/dwarf2loc.c                         |  52 ++++++++--
 gdb/dwarf2loc.h                         |  11 ++-
 gdb/dwarf2read.c                        |  18 +++-
 gdb/f-exp.y                             |   5 +-
 gdb/findvar.c                           | 168 +++++++++++++++++++++++++++++++-
 gdb/gdbtypes.c                          |   7 +-
 gdb/go-exp.y                            |   5 +-
 gdb/guile/scm-frame.c                   |   9 +-
 gdb/guile/scm-symbol.c                  |   6 +-
 gdb/infcmd.c                            |   2 +-
 gdb/infrun.c                            |   7 +-
 gdb/jv-exp.y                            |   4 +-
 gdb/language.h                          |  12 ++-
 gdb/m2-exp.y                            |   5 +-
 gdb/objfiles.c                          |  91 +++++++++++++++++
 gdb/objfiles.h                          |  22 +++++
 gdb/p-exp.y                             |   5 +-
 gdb/printcmd.c                          |   6 +-
 gdb/python/py-finishbreakpoint.c        |   2 +-
 gdb/python/py-frame.c                   |   9 +-
 gdb/python/py-framefilter.c             |  29 ++++--
 gdb/python/py-symbol.c                  |   6 +-
 gdb/stack.c                             |   8 +-
 gdb/symtab.h                            |  19 ++++
 gdb/testsuite/gdb.base/nested-subp1.c   |  37 +++++++
 gdb/testsuite/gdb.base/nested-subp1.exp |  55 +++++++++++
 gdb/testsuite/gdb.base/nested-subp2.c   |  48 +++++++++
 gdb/testsuite/gdb.base/nested-subp2.exp |  64 ++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.c   |  66 +++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.exp |  55 +++++++++++
 gdb/valops.c                            |  35 ++-----
 gdb/value.h                             |   2 +
 gdb/xcoffread.c                         |   5 +-
 44 files changed, 881 insertions(+), 158 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 049fb48..3f0bdb1 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13749,7 +13749,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
 /* Implement the "la_read_var_value" language_defn method for Ada.  */
 
 static struct value *
-ada_read_var_value (struct symbol *var, struct frame_info *frame)
+ada_read_var_value (struct symbol *var, const struct block *var_block,
+		    struct frame_info *frame)
 {
   const struct block *frame_block = NULL;
   struct symbol *renaming_sym = NULL;
@@ -13765,7 +13766,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
 
   /* This is a typical case where we expect the default_read_var_value
      function to work.  */
-  return default_read_var_value (var, frame);
+  return default_read_var_value (var, var_block, frame);
 }
 
 const struct language_defn ada_language_defn = {
diff --git a/gdb/block.c b/gdb/block.c
index f7621aa..f4b8e4f 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
   gb->compunit_symtab = cu;
 }
 
+/* See block.h.  */
+
+struct dynamic_prop *
+block_static_link (const struct block *block)
+{
+  struct objfile *objfile = block_objfile (block);
+
+  /* Only objfile-owned blocks that materialize top function scopes can have
+     static links.  */
+  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
+    return NULL;
+
+  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
+}
+
 /* Return the compunit of the global block.  */
 
 static struct compunit_symtab *
diff --git a/gdb/block.h b/gdb/block.h
index d8ad343..aac7929 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -190,6 +190,17 @@ extern struct block *allocate_global_block (struct obstack *obstack);
 extern void set_block_compunit_symtab (struct block *,
 				       struct compunit_symtab *);
 
+/* Return a property to evaluate the static link associated to BLOCK.
+
+   In the context of nested functions (available in Pascal, Ada and GNU C, for
+   instance), a static link (as in DWARF's DW_AT_static_link attribute) for a
+   function is a way to get the frame corresponding to the enclosing function.
+
+   Note that only objfile-owned and function-level blocks can have a static
+   link.  Return NULL if there is no such property.  */
+
+extern struct dynamic_prop *block_static_link (const struct block *block);
+
 /* A block iterator.  This structure should be treated as though it
    were opaque; it is only defined here because we want to support
    stack allocation of iterators.  */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 2a24a25..ba4f219 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -331,8 +331,10 @@ 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 pending **listhead,
 		       struct pending_block *old_blocks,
+		       const struct dynamic_prop *static_link,
 		       CORE_ADDR start, CORE_ADDR end,
 		       int is_global, int expandable)
 {
@@ -422,6 +424,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
       BLOCK_FUNCTION (block) = NULL;
     }
 
+  if (static_link != NULL)
+    objfile_register_static_link (objfile, block, static_link);
+
   /* Now "free" the links of the list, and empty the list.  */
 
   for (next = *listhead; next; next = next1)
@@ -512,11 +517,13 @@ 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 pending **listhead,
 	      struct pending_block *old_blocks,
+	      const struct dynamic_prop *static_link,
 	      CORE_ADDR start, CORE_ADDR end)
 {
-  return finish_block_internal (symbol, listhead, old_blocks,
+  return finish_block_internal (symbol, listhead, old_blocks, static_link,
 				start, end, 0, 0);
 }
 
@@ -1218,7 +1225,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, &local_symbols, cstk->old_blocks, NULL,
 		    cstk->start_addr, end_addr);
 
       if (context_stack_depth > 0)
@@ -1289,7 +1296,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, &file_symbols, NULL, NULL,
 				    last_source_start_addr, end_addr,
 				    0, expandable);
     }
@@ -1317,7 +1324,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, &global_symbols, NULL, NULL,
 			 last_source_start_addr, end_addr,
 			 1, expandable);
   blockvector = make_blockvector ();
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index f98203e..81c00f3 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -39,6 +39,8 @@ struct compunit_symtab;
 struct block;
 struct pending_block;
 
+struct dynamic_prop;
+
 #ifndef EXTERN
 #define	EXTERN extern
 #endif
@@ -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,11 @@ 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 pending **listhead,
+				   struct pending_block *old_blocks,
+				   const struct dynamic_prop *static_link,
+				   CORE_ADDR start,
+				   CORE_ADDR end);
 
 extern void record_block_range (struct block *,
                                 CORE_ADDR start, CORE_ADDR end_inclusive);
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 59cecb5..9504e92 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1072,10 +1072,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 7722cdb..c0f4267 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1144,8 +1144,8 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
 		enter_linenos (fcn_line_ptr, fcn_first_line,
 			       fcn_last_line, objfile);
 
-	      finish_block (newobj->name, &local_symbols,
-			    newobj->old_blocks, newobj->start_addr,
+	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+			    NULL, newobj->start_addr,
 			    fcn_cs_saved.c_value
 			    + fcn_aux_saved.x_sym.x_misc.x_fsize
 			    + ANOFFSET (objfile->section_offsets,
@@ -1188,7 +1188,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, newobj->old_blocks,
+		  finish_block (0, &local_symbols, newobj->old_blocks, NULL,
 				newobj->start_addr, tmpaddr);
 		}
 	      /* Now pop locals of block just finished.  */
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 21ce655..355b063 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -143,26 +143,26 @@ symbol_substitution_name (struct symbol *sym)
 
 static void
 convert_one_symbol (struct compile_c_instance *context,
-		    struct symbol *sym,
+		    struct block_symbol sym,
 		    int is_global,
 		    int is_local)
 {
   gcc_type sym_type;
-  const char *filename = symbol_symtab (sym)->filename;
-  unsigned short line = SYMBOL_LINE (sym);
+  const char *filename = symbol_symtab (sym.symbol)->filename;
+  unsigned short line = SYMBOL_LINE (sym.symbol);
 
-  error_symbol_once (context, sym);
+  error_symbol_once (context, sym.symbol);
 
-  if (SYMBOL_CLASS (sym) == LOC_LABEL)
+  if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
     sym_type = 0;
   else
-    sym_type = convert_type (context, SYMBOL_TYPE (sym));
+    sym_type = convert_type (context, SYMBOL_TYPE (sym.symbol));
 
-  if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
+  if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
     {
       /* Binding a tag, so we don't need to build a decl.  */
       C_CTX (context)->c_ops->tagbind (C_CTX (context),
-				       SYMBOL_NATURAL_NAME (sym),
+				       SYMBOL_NATURAL_NAME (sym.symbol),
 				       sym_type, filename, line);
     }
   else
@@ -172,7 +172,7 @@ convert_one_symbol (struct compile_c_instance *context,
       CORE_ADDR addr = 0;
       char *symbol_name = NULL;
 
-      switch (SYMBOL_CLASS (sym))
+      switch (SYMBOL_CLASS (sym.symbol))
 	{
 	case LOC_TYPEDEF:
 	  kind = GCC_C_SYMBOL_TYPEDEF;
@@ -180,45 +180,46 @@ convert_one_symbol (struct compile_c_instance *context,
 
 	case LOC_LABEL:
 	  kind = GCC_C_SYMBOL_LABEL;
-	  addr = SYMBOL_VALUE_ADDRESS (sym);
+	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
 	  break;
 
 	case LOC_BLOCK:
 	  kind = GCC_C_SYMBOL_FUNCTION;
-	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
-	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
+	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
 	    addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
 	  break;
 
 	case LOC_CONST:
-	  if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
+	  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
 	    {
 	      /* Already handled by convert_enum.  */
 	      return;
 	    }
-	  C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
-						  SYMBOL_NATURAL_NAME (sym),
-						  SYMBOL_VALUE (sym),
-						  filename, line);
+	  C_CTX (context)->c_ops->build_constant
+	    (C_CTX (context),
+	     sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+	     SYMBOL_VALUE (sym.symbol),
+	     filename, line);
 	  return;
 
 	case LOC_CONST_BYTES:
 	  error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
-		 SYMBOL_PRINT_NAME (sym));
+		 SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_UNDEF:
 	  internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
-			  SYMBOL_PRINT_NAME (sym));
+			  SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_COMMON_BLOCK:
 	  error (_("Fortran common block is unsupported for compilation "
 		   "evaluaton of symbol \"%s\"."),
-		 SYMBOL_PRINT_NAME (sym));
+		 SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_OPTIMIZED_OUT:
 	  error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		   "as it is optimized out."),
-		 SYMBOL_PRINT_NAME (sym));
+		 SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_COMPUTED:
 	  if (is_local)
@@ -227,7 +228,7 @@ convert_one_symbol (struct compile_c_instance *context,
 	  warning (_("Symbol \"%s\" is thread-local and currently can only "
 		     "be referenced from the current thread in "
 		     "compiled code."),
-		   SYMBOL_PRINT_NAME (sym));
+		   SYMBOL_PRINT_NAME (sym.symbol));
 	  /* FALLTHROUGH */
 	case LOC_UNRESOLVED:
 	  /* 'symbol_name' cannot be used here as that one is used only for
@@ -238,20 +239,20 @@ convert_one_symbol (struct compile_c_instance *context,
 	    struct value *val;
 	    struct frame_info *frame = NULL;
 
-	    if (symbol_read_needs_frame (sym))
+	    if (symbol_read_needs_frame (sym.symbol))
 	      {
 		frame = get_selected_frame (NULL);
 		if (frame == NULL)
 		  error (_("Symbol \"%s\" cannot be used because "
 			   "there is no selected frame"),
-			 SYMBOL_PRINT_NAME (sym));
+			 SYMBOL_PRINT_NAME (sym.symbol));
 	      }
 
-	    val = read_var_value (sym, frame);
+	    val = read_var_value (sym.symbol, sym.block, frame);
 	    if (VALUE_LVAL (val) != lval_memory)
 	      error (_("Symbol \"%s\" cannot be used for compilation "
 		       "evaluation as its address has not been found."),
-		     SYMBOL_PRINT_NAME (sym));
+		     SYMBOL_PRINT_NAME (sym.symbol));
 
 	    kind = GCC_C_SYMBOL_VARIABLE;
 	    addr = value_address (val);
@@ -266,12 +267,12 @@ convert_one_symbol (struct compile_c_instance *context,
 	case LOC_LOCAL:
 	substitution:
 	  kind = GCC_C_SYMBOL_VARIABLE;
-	  symbol_name = symbol_substitution_name (sym);
+	  symbol_name = symbol_substitution_name (sym.symbol);
 	  break;
 
 	case LOC_STATIC:
 	  kind = GCC_C_SYMBOL_VARIABLE;
-	  addr = SYMBOL_VALUE_ADDRESS (sym);
+	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
 	  break;
 
 	case LOC_FINAL_VALUE:
@@ -284,12 +285,13 @@ convert_one_symbol (struct compile_c_instance *context,
       if (context->base.scope != COMPILE_I_RAW_SCOPE
 	  || symbol_name == NULL)
 	{
-	  decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
-						     SYMBOL_NATURAL_NAME (sym),
-						     kind,
-						     sym_type,
-						     symbol_name, addr,
-						     filename, line);
+	  decl = C_CTX (context)->c_ops->build_decl
+	    (C_CTX (context),
+	     SYMBOL_NATURAL_NAME (sym.symbol),
+	     kind,
+	     sym_type,
+	     symbol_name, addr,
+	     filename, line);
 
 	  C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
 	}
@@ -338,7 +340,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
 	    fprintf_unfiltered (gdb_stdlog,
 				"gcc_convert_symbol \"%s\": global symbol\n",
 				identifier);
-	  convert_one_symbol (context, global_sym.symbol, 1, 0);
+	  convert_one_symbol (context, global_sym, 1, 0);
 	}
     }
 
@@ -346,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
     fprintf_unfiltered (gdb_stdlog,
 			"gcc_convert_symbol \"%s\": local symbol\n",
 			identifier);
-  convert_one_symbol (context, sym.symbol, 0, is_local_symbol);
+  convert_one_symbol (context, sym, 0, is_local_symbol);
 }
 
 /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 6f53814..18ca4ae 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
 		 "there is no selected frame"),
 	       SYMBOL_PRINT_NAME (sym));
 
-      val = read_var_value (sym, frame);
+      val = read_var_value (sym, NULL, frame);
       if (VALUE_LVAL (val) != lval_memory)
 	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		 "as its address has not been found."),
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index 1b7a09c..fa4f78c 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -1067,9 +1067,7 @@ push_variable (struct parser_state *ps, struct stoken name)
         }
 
       write_exp_elt_opcode (ps, OP_VAR_VALUE);
-      /* We want to use the selected frame, not another more inner frame
-         which happens to be in the same block.  */
-      write_exp_elt_block (ps, NULL);
+      write_exp_elt_block (ps, sym.block);
       write_exp_elt_sym (ps, sym.symbol);
       write_exp_elt_opcode (ps, OP_VAR_VALUE);
       return 1;
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 6098b35..56967a8 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2767,7 +2767,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 
 	  /* Make a block for the local symbols within.  */
 	  block = finish_block (newobj->name, &local_symbols,
-				newobj->old_blocks,
+				newobj->old_blocks, NULL,
 				newobj->start_addr, newobj->start_addr + valu);
 
 	  /* For C++, set the block's scope.  */
@@ -2868,7 +2868,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj->start_addr = valu;
 		}
 	      /* Make a block for the local symbols within.  */
-	      finish_block (0, &local_symbols, newobj->old_blocks,
+	      finish_block (0, &local_symbols, newobj->old_blocks, NULL,
 			    newobj->start_addr, valu);
 	    }
 	}
@@ -3166,8 +3166,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj = pop_context ();
 		  /* Make a block for the local symbols within.  */
 		  block = finish_block (newobj->name, &local_symbols,
-					newobj->old_blocks, newobj->start_addr,
-					valu);
+					newobj->old_blocks, NULL,
+					newobj->start_addr, valu);
 
 		  /* For C++, set the block's scope.  */
 		  if (SYMBOL_LANGUAGE (newobj->name) == language_cplus)
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index c75767e..edfa220 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 f3630ac..2415656 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -122,12 +122,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 24a4022..9359f0d 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1737,6 +1737,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 *);
@@ -11398,6 +11402,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (attr)
     dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
 
+  /* If there is a location for the static link, record it.  */
+  newobj->static_link = NULL;
+  attr = dwarf2_attr (die, DW_AT_static_link, cu);
+  if (attr)
+    {
+      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
+					sizeof (*newobj->static_link));
+      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
+    }
+
   cu->list_in_scope = &local_symbols;
 
   if (die->child != NULL)
@@ -11449,7 +11463,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   newobj = pop_context ();
   /* Make a block for the local symbols within.  */
   block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-                        lowpc, highpc);
+			newobj->static_link, lowpc, highpc);
 
   /* For C++, set the block's scope.  */
   if ((cu->language == language_cplus
@@ -11534,7 +11548,7 @@ 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, newobj->old_blocks,
+        = finish_block (0, &local_symbols, newobj->old_blocks, NULL,
 			newobj->start_addr, highpc);
 
       /* Note that recording ranges after traversing children, as we
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 7f53c72..ee24244 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -521,10 +521,7 @@ variable:	name_not_typename
 				    innermost_block = sym.block;
 				}
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			      break;
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 83b4fca..cc5420e 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,11 +410,166 @@ 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);
+
+      /* Stacks can be quite deep: give the user a chance to stop this.  */
+      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 != NULL
+	  && (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
+   functions.
+
+   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, const struct block *var_block,
+		   struct frame_info *frame)
+{
+  const struct block *frame_block = NULL;
+
+  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)
+    {
+      /* Stacks can be quite deep: give the user a chance to stop this.  */
+      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 function
+	 level, the immediate upper lexical block is in an outer function:
+	 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 function 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.  */
 
 struct value *
-default_read_var_value (struct symbol *var, struct frame_info *frame)
+default_read_var_value (struct symbol *var, const struct block *var_block,
+			struct frame_info *frame)
 {
   struct value *v;
   struct type *type = SYMBOL_TYPE (var);
@@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
   check_typedef (type);
 
   if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
+    gdb_assert (frame != NULL);
+
+  if (frame != NULL)
+    frame = get_hosting_frame (var, var_block, frame);
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
@@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
 /* Calls VAR's language la_read_var_value hook with the given arguments.  */
 
 struct value *
-read_var_value (struct symbol *var, struct frame_info *frame)
+read_var_value (struct symbol *var, const struct block *var_block,
+		struct frame_info *frame)
 {
   const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
 
   gdb_assert (lang != NULL);
   gdb_assert (lang->la_read_var_value != NULL);
 
-  return lang->la_read_var_value (var, frame);
+  return lang->la_read_var_value (var, var_block, frame);
 }
 
 /* Install default attributes for register values.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 125af01..301c6fc 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1885,7 +1885,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;
@@ -1897,7 +1897,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;
@@ -2139,7 +2139,8 @@ resolve_dynamic_type_internal (struct type *type,
 
   /* Resolve data_location attribute.  */
   prop = TYPE_DATA_LOCATION (resolved_type);
-  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (prop != NULL
+      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       TYPE_DYN_PROP_ADDR (prop) = value;
       TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index c1ddfa9..4e017fe 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -611,10 +611,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 64ac0c0..de77c21 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -855,6 +855,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
   SCM block_scm = SCM_UNDEFINED;
   struct frame_info *frame = NULL;
   struct symbol *var = NULL;
+  const struct block *block = NULL;
   struct value *value = NULL;
 
   f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
@@ -909,9 +910,13 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
 
       TRY
 	{
+	  struct block_symbol lookup_sym;
+
 	  if (block == NULL)
 	    block = get_frame_block (frame, NULL);
-	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  var = lookup_sym.symbol;
+	  block = lookup_sym.block;
 	}
       CATCH (ex, RETURN_MASK_ALL)
 	{
@@ -940,7 +945,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
 
   TRY
     {
-      value = read_var_value (var, frame);
+      value = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 01c9eb1..0970a72 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -550,7 +550,11 @@ gdbscm_symbol_value (SCM self, SCM rest)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("Symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO: currently, we have no way to recover the block in which SYMBOL
+	 was found, so we have no block to pass to read_var_value.  This will
+	 yield an incorrect value when symbol is not local to FRAME_INFO (this
+	 can happen with nested functions).  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4948d27..2872292 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1660,7 +1660,7 @@ finish_command_continuation (void *arg, int err)
 	    {
 	      struct value *func;
 
-	      func = read_var_value (a->function, get_current_frame ());
+	      func = read_var_value (a->function, NULL, get_current_frame ());
 	      TRY
 		{
 		  /* print_return_value can throw an exception in some
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9a46242..a27e804 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6082,14 +6082,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
 {
   TRY
     {
-      struct symbol *vsym;
+      struct block_symbol vsym;
       struct value *value;
       CORE_ADDR handler;
       struct breakpoint *bp;
 
-      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
-			    NULL).symbol;
-      value = read_var_value (vsym, frame);
+      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+      value = read_var_value (vsym.symbol, vsym.block, frame);
       /* If the value was optimized out, revert to the old behavior.  */
       if (! value_optimized_out (value))
 	{
diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
index 4999848..60b7d2e 100644
--- a/gdb/jv-exp.y
+++ b/gdb/jv-exp.y
@@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
 	}
 
       write_exp_elt_opcode (par_state, OP_VAR_VALUE);
-      /* We want to use the selected frame, not another more inner frame
-	 which happens to be in the same block.  */
-      write_exp_elt_block (par_state, NULL);
+      write_exp_elt_block (par_state, sym.block);
       write_exp_elt_sym (par_state, sym.symbol);
       write_exp_elt_opcode (par_state, OP_VAR_VALUE);
       return 1;
diff --git a/gdb/language.h b/gdb/language.h
index 4ecb103..01654c1 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -241,13 +241,19 @@ struct language_defn
     void (*la_value_print) (struct value *, struct ui_file *,
 			    const struct value_print_options *);
 
-    /* Given a symbol VAR, and a stack frame id FRAME, read the value
-       of the variable an return (pointer to a) struct value containing
-       the value.
+    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
+       stack frame id FRAME, read the value of the variable and return (pointer
+       to a) struct value containing the value.
+
+       VAR_BLOCK is needed if there's a possibility for VAR to be outside
+       FRAME.  This is what happens if FRAME correspond to a nested function
+       and VAR is defined in the outer function.  If callers know that VAR is
+       located in FRAME or is global/static, NULL can be passed as VAR_BLOCK.
 
        Throw an error if the variable cannot be found.  */
 
     struct value *(*la_read_var_value) (struct symbol *var,
+					const struct block *var_block,
 					struct frame_info *frame);
 
     /* PC is possibly an unknown languages trampoline.
diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
index 633c354..360fdea 100644
--- a/gdb/m2-exp.y
+++ b/gdb/m2-exp.y
@@ -637,10 +637,7 @@ variable:	NAME
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index c6f9f00..93d8b7d 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -199,6 +199,92 @@ set_objfile_main_name (struct objfile *objfile,
   objfile->per_bfd->language_of_main = lang;
 }
 
+/* Helper structure to map blocks to static link properties in hash tables.  */
+
+struct static_link_htab_entry
+{
+  const struct block *block;
+  const struct dynamic_prop *static_link;
+};
+
+/* Return a hash code for struct static_link_htab_entry *P.  */
+
+static hashval_t
+static_link_htab_entry_hash (const void *p)
+{
+  const struct static_link_htab_entry *e
+    = (const struct static_link_htab_entry *) p;
+
+  return htab_hash_pointer (e->block);
+}
+
+/* Return whether P1 an P2 (pointers to struct static_link_htab_entry) are
+   mappings for the same block.  */
+
+static int
+static_link_htab_entry_eq (const void *p1, const void *p2)
+{
+  const struct static_link_htab_entry *e1
+    = (const struct static_link_htab_entry *) p1;
+  const struct static_link_htab_entry *e2
+    = (const struct static_link_htab_entry *) p2;
+
+  return e1->block == e2->block;
+}
+
+/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
+   Must not be called more than once for each BLOCK.  */
+
+void
+objfile_register_static_link (struct objfile *objfile,
+			      const struct block *block,
+			      const struct dynamic_prop *static_link)
+{
+  void **slot;
+  struct static_link_htab_entry lookup_entry;
+  struct static_link_htab_entry *entry;
+
+  if (objfile->static_links == NULL)
+    objfile->static_links = htab_create_alloc
+      (1, &static_link_htab_entry_hash, static_link_htab_entry_eq, NULL,
+       xcalloc, xfree);
+
+  /* Create a slot for the mapping, make sure it's the first mapping for this
+     block and then create the mapping itself.  */
+  lookup_entry.block = block;
+  slot = htab_find_slot (objfile->static_links, &lookup_entry, INSERT);
+  gdb_assert (*slot == NULL);
+
+  entry = (struct static_link_htab_entry *) obstack_alloc
+	    (&objfile->objfile_obstack, sizeof (*entry));
+  entry->block = block;
+  entry->static_link = static_link;
+  *slot = (void *) entry;
+}
+
+/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
+   none was found.  */
+
+const struct dynamic_prop *
+objfile_lookup_static_link (struct objfile *objfile,
+			    const struct block *block)
+{
+  struct static_link_htab_entry *entry;
+  struct static_link_htab_entry lookup_entry;
+
+  if (objfile->static_links == NULL)
+    return NULL;
+  lookup_entry.block = block;
+  entry
+    = (struct static_link_htab_entry *) htab_find (objfile->static_links,
+						   &lookup_entry);
+  if (entry == NULL)
+    return NULL;
+
+  gdb_assert (entry->block == block);
+  return entry->static_link;
+}
+
 \f
 
 /* Called via bfd_map_over_sections to build up the section table that
@@ -653,6 +739,11 @@ free_objfile (struct objfile *objfile)
   /* Rebuild section map next time we need it.  */
   get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
 
+  /* Free the map for static links.  There's no need to free static link
+     themselves since they were allocated on the objstack.  */
+  if (objfile->static_links != NULL)
+    htab_delete (objfile->static_links);
+
   /* The last thing we do is free the objfile struct itself.  */
   xfree (objfile);
 }
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a0dc69b..653106f 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -20,6 +20,7 @@
 #if !defined (OBJFILES_H)
 #define OBJFILES_H
 
+#include "hashtab.h"
 #include "gdb_obstack.h"	/* For obstack internals.  */
 #include "symfile.h"		/* For struct psymbol_allocation_list.  */
 #include "progspace.h"
@@ -412,6 +413,19 @@ struct objfile
        table, so we have to keep them here to relocate them
        properly.  */
     struct symbol *template_symbols;
+
+    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
+       block *) that have one.
+
+       In the context of nested functions (available in Pascal, Ada and GNU C,
+       for instance), a static link (as in DWARF's DW_AT_static_link attribute)
+       for a function is a way to get the frame corresponding to the enclosing
+       function.
+
+       Very few blocks have a static link, so it's more memory efficient to
+       store these here rather than in struct block.  Static links must be
+       allocated on the objfile's obstack.  */
+    htab_t static_links;
   };
 
 /* Defines for the objfile flag word.  */
@@ -719,4 +733,12 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
 extern void set_objfile_main_name (struct objfile *objfile,
 				   const char *name, enum language lang);
 
+extern void objfile_register_static_link
+  (struct objfile *objfile,
+   const struct block *block,
+   const struct dynamic_prop *static_link);
+
+extern const struct dynamic_prop *objfile_lookup_static_link
+  (struct objfile *objfile, const struct block *block);
+
 #endif /* !defined (OBJFILES_H) */
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 191b3d3..c255a57 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -772,10 +772,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			      current_type = sym.symbol->type; }
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f51e25c..553cc71 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
       struct value *val;
       struct value_print_options opts;
 
-      val = read_var_value (var, frame);
+      /* READ_VAR_VALUE needs a block in order to deal with non-local
+	 references (i.e. to handle nested functions).  In this context, we
+	 print variables that are local to this frame, so we can avoid passing
+	 a block to it.  */
+      val = read_var_value (var, NULL, frame);
       get_user_print_options (&opts);
       opts.deref_ref = 1;
       common_val_print (val, stream, indent, &opts, current_language);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index e3d4867..345642e 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  func_value = read_var_value (function, frame);
+                  func_value = read_var_value (function, NULL, frame);
                   self_bpfinish->function_value =
                       value_to_value_object (func_value);
                   PyErr_Clear ();
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 7290056..1923f64 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
   struct frame_info *frame;
   PyObject *sym_obj, *block_obj = NULL;
   struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
+  const struct block *block = NULL;
   struct value *val = NULL;
 
   if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
@@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
   else if (gdbpy_is_string (sym_obj))
     {
       char *var_name;
-      const struct block *block = NULL;
       struct cleanup *cleanup;
 
       var_name = python_string_to_target_string (sym_obj);
@@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
 
       TRY
 	{
+	  struct block_symbol lookup_sym;
 	  FRAPY_REQUIRE_VALID (self, frame);
 
 	  if (!block)
 	    block = get_frame_block (frame, NULL);
-	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  var = lookup_sym.symbol;
+	  block = lookup_sym.block;
 	}
       CATCH (except, RETURN_MASK_ALL)
 	{
@@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
     {
       FRAPY_REQUIRE_VALID (self, frame);
 
-      val = read_var_value (var, frame);
+      val = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index e3336b1..ac97723 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -43,16 +43,17 @@ enum mi_print_types
    NAME is a  pass-through argument where the name of  the symbol will
    be written.  NAME is allocated in  this function, but the caller is
    responsible for clean up.  SYM is a pass-through argument where the
-   symbol will be written.  In the case of the API returning a string,
-   this will be set to NULL.  LANGUAGE is also a pass-through argument
-   denoting the language attributed to the Symbol.  In the case of SYM
-   being  NULL, this  will be  set to  the current  language.  Returns
-   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
-   EXT_LANG_BT_OK on success.  */
+   symbol will be written and  SYM_BLOCK is a pass-through argument to
+   write  the block where the symbol lies in.  In the case of the  API
+   returning a  string,  this will be set to NULL.  LANGUAGE is also a
+   pass-through  argument  denoting  the  language  attributed  to the
+   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
+   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
+   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
 
 static enum ext_lang_bt_status
 extract_sym (PyObject *obj, char **name, struct symbol **sym,
-	     const struct language_defn **language)
+	     struct block **sym_block, const struct language_defn **language)
 {
   PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
 
@@ -75,12 +76,18 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
 	python_language.  */
       *language = python_language;
       *sym = NULL;
+      *sym_block = NULL;
     }
   else
     {
       /* This type checks 'result' during the conversion so we
 	 just call it unconditionally and check the return.  */
       *sym = symbol_object_to_symbol (result);
+      /* TODO: currently, we have no way to recover the block in which SYMBOL
+	 was found, so we have no block to return.  Trying to evaluate SYMBOL
+	 will yield an incorrect value when it's located in a FRAME and
+	 evaluated from another frame (as permitted in nested functions).  */
+      *sym_block = NULL;
 
       Py_DECREF (result);
 
@@ -537,10 +544,11 @@ enumerate_args (PyObject *iter,
       const struct language_defn *language;
       char *sym_name;
       struct symbol *sym;
+      struct block *sym_block;
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  Py_DECREF (item);
@@ -736,12 +744,13 @@ enumerate_locals (PyObject *iter,
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
       struct symbol *sym;
+      struct block *sym_block;
       int local_indent = 8 + (8 * indent);
       struct cleanup *locals_cleanups;
 
       locals_cleanups = make_cleanup_py_decref (item);
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  do_cleanups (locals_cleanups);
@@ -769,7 +778,7 @@ enumerate_locals (PyObject *iter,
 	{
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, sym_block, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 401e7e9..bbc8b6b 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -278,7 +278,11 @@ sympy_value (PyObject *self, PyObject *args)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO: currently, we have no way to recover the block in which SYMBOL
+	 was found, so we have no block to pass to read_var_value.  This will
+	 yield an incorrect value when symbol is not local to FRAME_INFO (this
+	 can happen with nested functions).  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/stack.c b/gdb/stack.c
index b4cfdbd..5a18a06 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
 
   TRY
     {
-      argp->val = read_var_value (sym, frame);
+      argp->val = read_var_value (sym, NULL, frame);
     }
   CATCH (except, RETURN_MASK_ERROR)
     {
@@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
     {
       TRY
 	{
-	  val = read_var_value (sym, frame);
+	  val = read_var_value (sym, NULL, frame);
 	}
       CATCH (except, RETURN_MASK_ERROR)
 	{
@@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
 
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, NULL, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
@@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
 	value_fetch_lazy (return_value);
 
       if (thisfun != NULL)
-	function = read_var_value (thisfun, thisframe);
+	function = read_var_value (thisfun, NULL, thisframe);
 
       rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
       if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 61fc8c5..df781b8 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -665,6 +665,25 @@ 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.  Return 0 on failure (FRAMEFUNC may not hold the
+     information we need).
+
+     This method is designed to work with static links (nested functions
+     handling).  Static links are function properties whose evaluation returns
+     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 fuctions, 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.  */
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..967eb2f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.c
@@ -0,0 +1,37 @@
+/* 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 function 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..9720f5b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a6449e34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.c
@@ -0,0 +1,48 @@
+/* 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..a107d1c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.exp
@@ -0,0 +1,64 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a51f417
--- /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);
+
+extern void process (callback_t cb);
+extern 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..8f9b522
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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.
+
+gdb_test "print first"        "1"
+gdb_test "print parent_first" "1"
diff --git a/gdb/valops.c b/gdb/valops.c
index acaf027..26fdfa6 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1291,27 +1291,12 @@ value_repeat (struct value *arg1, int count)
 struct value *
 value_of_variable (struct symbol *var, const struct block *b)
 {
-  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);
+  return read_var_value (var, b, frame);
 }
 
 struct value *
@@ -3463,9 +3448,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 		return NULL;
 
 	      if (want_address)
-		return value_addr (read_var_value (s, 0));
+		return value_addr (read_var_value (s, 0, 0));
 	      else
-		return read_var_value (s, 0);
+		return read_var_value (s, 0, 0);
 	    }
 
 	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -3493,7 +3478,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 	      if (s == NULL)
 		return NULL;
 
-	      v = read_var_value (s, 0);
+	      v = read_var_value (s, 0, 0);
 	      if (!want_address)
 		result = v;
 	      else
@@ -3729,7 +3714,7 @@ value_full_object (struct value *argp,
 struct value *
 value_of_this (const struct language_defn *lang)
 {
-  struct symbol *sym;
+  struct block_symbol sym;
   const struct block *b;
   struct frame_info *frame;
 
@@ -3740,12 +3725,12 @@ value_of_this (const struct language_defn *lang)
 
   b = get_frame_block (frame, NULL);
 
-  sym = lookup_language_this (lang, b).symbol;
-  if (sym == NULL)
+  sym = lookup_language_this (lang, b);
+  if (sym.symbol == NULL)
     error (_("current stack frame does not contain a variable named `%s'"),
 	   lang->la_name_of_this);
 
-  return read_var_value (sym, frame);
+  return read_var_value (sym.symbol, sym.block, frame);
 }
 
 /* Return the value of the local variable, if one exists.  Return NULL
diff --git a/gdb/value.h b/gdb/value.h
index 82deaf2..0a4bc47 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -674,9 +674,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
 extern int symbol_read_needs_frame (struct symbol *);
 
 extern struct value *read_var_value (struct symbol *var,
+				     const struct block *var_block,
 				     struct frame_info *frame);
 
 extern struct value *default_read_var_value (struct symbol *var,
+					     const struct block *var_block,
 					     struct frame_info *frame);
 
 extern struct value *allocate_value (struct type *type);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index b5b2a1d..4be7dd2 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1389,7 +1389,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 		}
 
 	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-			    newobj->start_addr,
+			    NULL, newobj->start_addr,
 			    (fcn_cs_saved.c_value
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
 			     + ANOFFSET (objfile->section_offsets,
@@ -1480,7 +1480,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 	      if (local_symbols && context_stack_depth > 0)
 		{
 		  /* Make a block for the local symbols within.  */
-		  finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+		  finish_block (newobj->name, &local_symbols,
+				newobj->old_blocks, NULL,
 				newobj->start_addr,
 				(cs->c_value
 				 + ANOFFSET (objfile->section_offsets,
-- 
2.4.6


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-31 10:53                 ` Pierre-Marie de Rodat
@ 2015-08-10  8:34                   ` Pierre-Marie de Rodat
  2015-08-13 15:03                     ` Doug Evans
  2015-08-15  5:12                   ` Doug Evans
  2015-08-15  5:13                   ` Doug Evans
  2 siblings, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-10  8:34 UTC (permalink / raw)
  To: Doug Evans; +Cc: Pedro Alves, gdb-patches

Hello

Ping for the updated patch after the last review: see 
<https://sourceware.org/ml/gdb-patches/2015-07/msg00931.html>. Thanks in 
advance!

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-10  8:34                   ` Pierre-Marie de Rodat
@ 2015-08-13 15:03                     ` Doug Evans
  2015-08-14  6:31                       ` Pierre-Marie de Rodat
  0 siblings, 1 reply; 40+ messages in thread
From: Doug Evans @ 2015-08-13 15:03 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Pedro Alves, gdb-patches

Hi.
I found some time last night to read the patch.
Almost done ... sorry for the delay.

On Mon, Aug 10, 2015 at 1:34 AM, Pierre-Marie de Rodat
<derodat@adacore.com> wrote:
> Hello
>
> Ping for the updated patch after the last review: see
> <https://sourceware.org/ml/gdb-patches/2015-07/msg00931.html>. Thanks in
> advance!
>
> --
> Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-13 15:03                     ` Doug Evans
@ 2015-08-14  6:31                       ` Pierre-Marie de Rodat
  0 siblings, 0 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-14  6:31 UTC (permalink / raw)
  To: Doug Evans; +Cc: Pedro Alves, gdb-patches

Hi Doug,

On 08/13/2015 05:03 PM, Doug Evans wrote:
> Hi.
> I found some time last night to read the patch.
> Almost done ... sorry for the delay.

Great, thanks! ... and no problem. :-)

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-31 10:53                 ` Pierre-Marie de Rodat
  2015-08-10  8:34                   ` Pierre-Marie de Rodat
@ 2015-08-15  5:12                   ` Doug Evans
  2015-08-15  6:21                     ` Doug Evans
  2015-08-17 13:33                     ` Pierre-Marie de Rodat
  2015-08-15  5:13                   ` Doug Evans
  2 siblings, 2 replies; 40+ messages in thread
From: Doug Evans @ 2015-08-15  5:12 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Kevin Buettner, gdb-patches

Hi.
Just a couple of nits.
Ok with them fixed (not sure what the right fix for the first one is
though, I could be missing something).
grep for ^====

Also, I found a 4% performance degradation in a couple of gmonster
perf tests (e.g., gmonster2-ptype-string.exp).
Not enough to reject the patch, but it would be interesting
to find the culprit (assuming it's not a test issue!).

Pierre-Marie de Rodat <derodat@adacore.com> writes:
> On 07/26/2015 10:34 PM, Doug Evans wrote:
>> Hi.
>>
>> Several nits and questions inline.  grep for ====.
>
> Thank you for reviewing!
>
>> One thing I still want to do is take this patch and run it through
>> the perf testsuite.
>>
>> Also, I still need to look at follow_static_link, get_hosting_frame closer.
>
> Okay.
>
>> Cool stuff though, there's clearly missing functionality we need here.
>
> Indeed, thanks! For the record, just like for the block_found
> business, I re-enabled Guile support in my builds and propagated the
> support for non-local references to the Guile API.
>
>>> +/* Return a property to evaluate the static link associated to BLOCK.  Note
>>> +   that only objfile-owned and function-level blocks can have a static link.
>>> +   Return NULL if there is no such property.  */
>>> +
>>
>> ====
>> Add a comment here stating that the term "static_link" is derived from
>> DW_AT_static_link.
>
> Done. I also added one in objfiles.h, for struct objfile's
> static_links field.
>
>>> -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,
>>
>> ====
>> Move the static_link property here.
>> [Arguments to functions aren't in completely random order,
>> and here static_link is among the collection of random things
>> about the block like start,end. So it reads better to me if
>> static_link appears with start,end]
>
> Fine by me: done and callers updated.
>
>>> +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;
>>> +}
>>
>> ====
>> If this is implemented on top of symbol_block_ops::find_frame_base_location,
>> do we need another method? Or can we just have a wrapper that calls
>> find_frame_base_location?
>> For one, I see block_op_get_frame_base being used for both
>> dwarf2_block_frame_base_locexpr_funcs and
>> dwarf2_block_frame_base_loclist_funcs.
>
> Correct me if I'm wrong, but the problem here is that if we aren't
> handling a "DWARF-described function", then we cannot assume that the
> find_frame_base_location method yields a location
> description. Mhm... maybe I should change it to return a dynamic
> property instead, then: what do you think?

Without non-DWARF examples it's hard to say.

>>> +/* 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))
>>
>> ====
>> It gets harder and harder to reason about correctness the more
>> we blur lines between foo-independent and foo-dependent parts of gdb.
>> [In debug case "foo" == "debug-format".]
>
> Agreed.
>
>> I guess to begin with, why are we calling a dwarf-specific function here
>> and what guarantees are in place (and easily discernable from reading
>> the code!) that the right thing will happen for non-dwarf targets?
>
> My interpretation is that even though dynamic properties seem to be
> used only with DWARF info., they should not be specific to it. In
> other words, dwarf2_evaluate_property should be called instead
> something like "evaluate_dynamic_prop" and moved elsewhere. After all,
> struct dynamic_prop isn't supposed to be itself DWARF-specific, and it
> is defined in gdbtypes.h.

I see.
I also see gdbtypes.c calling dwarf2_evaluate_property. Bleah.
dwarf2_evaluate_property has a lot of dwarf-specific code in it.

I guess this is ok, for now anyway.


>>> +      /* Protect ourselves against bad things such as circular call stacks.  */
>>
>> ====
>> Here's a good question.
>> gdb has other mechanisms to catch corrupt (e.g., circular) stacks
>> (e.g., UNWIND_INNER_ID). Is this QUIT here for protection or in case
>> of really large stacks (e.g., due to infinite recursion)?
>>
>>> +      QUIT;
>
> I wasn't aware of these mechanisms: thanks! Well, I had indeed
> circular stacks in mind, but this QUIT is also here to let users stop
> heavy computations in case of huge stacks (Joel advised me live to do
> this for this reason). So the comment is misleading and I have updated
> it. Thanks!
>
>>> +      if (framefunc != NULL
>>> +	  && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base
>>
>> ====
>> != NULL
>
> Done.
>
>>> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
>>> +       stack frame id FRAME, read the value of the variable and return (pointer
>>> +       to a) struct value containing the value.
>>> +
>>> +       VAR_BLOCK is needed if there's a possibility for VAR to be outside
>>> +       FRAME.  This is what happens if FRAME correspond to a nested function
>>> +       and VAR is defined in the outer function.  If callers know that VAR is
>>> +       located in FRAME, NULL can be passed as VAR_BLOCK.
>>
>> ====
>> "If callers know that VAR is located in FRAME or is global, ..." ?
>
> Indeed. I added "or is global/static" instead.
>
>>> +struct static_link_htab_entry
>>> +{
>>> +  const struct block *block;
>>> +  struct dynamic_prop *static_link;
>>
>> ====
>> It's too bad this isn't const struct dynamic_prop *static_link;
>> I'm guessing it can't be that without fixing some laxness elsewhere
>> (which I wouldn't impose on this patch), but can you check?
>
> I thought it would indeed bring a lot of changes everywhere... but
> it's not actually! I could add const qualifiers everywhere on dynamic
> properties in objfiles.* without trouble at all and added a coulpe in
> buildsym.* as well. Thanks for suggesting this!
>
>>> +static int
>>> +static_link_htab_entry_eq (const void *p1, const void *p2)
>>> +{
>>> +  const struct static_link_htab_entry *entry
>>> +    = (const struct static_link_htab_entry *) p1;
>>> +  const struct block *block = (const struct block *) p2;
>>
>> ====
>> blank line here
>
> Done.
>
>> Also, this is a non-standard implementation of an htab eq function.
>> Generally both p1 and p2 point to an element in the hash table.
>>
>> I see hashtab.h has this:
>>
>> /* Compare a table entry with a possible entry.  The entry already in
>>     the table always comes first, so the second element can be of a
>>     different type (but in this case htab_find and htab_find_slot
>>     cannot be used; instead the variants that accept a hash value
>>     must be used).  */
>> typedef int (*htab_eq) (const void *, const void *);
>>
>> so this eq function is possibly ok, except I also see calls to
>> htab_find,htab_find_slot below. AIUC, one of these needs to change.
>
> Yeah... I spent some time before having something that actually worked
> (first time I used this container) and got it wrong wrt. to doc
> anyway. Now, I eventually understood that all hash table lookups must
> be done with struct static_link_htab_entry * instead of struct block
> *, so I could fix the htab_eq function to be commutative.
>
>>> +  if (entry == NULL)
>>> +    return NULL;
>>> +  else
>>
>> ====
>> I don't know how others feel, but "else" clauses in particular situations
>> like this are just noise. How about removing it?
>
> Sure, removed.
>
>>> +    struct htab *static_links;
>>
>> ====
>> s/struct htab */htab_t /
>
> Done.
>
>>> +
>>> +  /* 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 functions
>>> +     handling).  Static links are function properties whose evaluation return
>>
>> ====
>> s/return/returns/
>
> Fixed: thanks!
>
> Updated patch is attached and tested again on x86_64-linux.
>
> -- 
> Pierre-Marie de Rodat
>
> From 26961370aaa5343e0164ded82dc7531a44bebc6d 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] DWARF: handle non-local references in nested functions
>
> GDB's current behavior when dealing with non-local references in the
> context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
> references.
>
> gdb/ChangeLog:
>
> 	* ada-lang.c (ada_read_var_value): Add a var_block argument
> 	and pass it to default_read_var_value.
> 	* block.c (block_static_link): New accessor.
> 	* block.h (block_static_link): Declare it.
> 	* buildsym.c (finish_block_internal): Add a static_link
> 	argument.  If there is a static link, associate it to the new
> 	block.
> 	(finish_block): Add a static link argument and pass it to
> 	finish_block_internal.
> 	(end_symtab_get_static_block): Update calls to finish_block and
> 	to finish_block_internal.
> 	(end_symtab_with_blockvector): Update call to
> 	finish_block_internal.
> 	* buildsym.h: Forward-declare struct dynamic_prop.
> 	(struct context_stack): Add a static_link field.
> 	(finish_block): Add a static link argument.
> 	* c-exp.y: Remove an obsolete comment (evaluation of variables
> 	already start from the selected frame, and now they climb *up*
> 	the call stack) and propagate the block information to the
> 	produced expression.
> 	* d-exp.y: Likewise.
> 	* f-exp.y: Likewise.
> 	* go-exp.y: Likewise.
> 	* jv-exp.y: Likewise.
> 	* m2-exp.y: Likewise.
> 	* p-exp.y: Likewise.
> 	* coffread.c (coff_symtab_read): Update calls to finish_block.
> 	* dbxread.c (process_one_symbol): Likewise.
> 	* xcoffread.c (read_xcoff_symtab): Likewise.
> 	* compile/compile-c-symbols.c (convert_one_symbol): Promote the
> 	"sym" parameter to struct block_symbol, update its uses and pass
> 	its block to calls to read_var_value.
> 	(convert_symbol_sym): Update the calls to convert_one_symbol.
> 	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
> 	call to read_var_value.
> 	* 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.
> 	* findvar.c (follow_static_link): New.
> 	(get_hosting_frame): New.
> 	(default_read_var_value): Add a var_block argument.  Use
> 	get_hosting_frame to handle non-local references.
> 	(read_var_value): Add a var_block argument and pass it to the
> 	LA_READ_VAR_VALUE method.
> 	* gdbtypes.c (resolve_dynamic_range): Update calls to
> 	dwarf2_evaluate_property.
> 	(resolve_dynamic_type_internal): Likewise.
> 	* guile/scm-frame.c (gdbscm_frame_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* guile/scm-symbol.c (gdbscm_symbol_value): Update call to
> 	read_var_value (TODO).
> 	* infcmd.c (finish_command_continuation): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* infrun.c (insert_exception_resume_breakpoint): Likewise.
> 	* language.h (struct language_defn): Add a var_block argument to
> 	the LA_READ_VAR_VALUE method.
> 	* objfiles.c (struct static_link_htab_entry): New.
> 	(static_link_htab_entry_hash): New.
> 	(static_link_htab_entry_eq): New.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	(free_objfile): Free the STATIC_LINKS hashed map if needed.
> 	* objfiles.h: Include hashtab.h.
> 	(struct objfile): Add a static_links field.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	* printcmd.c (print_variable_and_value): Update call to
> 	read_var_value.
> 	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
> 	* python/py-frame.c (frapy_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* python/py-framefilter.c (extract_sym): Add a sym_block
> 	parameter and set the pointed value to NULL (TODO).
> 	(enumerate_args): Update call to extract_sym.
> 	(enumerate_locals): Update calls to extract_sym and to
> 	read_var_value.
> 	* python/py-symbol.c (sympy_value): Update call to
> 	read_var_value (TODO).
> 	* stack.c (read_frame_local): Update call to read_var_value.
> 	(read_frame_arg): Likewise.
> 	(return_command): Likewise.
> 	* symtab.h (struct symbol_block_ops): Add a get_frame_base
> 	method.
> 	(struct symbol): Add a block field.
> 	(SYMBOL_BLOCK): New accessor.
> 	* valops.c (value_of_variable): Remove frame/block handling and
> 	pass the block argument to read_var_value, which does this job
> 	now.
> 	(value_struct_elt_for_reference): Update calls to
> 	read_var_value.
> 	(value_of_this): Pass the block found to read_var_value.
> 	* value.h (read_var_value): Add a var_block argument.
> 	(default_read_var_value): Likewise.
>
> gdb/testsuite/ChangeLog:
>
> 	* 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.
>...
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 049fb48..3f0bdb1 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -13749,7 +13749,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
>  /* Implement the "la_read_var_value" language_defn method for Ada.  */
>  
>  static struct value *
> -ada_read_var_value (struct symbol *var, struct frame_info *frame)
> +ada_read_var_value (struct symbol *var, const struct block *var_block,
> +		    struct frame_info *frame)
>  {
>    const struct block *frame_block = NULL;
>    struct symbol *renaming_sym = NULL;
> @@ -13765,7 +13766,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
>  
>    /* This is a typical case where we expect the default_read_var_value
>       function to work.  */
> -  return default_read_var_value (var, frame);
> +  return default_read_var_value (var, var_block, frame);
>  }
>  
>  const struct language_defn ada_language_defn = {
> diff --git a/gdb/block.c b/gdb/block.c
> index f7621aa..f4b8e4f 100644
> --- a/gdb/block.c
> +++ b/gdb/block.c
> @@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
>    gb->compunit_symtab = cu;
>  }
>  
> +/* See block.h.  */
> +
> +struct dynamic_prop *
> +block_static_link (const struct block *block)
> +{
> +  struct objfile *objfile = block_objfile (block);
> +
> +  /* Only objfile-owned blocks that materialize top function scopes can have
> +     static links.  */
> +  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
> +    return NULL;
> +
> +  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
> +}
> +
>  /* Return the compunit of the global block.  */
>  
>  static struct compunit_symtab *
> diff --git a/gdb/block.h b/gdb/block.h
> index d8ad343..aac7929 100644
> --- a/gdb/block.h
> +++ b/gdb/block.h
> @@ -190,6 +190,17 @@ extern struct block *allocate_global_block (struct obstack *obstack);
>  extern void set_block_compunit_symtab (struct block *,
>  				       struct compunit_symtab *);
>  
> +/* Return a property to evaluate the static link associated to BLOCK.
> +
> +   In the context of nested functions (available in Pascal, Ada and GNU C, for
> +   instance), a static link (as in DWARF's DW_AT_static_link attribute) for a
> +   function is a way to get the frame corresponding to the enclosing function.
> +
> +   Note that only objfile-owned and function-level blocks can have a static
> +   link.  Return NULL if there is no such property.  */
> +
> +extern struct dynamic_prop *block_static_link (const struct block *block);
> +
>  /* A block iterator.  This structure should be treated as though it
>     were opaque; it is only defined here because we want to support
>     stack allocation of iterators.  */
> diff --git a/gdb/buildsym.c b/gdb/buildsym.c
> index 2a24a25..ba4f219 100644
> --- a/gdb/buildsym.c
> +++ b/gdb/buildsym.c
> @@ -331,8 +331,10 @@ 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 pending **listhead,
>  		       struct pending_block *old_blocks,
> +		       const struct dynamic_prop *static_link,
>  		       CORE_ADDR start, CORE_ADDR end,
>  		       int is_global, int expandable)
>  {
> @@ -422,6 +424,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
>        BLOCK_FUNCTION (block) = NULL;
>      }
>  
> +  if (static_link != NULL)
> +    objfile_register_static_link (objfile, block, static_link);
> +
>    /* Now "free" the links of the list, and empty the list.  */
>  
>    for (next = *listhead; next; next = next1)
> @@ -512,11 +517,13 @@ 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 pending **listhead,
>  	      struct pending_block *old_blocks,
> +	      const struct dynamic_prop *static_link,
>  	      CORE_ADDR start, CORE_ADDR end)
>  {
> -  return finish_block_internal (symbol, listhead, old_blocks,
> +  return finish_block_internal (symbol, listhead, old_blocks, static_link,
>  				start, end, 0, 0);
>  }
>  
> @@ -1218,7 +1225,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, &local_symbols, cstk->old_blocks, NULL,
>  		    cstk->start_addr, end_addr);
>  
>        if (context_stack_depth > 0)
> @@ -1289,7 +1296,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, &file_symbols, NULL, NULL,
>  				    last_source_start_addr, end_addr,
>  				    0, expandable);
>      }
> @@ -1317,7 +1324,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, &global_symbols, NULL, NULL,
>  			 last_source_start_addr, end_addr,
>  			 1, expandable);
>    blockvector = make_blockvector ();
> diff --git a/gdb/buildsym.h b/gdb/buildsym.h
> index f98203e..81c00f3 100644
> --- a/gdb/buildsym.h
> +++ b/gdb/buildsym.h
> @@ -39,6 +39,8 @@ struct compunit_symtab;
>  struct block;
>  struct pending_block;
>  
> +struct dynamic_prop;
> +
>  #ifndef EXTERN
>  #define	EXTERN extern
>  #endif
> @@ -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,11 @@ 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 pending **listhead,
> +				   struct pending_block *old_blocks,
> +				   const struct dynamic_prop *static_link,
> +				   CORE_ADDR start,
> +				   CORE_ADDR end);
>  
>  extern void record_block_range (struct block *,
>                                  CORE_ADDR start, CORE_ADDR end_inclusive);
> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
> index 59cecb5..9504e92 100644
> --- a/gdb/c-exp.y
> +++ b/gdb/c-exp.y
> @@ -1072,10 +1072,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/coffread.c b/gdb/coffread.c
> index 7722cdb..c0f4267 100644
> --- a/gdb/coffread.c
> +++ b/gdb/coffread.c
> @@ -1144,8 +1144,8 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
>  		enter_linenos (fcn_line_ptr, fcn_first_line,
>  			       fcn_last_line, objfile);
>  
> -	      finish_block (newobj->name, &local_symbols,
> -			    newobj->old_blocks, newobj->start_addr,
> +	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> +			    NULL, newobj->start_addr,
>  			    fcn_cs_saved.c_value
>  			    + fcn_aux_saved.x_sym.x_misc.x_fsize
>  			    + ANOFFSET (objfile->section_offsets,
> @@ -1188,7 +1188,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, newobj->old_blocks,
> +		  finish_block (0, &local_symbols, newobj->old_blocks, NULL,
>  				newobj->start_addr, tmpaddr);
>  		}
>  	      /* Now pop locals of block just finished.  */
> diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
> index 21ce655..355b063 100644
> --- a/gdb/compile/compile-c-symbols.c
> +++ b/gdb/compile/compile-c-symbols.c
> @@ -143,26 +143,26 @@ symbol_substitution_name (struct symbol *sym)
>  
>  static void
>  convert_one_symbol (struct compile_c_instance *context,
> -		    struct symbol *sym,
> +		    struct block_symbol sym,
>  		    int is_global,
>  		    int is_local)
>  {
>    gcc_type sym_type;
> -  const char *filename = symbol_symtab (sym)->filename;
> -  unsigned short line = SYMBOL_LINE (sym);
> +  const char *filename = symbol_symtab (sym.symbol)->filename;
> +  unsigned short line = SYMBOL_LINE (sym.symbol);
>  
> -  error_symbol_once (context, sym);
> +  error_symbol_once (context, sym.symbol);
>  
> -  if (SYMBOL_CLASS (sym) == LOC_LABEL)
> +  if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
>      sym_type = 0;
>    else
> -    sym_type = convert_type (context, SYMBOL_TYPE (sym));
> +    sym_type = convert_type (context, SYMBOL_TYPE (sym.symbol));
>  
> -  if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
> +  if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
>      {
>        /* Binding a tag, so we don't need to build a decl.  */
>        C_CTX (context)->c_ops->tagbind (C_CTX (context),
> -				       SYMBOL_NATURAL_NAME (sym),
> +				       SYMBOL_NATURAL_NAME (sym.symbol),
>  				       sym_type, filename, line);
>      }
>    else
> @@ -172,7 +172,7 @@ convert_one_symbol (struct compile_c_instance *context,
>        CORE_ADDR addr = 0;
>        char *symbol_name = NULL;
>  
> -      switch (SYMBOL_CLASS (sym))
> +      switch (SYMBOL_CLASS (sym.symbol))
>  	{
>  	case LOC_TYPEDEF:
>  	  kind = GCC_C_SYMBOL_TYPEDEF;
> @@ -180,45 +180,46 @@ convert_one_symbol (struct compile_c_instance *context,
>  
>  	case LOC_LABEL:
>  	  kind = GCC_C_SYMBOL_LABEL;
> -	  addr = SYMBOL_VALUE_ADDRESS (sym);
> +	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
>  	  break;
>  
>  	case LOC_BLOCK:
>  	  kind = GCC_C_SYMBOL_FUNCTION;
> -	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
> -	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
> +	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
> +	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
>  	    addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
>  	  break;
>  
>  	case LOC_CONST:
> -	  if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
> +	  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
>  	    {
>  	      /* Already handled by convert_enum.  */
>  	      return;
>  	    }
> -	  C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
> -						  SYMBOL_NATURAL_NAME (sym),
> -						  SYMBOL_VALUE (sym),
> -						  filename, line);
> +	  C_CTX (context)->c_ops->build_constant
> +	    (C_CTX (context),
> +	     sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
> +	     SYMBOL_VALUE (sym.symbol),
> +	     filename, line);
>  	  return;
>  
>  	case LOC_CONST_BYTES:
>  	  error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
> -		 SYMBOL_PRINT_NAME (sym));
> +		 SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_UNDEF:
>  	  internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
> -			  SYMBOL_PRINT_NAME (sym));
> +			  SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_COMMON_BLOCK:
>  	  error (_("Fortran common block is unsupported for compilation "
>  		   "evaluaton of symbol \"%s\"."),
> -		 SYMBOL_PRINT_NAME (sym));
> +		 SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_OPTIMIZED_OUT:
>  	  error (_("Symbol \"%s\" cannot be used for compilation evaluation "
>  		   "as it is optimized out."),
> -		 SYMBOL_PRINT_NAME (sym));
> +		 SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_COMPUTED:
>  	  if (is_local)
> @@ -227,7 +228,7 @@ convert_one_symbol (struct compile_c_instance *context,
>  	  warning (_("Symbol \"%s\" is thread-local and currently can only "
>  		     "be referenced from the current thread in "
>  		     "compiled code."),
> -		   SYMBOL_PRINT_NAME (sym));
> +		   SYMBOL_PRINT_NAME (sym.symbol));
>  	  /* FALLTHROUGH */
>  	case LOC_UNRESOLVED:
>  	  /* 'symbol_name' cannot be used here as that one is used only for
> @@ -238,20 +239,20 @@ convert_one_symbol (struct compile_c_instance *context,
>  	    struct value *val;
>  	    struct frame_info *frame = NULL;
>  
> -	    if (symbol_read_needs_frame (sym))
> +	    if (symbol_read_needs_frame (sym.symbol))
>  	      {
>  		frame = get_selected_frame (NULL);
>  		if (frame == NULL)
>  		  error (_("Symbol \"%s\" cannot be used because "
>  			   "there is no selected frame"),
> -			 SYMBOL_PRINT_NAME (sym));
> +			 SYMBOL_PRINT_NAME (sym.symbol));
>  	      }
>  
> -	    val = read_var_value (sym, frame);
> +	    val = read_var_value (sym.symbol, sym.block, frame);
>  	    if (VALUE_LVAL (val) != lval_memory)
>  	      error (_("Symbol \"%s\" cannot be used for compilation "
>  		       "evaluation as its address has not been found."),
> -		     SYMBOL_PRINT_NAME (sym));
> +		     SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	    kind = GCC_C_SYMBOL_VARIABLE;
>  	    addr = value_address (val);
> @@ -266,12 +267,12 @@ convert_one_symbol (struct compile_c_instance *context,
>  	case LOC_LOCAL:
>  	substitution:
>  	  kind = GCC_C_SYMBOL_VARIABLE;
> -	  symbol_name = symbol_substitution_name (sym);
> +	  symbol_name = symbol_substitution_name (sym.symbol);
>  	  break;
>  
>  	case LOC_STATIC:
>  	  kind = GCC_C_SYMBOL_VARIABLE;
> -	  addr = SYMBOL_VALUE_ADDRESS (sym);
> +	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
>  	  break;
>  
>  	case LOC_FINAL_VALUE:
> @@ -284,12 +285,13 @@ convert_one_symbol (struct compile_c_instance *context,
>        if (context->base.scope != COMPILE_I_RAW_SCOPE
>  	  || symbol_name == NULL)
>  	{
> -	  decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
> -						     SYMBOL_NATURAL_NAME (sym),
> -						     kind,
> -						     sym_type,
> -						     symbol_name, addr,
> -						     filename, line);
> +	  decl = C_CTX (context)->c_ops->build_decl
> +	    (C_CTX (context),
> +	     SYMBOL_NATURAL_NAME (sym.symbol),
> +	     kind,
> +	     sym_type,
> +	     symbol_name, addr,
> +	     filename, line);
>  
>  	  C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
>  	}
> @@ -338,7 +340,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
>  	    fprintf_unfiltered (gdb_stdlog,
>  				"gcc_convert_symbol \"%s\": global symbol\n",
>  				identifier);
> -	  convert_one_symbol (context, global_sym.symbol, 1, 0);
> +	  convert_one_symbol (context, global_sym, 1, 0);
>  	}
>      }
>  
> @@ -346,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
>      fprintf_unfiltered (gdb_stdlog,
>  			"gcc_convert_symbol \"%s\": local symbol\n",
>  			identifier);
> -  convert_one_symbol (context, sym.symbol, 0, is_local_symbol);
> +  convert_one_symbol (context, sym, 0, is_local_symbol);
>  }
>  
>  /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
> diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
> index 6f53814..18ca4ae 100644
> --- a/gdb/compile/compile-loc2c.c
> +++ b/gdb/compile/compile-loc2c.c
> @@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  		 "there is no selected frame"),
>  	       SYMBOL_PRINT_NAME (sym));
>  
> -      val = read_var_value (sym, frame);
> +      val = read_var_value (sym, NULL, frame);
>        if (VALUE_LVAL (val) != lval_memory)
>  	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
>  		 "as its address has not been found."),
> diff --git a/gdb/d-exp.y b/gdb/d-exp.y
> index 1b7a09c..fa4f78c 100644
> --- a/gdb/d-exp.y
> +++ b/gdb/d-exp.y
> @@ -1067,9 +1067,7 @@ push_variable (struct parser_state *ps, struct stoken name)
>          }
>  
>        write_exp_elt_opcode (ps, OP_VAR_VALUE);
> -      /* We want to use the selected frame, not another more inner frame
> -         which happens to be in the same block.  */
> -      write_exp_elt_block (ps, NULL);
> +      write_exp_elt_block (ps, sym.block);
>        write_exp_elt_sym (ps, sym.symbol);
>        write_exp_elt_opcode (ps, OP_VAR_VALUE);
>        return 1;
> diff --git a/gdb/dbxread.c b/gdb/dbxread.c
> index 6098b35..56967a8 100644
> --- a/gdb/dbxread.c
> +++ b/gdb/dbxread.c
> @@ -2767,7 +2767,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  
>  	  /* Make a block for the local symbols within.  */
>  	  block = finish_block (newobj->name, &local_symbols,
> -				newobj->old_blocks,
> +				newobj->old_blocks, NULL,
>  				newobj->start_addr, newobj->start_addr + valu);
>  
>  	  /* For C++, set the block's scope.  */
> @@ -2868,7 +2868,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  		  newobj->start_addr = valu;
>  		}
>  	      /* Make a block for the local symbols within.  */
> -	      finish_block (0, &local_symbols, newobj->old_blocks,
> +	      finish_block (0, &local_symbols, newobj->old_blocks, NULL,
>  			    newobj->start_addr, valu);
>  	    }
>  	}
> @@ -3166,8 +3166,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  		  newobj = pop_context ();
>  		  /* Make a block for the local symbols within.  */
>  		  block = finish_block (newobj->name, &local_symbols,
> -					newobj->old_blocks, newobj->start_addr,
> -					valu);
> +					newobj->old_blocks, NULL,
> +					newobj->start_addr, valu);
>  
>  		  /* For C++, set the block's scope.  */
>  		  if (SYMBOL_LANGUAGE (newobj->name) == language_cplus)
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index c75767e..edfa220 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)

====
It's hard for this reader to figure out why this test is here.
If the code gets here, when would find_frame_base_location be NULL?
Seems like we could just assert find_frame_base_location is non-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 f3630ac..2415656 100644
> --- a/gdb/dwarf2loc.h
> +++ b/gdb/dwarf2loc.h
> @@ -122,12 +122,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 24a4022..9359f0d 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -1737,6 +1737,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 *);
> @@ -11398,6 +11402,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>    if (attr)
>      dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
>  
> +  /* If there is a location for the static link, record it.  */
> +  newobj->static_link = NULL;
> +  attr = dwarf2_attr (die, DW_AT_static_link, cu);
> +  if (attr)
> +    {
> +      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
> +					sizeof (*newobj->static_link));
> +      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
> +    }
> +
>    cu->list_in_scope = &local_symbols;
>  
>    if (die->child != NULL)
> @@ -11449,7 +11463,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>    newobj = pop_context ();
>    /* Make a block for the local symbols within.  */
>    block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> -                        lowpc, highpc);
> +			newobj->static_link, lowpc, highpc);
>  
>    /* For C++, set the block's scope.  */
>    if ((cu->language == language_cplus
> @@ -11534,7 +11548,7 @@ 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, newobj->old_blocks,
> +        = finish_block (0, &local_symbols, newobj->old_blocks, NULL,
>  			newobj->start_addr, highpc);
>  
>        /* Note that recording ranges after traversing children, as we
> diff --git a/gdb/f-exp.y b/gdb/f-exp.y
> index 7f53c72..ee24244 100644
> --- a/gdb/f-exp.y
> +++ b/gdb/f-exp.y
> @@ -521,10 +521,7 @@ variable:	name_not_typename
>  				    innermost_block = sym.block;
>  				}
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			      break;
> diff --git a/gdb/findvar.c b/gdb/findvar.c
> index 83b4fca..cc5420e 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,11 +410,166 @@ 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);
> +
> +      /* Stacks can be quite deep: give the user a chance to stop this.  */
> +      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 != NULL
> +	  && (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
> +   functions.
> +
> +   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, const struct block *var_block,
> +		   struct frame_info *frame)
> +{
> +  const struct block *frame_block = NULL;
> +
> +  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)
> +    {
> +      /* Stacks can be quite deep: give the user a chance to stop this.  */
> +      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 function
> +	 level, the immediate upper lexical block is in an outer function:
> +	 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 function 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)

====
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"));
> +	}
> +    }
> +
> +  return frame;
> +}
> +
>  /* A default implementation for the "la_read_var_value" hook in
>     the language vector which should work in most situations.  */
>  
>  struct value *
> -default_read_var_value (struct symbol *var, struct frame_info *frame)
> +default_read_var_value (struct symbol *var, const struct block *var_block,
> +			struct frame_info *frame)
>  {
>    struct value *v;
>    struct type *type = SYMBOL_TYPE (var);
> @@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
>    check_typedef (type);
>  
>    if (symbol_read_needs_frame (var))
> -    gdb_assert (frame);
> +    gdb_assert (frame != NULL);
> +
> +  if (frame != NULL)
> +    frame = get_hosting_frame (var, var_block, frame);
>  
>    if (SYMBOL_COMPUTED_OPS (var) != NULL)
>      return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
> @@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
>  /* Calls VAR's language la_read_var_value hook with the given arguments.  */
>  
>  struct value *
> -read_var_value (struct symbol *var, struct frame_info *frame)
> +read_var_value (struct symbol *var, const struct block *var_block,
> +		struct frame_info *frame)
>  {
>    const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
>  
>    gdb_assert (lang != NULL);
>    gdb_assert (lang->la_read_var_value != NULL);
>  
> -  return lang->la_read_var_value (var, frame);
> +  return lang->la_read_var_value (var, var_block, frame);
>  }
>  
>  /* Install default attributes for register values.  */
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 125af01..301c6fc 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -1885,7 +1885,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;
> @@ -1897,7 +1897,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;
> @@ -2139,7 +2139,8 @@ resolve_dynamic_type_internal (struct type *type,
>  
>    /* Resolve data_location attribute.  */
>    prop = TYPE_DATA_LOCATION (resolved_type);
> -  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
> +  if (prop != NULL
> +      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
>      {
>        TYPE_DYN_PROP_ADDR (prop) = value;
>        TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
> diff --git a/gdb/go-exp.y b/gdb/go-exp.y
> index c1ddfa9..4e017fe 100644
> --- a/gdb/go-exp.y
> +++ b/gdb/go-exp.y
> @@ -611,10 +611,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
> index 64ac0c0..de77c21 100644
> --- a/gdb/guile/scm-frame.c
> +++ b/gdb/guile/scm-frame.c
> @@ -855,6 +855,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
>    SCM block_scm = SCM_UNDEFINED;
>    struct frame_info *frame = NULL;
>    struct symbol *var = NULL;
> +  const struct block *block = NULL;
>    struct value *value = NULL;
>  
>    f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
> @@ -909,9 +910,13 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
>  
>        TRY
>  	{
> +	  struct block_symbol lookup_sym;
> +
>  	  if (block == NULL)
>  	    block = get_frame_block (frame, NULL);
> -	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
> +	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
> +	  var = lookup_sym.symbol;
> +	  block = lookup_sym.block;
>  	}
>        CATCH (ex, RETURN_MASK_ALL)
>  	{
> @@ -940,7 +945,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
>  
>    TRY
>      {
> -      value = read_var_value (var, frame);
> +      value = read_var_value (var, block, frame);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
> index 01c9eb1..0970a72 100644
> --- a/gdb/guile/scm-symbol.c
> +++ b/gdb/guile/scm-symbol.c
> @@ -550,7 +550,11 @@ gdbscm_symbol_value (SCM self, SCM rest)
>        if (symbol_read_needs_frame (symbol) && frame_info == NULL)
>  	error (_("Symbol requires a frame to compute its value"));
>  
> -      value = read_var_value (symbol, frame_info);
> +      /* TODO: currently, we have no way to recover the block in which SYMBOL
> +	 was found, so we have no block to pass to read_var_value.  This will
> +	 yield an incorrect value when symbol is not local to FRAME_INFO (this
> +	 can happen with nested functions).  */
> +      value = read_var_value (symbol, NULL, frame_info);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 4948d27..2872292 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1660,7 +1660,7 @@ finish_command_continuation (void *arg, int err)
>  	    {
>  	      struct value *func;
>  
> -	      func = read_var_value (a->function, get_current_frame ());
> +	      func = read_var_value (a->function, NULL, get_current_frame ());
>  	      TRY
>  		{
>  		  /* print_return_value can throw an exception in some
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 9a46242..a27e804 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -6082,14 +6082,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
>  {
>    TRY
>      {
> -      struct symbol *vsym;
> +      struct block_symbol vsym;
>        struct value *value;
>        CORE_ADDR handler;
>        struct breakpoint *bp;
>  
> -      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
> -			    NULL).symbol;
> -      value = read_var_value (vsym, frame);
> +      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
> +      value = read_var_value (vsym.symbol, vsym.block, frame);
>        /* If the value was optimized out, revert to the old behavior.  */
>        if (! value_optimized_out (value))
>  	{
> diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
> index 4999848..60b7d2e 100644
> --- a/gdb/jv-exp.y
> +++ b/gdb/jv-exp.y
> @@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
>  	}
>  
>        write_exp_elt_opcode (par_state, OP_VAR_VALUE);
> -      /* We want to use the selected frame, not another more inner frame
> -	 which happens to be in the same block.  */
> -      write_exp_elt_block (par_state, NULL);
> +      write_exp_elt_block (par_state, sym.block);
>        write_exp_elt_sym (par_state, sym.symbol);
>        write_exp_elt_opcode (par_state, OP_VAR_VALUE);
>        return 1;
> diff --git a/gdb/language.h b/gdb/language.h
> index 4ecb103..01654c1 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -241,13 +241,19 @@ struct language_defn
>      void (*la_value_print) (struct value *, struct ui_file *,
>  			    const struct value_print_options *);
>  
> -    /* Given a symbol VAR, and a stack frame id FRAME, read the value
> -       of the variable an return (pointer to a) struct value containing
> -       the value.
> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
> +       stack frame id FRAME, read the value of the variable and return (pointer
> +       to a) struct value containing the value.
> +
> +       VAR_BLOCK is needed if there's a possibility for VAR to be outside
> +       FRAME.  This is what happens if FRAME correspond to a nested function
> +       and VAR is defined in the outer function.  If callers know that VAR is
> +       located in FRAME or is global/static, NULL can be passed as VAR_BLOCK.
>  
>         Throw an error if the variable cannot be found.  */
>  
>      struct value *(*la_read_var_value) (struct symbol *var,
> +					const struct block *var_block,
>  					struct frame_info *frame);
>  
>      /* PC is possibly an unknown languages trampoline.
> diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
> index 633c354..360fdea 100644
> --- a/gdb/m2-exp.y
> +++ b/gdb/m2-exp.y
> @@ -637,10 +637,7 @@ variable:	NAME
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/objfiles.c b/gdb/objfiles.c
> index c6f9f00..93d8b7d 100644
> --- a/gdb/objfiles.c
> +++ b/gdb/objfiles.c
> @@ -199,6 +199,92 @@ set_objfile_main_name (struct objfile *objfile,
>    objfile->per_bfd->language_of_main = lang;
>  }
>  
> +/* Helper structure to map blocks to static link properties in hash tables.  */
> +
> +struct static_link_htab_entry
> +{
> +  const struct block *block;
> +  const struct dynamic_prop *static_link;
> +};
> +
> +/* Return a hash code for struct static_link_htab_entry *P.  */
> +
> +static hashval_t
> +static_link_htab_entry_hash (const void *p)
> +{
> +  const struct static_link_htab_entry *e
> +    = (const struct static_link_htab_entry *) p;
> +
> +  return htab_hash_pointer (e->block);
> +}
> +
> +/* Return whether P1 an P2 (pointers to struct static_link_htab_entry) are
> +   mappings for the same block.  */
> +
> +static int
> +static_link_htab_entry_eq (const void *p1, const void *p2)
> +{
> +  const struct static_link_htab_entry *e1
> +    = (const struct static_link_htab_entry *) p1;
> +  const struct static_link_htab_entry *e2
> +    = (const struct static_link_htab_entry *) p2;
> +
> +  return e1->block == e2->block;
> +}
> +
> +/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
> +   Must not be called more than once for each BLOCK.  */
> +
> +void
> +objfile_register_static_link (struct objfile *objfile,
> +			      const struct block *block,
> +			      const struct dynamic_prop *static_link)
> +{
> +  void **slot;
> +  struct static_link_htab_entry lookup_entry;
> +  struct static_link_htab_entry *entry;
> +
> +  if (objfile->static_links == NULL)
> +    objfile->static_links = htab_create_alloc
> +      (1, &static_link_htab_entry_hash, static_link_htab_entry_eq, NULL,
> +       xcalloc, xfree);
> +
> +  /* Create a slot for the mapping, make sure it's the first mapping for this
> +     block and then create the mapping itself.  */
> +  lookup_entry.block = block;
> +  slot = htab_find_slot (objfile->static_links, &lookup_entry, INSERT);
> +  gdb_assert (*slot == NULL);
> +
> +  entry = (struct static_link_htab_entry *) obstack_alloc
> +	    (&objfile->objfile_obstack, sizeof (*entry));
> +  entry->block = block;
> +  entry->static_link = static_link;
> +  *slot = (void *) entry;
> +}
> +
> +/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
> +   none was found.  */
> +
> +const struct dynamic_prop *
> +objfile_lookup_static_link (struct objfile *objfile,
> +			    const struct block *block)
> +{
> +  struct static_link_htab_entry *entry;
> +  struct static_link_htab_entry lookup_entry;
> +
> +  if (objfile->static_links == NULL)
> +    return NULL;
> +  lookup_entry.block = block;
> +  entry
> +    = (struct static_link_htab_entry *) htab_find (objfile->static_links,
> +						   &lookup_entry);
> +  if (entry == NULL)
> +    return NULL;
> +
> +  gdb_assert (entry->block == block);
> +  return entry->static_link;
> +}
> +
>  \f
>  
>  /* Called via bfd_map_over_sections to build up the section table that
> @@ -653,6 +739,11 @@ free_objfile (struct objfile *objfile)
>    /* Rebuild section map next time we need it.  */
>    get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
>  
> +  /* Free the map for static links.  There's no need to free static link
> +     themselves since they were allocated on the objstack.  */
> +  if (objfile->static_links != NULL)
> +    htab_delete (objfile->static_links);
> +
>    /* The last thing we do is free the objfile struct itself.  */
>    xfree (objfile);
>  }
> diff --git a/gdb/objfiles.h b/gdb/objfiles.h
> index a0dc69b..653106f 100644
> --- a/gdb/objfiles.h
> +++ b/gdb/objfiles.h
> @@ -20,6 +20,7 @@
>  #if !defined (OBJFILES_H)
>  #define OBJFILES_H
>  
> +#include "hashtab.h"
>  #include "gdb_obstack.h"	/* For obstack internals.  */
>  #include "symfile.h"		/* For struct psymbol_allocation_list.  */
>  #include "progspace.h"
> @@ -412,6 +413,19 @@ struct objfile
>         table, so we have to keep them here to relocate them
>         properly.  */
>      struct symbol *template_symbols;
> +
> +    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
> +       block *) that have one.
> +
> +       In the context of nested functions (available in Pascal, Ada and GNU C,
> +       for instance), a static link (as in DWARF's DW_AT_static_link attribute)
> +       for a function is a way to get the frame corresponding to the enclosing
> +       function.
> +
> +       Very few blocks have a static link, so it's more memory efficient to
> +       store these here rather than in struct block.  Static links must be
> +       allocated on the objfile's obstack.  */
> +    htab_t static_links;
>    };
>  
>  /* Defines for the objfile flag word.  */
> @@ -719,4 +733,12 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
>  extern void set_objfile_main_name (struct objfile *objfile,
>  				   const char *name, enum language lang);
>  
> +extern void objfile_register_static_link
> +  (struct objfile *objfile,
> +   const struct block *block,
> +   const struct dynamic_prop *static_link);
> +
> +extern const struct dynamic_prop *objfile_lookup_static_link
> +  (struct objfile *objfile, const struct block *block);
> +
>  #endif /* !defined (OBJFILES_H) */
> diff --git a/gdb/p-exp.y b/gdb/p-exp.y
> index 191b3d3..c255a57 100644
> --- a/gdb/p-exp.y
> +++ b/gdb/p-exp.y
> @@ -772,10 +772,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			      current_type = sym.symbol->type; }
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index f51e25c..553cc71 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
>        struct value *val;
>        struct value_print_options opts;
>  
> -      val = read_var_value (var, frame);
> +      /* READ_VAR_VALUE needs a block in order to deal with non-local
> +	 references (i.e. to handle nested functions).  In this context, we
> +	 print variables that are local to this frame, so we can avoid passing
> +	 a block to it.  */
> +      val = read_var_value (var, NULL, frame);
>        get_user_print_options (&opts);
>        opts.deref_ref = 1;
>        common_val_print (val, stream, indent, &opts, current_language);
> diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
> index e3d4867..345642e 100644
> --- a/gdb/python/py-finishbreakpoint.c
> +++ b/gdb/python/py-finishbreakpoint.c
> @@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>                    /* Ignore Python errors at this stage.  */
>                    self_bpfinish->return_type = type_to_type_object (ret_type);
>                    PyErr_Clear ();
> -                  func_value = read_var_value (function, frame);
> +                  func_value = read_var_value (function, NULL, frame);
>                    self_bpfinish->function_value =
>                        value_to_value_object (func_value);
>                    PyErr_Clear ();
> diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
> index 7290056..1923f64 100644
> --- a/gdb/python/py-frame.c
> +++ b/gdb/python/py-frame.c
> @@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
>    struct frame_info *frame;
>    PyObject *sym_obj, *block_obj = NULL;
>    struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
> +  const struct block *block = NULL;
>    struct value *val = NULL;
>  
>    if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
> @@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
>    else if (gdbpy_is_string (sym_obj))
>      {
>        char *var_name;
> -      const struct block *block = NULL;
>        struct cleanup *cleanup;
>  
>        var_name = python_string_to_target_string (sym_obj);
> @@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
>  
>        TRY
>  	{
> +	  struct block_symbol lookup_sym;
>  	  FRAPY_REQUIRE_VALID (self, frame);
>  
>  	  if (!block)
>  	    block = get_frame_block (frame, NULL);
> -	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
> +	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
> +	  var = lookup_sym.symbol;
> +	  block = lookup_sym.block;
>  	}
>        CATCH (except, RETURN_MASK_ALL)
>  	{
> @@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
>      {
>        FRAPY_REQUIRE_VALID (self, frame);
>  
> -      val = read_var_value (var, frame);
> +      val = read_var_value (var, block, frame);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
> index e3336b1..ac97723 100644
> --- a/gdb/python/py-framefilter.c
> +++ b/gdb/python/py-framefilter.c
> @@ -43,16 +43,17 @@ enum mi_print_types
>     NAME is a  pass-through argument where the name of  the symbol will
>     be written.  NAME is allocated in  this function, but the caller is
>     responsible for clean up.  SYM is a pass-through argument where the
> -   symbol will be written.  In the case of the API returning a string,
> -   this will be set to NULL.  LANGUAGE is also a pass-through argument
> -   denoting the language attributed to the Symbol.  In the case of SYM
> -   being  NULL, this  will be  set to  the current  language.  Returns
> -   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
> -   EXT_LANG_BT_OK on success.  */
> +   symbol will be written and  SYM_BLOCK is a pass-through argument to
> +   write  the block where the symbol lies in.  In the case of the  API
> +   returning a  string,  this will be set to NULL.  LANGUAGE is also a
> +   pass-through  argument  denoting  the  language  attributed  to the
> +   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
> +   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
> +   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
>  
>  static enum ext_lang_bt_status
>  extract_sym (PyObject *obj, char **name, struct symbol **sym,
> -	     const struct language_defn **language)
> +	     struct block **sym_block, const struct language_defn **language)
>  {
>    PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
>  
> @@ -75,12 +76,18 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
>  	python_language.  */
>        *language = python_language;
>        *sym = NULL;
> +      *sym_block = NULL;
>      }
>    else
>      {
>        /* This type checks 'result' during the conversion so we
>  	 just call it unconditionally and check the return.  */
>        *sym = symbol_object_to_symbol (result);
> +      /* TODO: currently, we have no way to recover the block in which SYMBOL
> +	 was found, so we have no block to return.  Trying to evaluate SYMBOL
> +	 will yield an incorrect value when it's located in a FRAME and
> +	 evaluated from another frame (as permitted in nested functions).  */
> +      *sym_block = NULL;
>  
>        Py_DECREF (result);
>  
> @@ -537,10 +544,11 @@ enumerate_args (PyObject *iter,
>        const struct language_defn *language;
>        char *sym_name;
>        struct symbol *sym;
> +      struct block *sym_block;
>        struct value *val;
>        enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
>  
> -      success = extract_sym (item, &sym_name, &sym, &language);
> +      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
>        if (success == EXT_LANG_BT_ERROR)
>  	{
>  	  Py_DECREF (item);
> @@ -736,12 +744,13 @@ enumerate_locals (PyObject *iter,
>        struct value *val;
>        enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
>        struct symbol *sym;
> +      struct block *sym_block;
>        int local_indent = 8 + (8 * indent);
>        struct cleanup *locals_cleanups;
>  
>        locals_cleanups = make_cleanup_py_decref (item);
>  
> -      success = extract_sym (item, &sym_name, &sym, &language);
> +      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
>        if (success == EXT_LANG_BT_ERROR)
>  	{
>  	  do_cleanups (locals_cleanups);
> @@ -769,7 +778,7 @@ enumerate_locals (PyObject *iter,
>  	{
>  	  TRY
>  	    {
> -	      val = read_var_value (sym, frame);
> +	      val = read_var_value (sym, sym_block, frame);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
> index 401e7e9..bbc8b6b 100644
> --- a/gdb/python/py-symbol.c
> +++ b/gdb/python/py-symbol.c
> @@ -278,7 +278,11 @@ sympy_value (PyObject *self, PyObject *args)
>        if (symbol_read_needs_frame (symbol) && frame_info == NULL)
>  	error (_("symbol requires a frame to compute its value"));
>  
> -      value = read_var_value (symbol, frame_info);
> +      /* TODO: currently, we have no way to recover the block in which SYMBOL
> +	 was found, so we have no block to pass to read_var_value.  This will
> +	 yield an incorrect value when symbol is not local to FRAME_INFO (this
> +	 can happen with nested functions).  */
> +      value = read_var_value (symbol, NULL, frame_info);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/stack.c b/gdb/stack.c
> index b4cfdbd..5a18a06 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
>  
>    TRY
>      {
> -      argp->val = read_var_value (sym, frame);
> +      argp->val = read_var_value (sym, NULL, frame);
>      }
>    CATCH (except, RETURN_MASK_ERROR)
>      {
> @@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
>      {
>        TRY
>  	{
> -	  val = read_var_value (sym, frame);
> +	  val = read_var_value (sym, NULL, frame);
>  	}
>        CATCH (except, RETURN_MASK_ERROR)
>  	{
> @@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
>  
>  	  TRY
>  	    {
> -	      val = read_var_value (sym, frame);
> +	      val = read_var_value (sym, NULL, frame);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> @@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
>  	value_fetch_lazy (return_value);
>  
>        if (thisfun != NULL)
> -	function = read_var_value (thisfun, thisframe);
> +	function = read_var_value (thisfun, NULL, thisframe);
>  
>        rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
>        if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index 61fc8c5..df781b8 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -665,6 +665,25 @@ 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.  Return 0 on failure (FRAMEFUNC may not hold the
> +     information we need).
> +
> +     This method is designed to work with static links (nested functions
> +     handling).  Static links are function properties whose evaluation returns
> +     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 fuctions, 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.  */
> diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
> new file mode 100644
> index 0000000..967eb2f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp1.c
> @@ -0,0 +1,37 @@
> +/* 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 function 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..9720f5b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp1.exp
> @@ -0,0 +1,55 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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..a6449e34
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp2.c
> @@ -0,0 +1,48 @@
> +/* 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..a107d1c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp2.exp
> @@ -0,0 +1,64 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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..a51f417
> --- /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);
> +
> +extern void process (callback_t cb);
> +extern 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..8f9b522
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp3.exp
> @@ -0,0 +1,55 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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.
> +
> +gdb_test "print first"        "1"
> +gdb_test "print parent_first" "1"
> diff --git a/gdb/valops.c b/gdb/valops.c
> index acaf027..26fdfa6 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1291,27 +1291,12 @@ value_repeat (struct value *arg1, int count)
>  struct value *
>  value_of_variable (struct symbol *var, const struct block *b)
>  {
> -  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);
> +  return read_var_value (var, b, frame);
>  }
>  
>  struct value *
> @@ -3463,9 +3448,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
>  		return NULL;
>  
>  	      if (want_address)
> -		return value_addr (read_var_value (s, 0));
> +		return value_addr (read_var_value (s, 0, 0));
>  	      else
> -		return read_var_value (s, 0);
> +		return read_var_value (s, 0, 0);
>  	    }
>  
>  	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
> @@ -3493,7 +3478,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
>  	      if (s == NULL)
>  		return NULL;
>  
> -	      v = read_var_value (s, 0);
> +	      v = read_var_value (s, 0, 0);
>  	      if (!want_address)
>  		result = v;
>  	      else
> @@ -3729,7 +3714,7 @@ value_full_object (struct value *argp,
>  struct value *
>  value_of_this (const struct language_defn *lang)
>  {
> -  struct symbol *sym;
> +  struct block_symbol sym;
>    const struct block *b;
>    struct frame_info *frame;
>  
> @@ -3740,12 +3725,12 @@ value_of_this (const struct language_defn *lang)
>  
>    b = get_frame_block (frame, NULL);
>  
> -  sym = lookup_language_this (lang, b).symbol;
> -  if (sym == NULL)
> +  sym = lookup_language_this (lang, b);
> +  if (sym.symbol == NULL)
>      error (_("current stack frame does not contain a variable named `%s'"),
>  	   lang->la_name_of_this);
>  
> -  return read_var_value (sym, frame);
> +  return read_var_value (sym.symbol, sym.block, frame);
>  }
>  
>  /* Return the value of the local variable, if one exists.  Return NULL
> diff --git a/gdb/value.h b/gdb/value.h
> index 82deaf2..0a4bc47 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -674,9 +674,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
>  extern int symbol_read_needs_frame (struct symbol *);
>  
>  extern struct value *read_var_value (struct symbol *var,
> +				     const struct block *var_block,
>  				     struct frame_info *frame);
>  
>  extern struct value *default_read_var_value (struct symbol *var,
> +					     const struct block *var_block,
>  					     struct frame_info *frame);
>  
>  extern struct value *allocate_value (struct type *type);
> diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
> index b5b2a1d..4be7dd2 100644
> --- a/gdb/xcoffread.c
> +++ b/gdb/xcoffread.c
> @@ -1389,7 +1389,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
>  		}
>  
>  	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> -			    newobj->start_addr,
> +			    NULL, newobj->start_addr,
>  			    (fcn_cs_saved.c_value
>  			     + fcn_aux_saved.x_sym.x_misc.x_fsize
>  			     + ANOFFSET (objfile->section_offsets,
> @@ -1480,7 +1480,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
>  	      if (local_symbols && context_stack_depth > 0)
>  		{
>  		  /* Make a block for the local symbols within.  */
> -		  finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> +		  finish_block (newobj->name, &local_symbols,
> +				newobj->old_blocks, NULL,
>  				newobj->start_addr,
>  				(cs->c_value
>  				 + ANOFFSET (objfile->section_offsets,

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-07-31 10:53                 ` Pierre-Marie de Rodat
  2015-08-10  8:34                   ` Pierre-Marie de Rodat
  2015-08-15  5:12                   ` Doug Evans
@ 2015-08-15  5:13                   ` Doug Evans
  2 siblings, 0 replies; 40+ messages in thread
From: Doug Evans @ 2015-08-15  5:13 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Kevin Buettner, gdb-patches

Hi.
Just a couple of nits.
Ok with them fixed (not sure what the right fix for the first one is
though, I could be missing something).
grep for ^====

Also, I found a 4% performance degradation in a couple of gmonster
perf tests (e.g., gmonster2-ptype-string.exp).
Not enough to reject the patch, but it would be interesting
to find the culprit (assuming it's not a test issue!).

Pierre-Marie de Rodat <derodat@adacore.com> writes:
> On 07/26/2015 10:34 PM, Doug Evans wrote:
>> Hi.
>>
>> Several nits and questions inline.  grep for ====.
>
> Thank you for reviewing!
>
>> One thing I still want to do is take this patch and run it through
>> the perf testsuite.
>>
>> Also, I still need to look at follow_static_link, get_hosting_frame closer.
>
> Okay.
>
>> Cool stuff though, there's clearly missing functionality we need here.
>
> Indeed, thanks! For the record, just like for the block_found
> business, I re-enabled Guile support in my builds and propagated the
> support for non-local references to the Guile API.
>
>>> +/* Return a property to evaluate the static link associated to BLOCK.  Note
>>> +   that only objfile-owned and function-level blocks can have a static link.
>>> +   Return NULL if there is no such property.  */
>>> +
>>
>> ====
>> Add a comment here stating that the term "static_link" is derived from
>> DW_AT_static_link.
>
> Done. I also added one in objfiles.h, for struct objfile's
> static_links field.
>
>>> -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,
>>
>> ====
>> Move the static_link property here.
>> [Arguments to functions aren't in completely random order,
>> and here static_link is among the collection of random things
>> about the block like start,end. So it reads better to me if
>> static_link appears with start,end]
>
> Fine by me: done and callers updated.
>
>>> +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;
>>> +}
>>
>> ====
>> If this is implemented on top of symbol_block_ops::find_frame_base_location,
>> do we need another method? Or can we just have a wrapper that calls
>> find_frame_base_location?
>> For one, I see block_op_get_frame_base being used for both
>> dwarf2_block_frame_base_locexpr_funcs and
>> dwarf2_block_frame_base_loclist_funcs.
>
> Correct me if I'm wrong, but the problem here is that if we aren't
> handling a "DWARF-described function", then we cannot assume that the
> find_frame_base_location method yields a location
> description. Mhm... maybe I should change it to return a dynamic
> property instead, then: what do you think?

Without non-DWARF examples it's hard to say.

>>> +/* 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))
>>
>> ====
>> It gets harder and harder to reason about correctness the more
>> we blur lines between foo-independent and foo-dependent parts of gdb.
>> [In debug case "foo" == "debug-format".]
>
> Agreed.
>
>> I guess to begin with, why are we calling a dwarf-specific function here
>> and what guarantees are in place (and easily discernable from reading
>> the code!) that the right thing will happen for non-dwarf targets?
>
> My interpretation is that even though dynamic properties seem to be
> used only with DWARF info., they should not be specific to it. In
> other words, dwarf2_evaluate_property should be called instead
> something like "evaluate_dynamic_prop" and moved elsewhere. After all,
> struct dynamic_prop isn't supposed to be itself DWARF-specific, and it
> is defined in gdbtypes.h.

I see.
I also see gdbtypes.c calling dwarf2_evaluate_property. Bleah.
dwarf2_evaluate_property has a lot of dwarf-specific code in it.

I guess this is ok, for now anyway.


>>> +      /* Protect ourselves against bad things such as circular call stacks.  */
>>
>> ====
>> Here's a good question.
>> gdb has other mechanisms to catch corrupt (e.g., circular) stacks
>> (e.g., UNWIND_INNER_ID). Is this QUIT here for protection or in case
>> of really large stacks (e.g., due to infinite recursion)?
>>
>>> +      QUIT;
>
> I wasn't aware of these mechanisms: thanks! Well, I had indeed
> circular stacks in mind, but this QUIT is also here to let users stop
> heavy computations in case of huge stacks (Joel advised me live to do
> this for this reason). So the comment is misleading and I have updated
> it. Thanks!
>
>>> +      if (framefunc != NULL
>>> +	  && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base
>>
>> ====
>> != NULL
>
> Done.
>
>>> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
>>> +       stack frame id FRAME, read the value of the variable and return (pointer
>>> +       to a) struct value containing the value.
>>> +
>>> +       VAR_BLOCK is needed if there's a possibility for VAR to be outside
>>> +       FRAME.  This is what happens if FRAME correspond to a nested function
>>> +       and VAR is defined in the outer function.  If callers know that VAR is
>>> +       located in FRAME, NULL can be passed as VAR_BLOCK.
>>
>> ====
>> "If callers know that VAR is located in FRAME or is global, ..." ?
>
> Indeed. I added "or is global/static" instead.
>
>>> +struct static_link_htab_entry
>>> +{
>>> +  const struct block *block;
>>> +  struct dynamic_prop *static_link;
>>
>> ====
>> It's too bad this isn't const struct dynamic_prop *static_link;
>> I'm guessing it can't be that without fixing some laxness elsewhere
>> (which I wouldn't impose on this patch), but can you check?
>
> I thought it would indeed bring a lot of changes everywhere... but
> it's not actually! I could add const qualifiers everywhere on dynamic
> properties in objfiles.* without trouble at all and added a coulpe in
> buildsym.* as well. Thanks for suggesting this!
>
>>> +static int
>>> +static_link_htab_entry_eq (const void *p1, const void *p2)
>>> +{
>>> +  const struct static_link_htab_entry *entry
>>> +    = (const struct static_link_htab_entry *) p1;
>>> +  const struct block *block = (const struct block *) p2;
>>
>> ====
>> blank line here
>
> Done.
>
>> Also, this is a non-standard implementation of an htab eq function.
>> Generally both p1 and p2 point to an element in the hash table.
>>
>> I see hashtab.h has this:
>>
>> /* Compare a table entry with a possible entry.  The entry already in
>>     the table always comes first, so the second element can be of a
>>     different type (but in this case htab_find and htab_find_slot
>>     cannot be used; instead the variants that accept a hash value
>>     must be used).  */
>> typedef int (*htab_eq) (const void *, const void *);
>>
>> so this eq function is possibly ok, except I also see calls to
>> htab_find,htab_find_slot below. AIUC, one of these needs to change.
>
> Yeah... I spent some time before having something that actually worked
> (first time I used this container) and got it wrong wrt. to doc
> anyway. Now, I eventually understood that all hash table lookups must
> be done with struct static_link_htab_entry * instead of struct block
> *, so I could fix the htab_eq function to be commutative.
>
>>> +  if (entry == NULL)
>>> +    return NULL;
>>> +  else
>>
>> ====
>> I don't know how others feel, but "else" clauses in particular situations
>> like this are just noise. How about removing it?
>
> Sure, removed.
>
>>> +    struct htab *static_links;
>>
>> ====
>> s/struct htab */htab_t /
>
> Done.
>
>>> +
>>> +  /* 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 functions
>>> +     handling).  Static links are function properties whose evaluation return
>>
>> ====
>> s/return/returns/
>
> Fixed: thanks!
>
> Updated patch is attached and tested again on x86_64-linux.
>
> -- 
> Pierre-Marie de Rodat
>
> From 26961370aaa5343e0164ded82dc7531a44bebc6d 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] DWARF: handle non-local references in nested functions
>
> GDB's current behavior when dealing with non-local references in the
> context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
> references.
>
> gdb/ChangeLog:
>
> 	* ada-lang.c (ada_read_var_value): Add a var_block argument
> 	and pass it to default_read_var_value.
> 	* block.c (block_static_link): New accessor.
> 	* block.h (block_static_link): Declare it.
> 	* buildsym.c (finish_block_internal): Add a static_link
> 	argument.  If there is a static link, associate it to the new
> 	block.
> 	(finish_block): Add a static link argument and pass it to
> 	finish_block_internal.
> 	(end_symtab_get_static_block): Update calls to finish_block and
> 	to finish_block_internal.
> 	(end_symtab_with_blockvector): Update call to
> 	finish_block_internal.
> 	* buildsym.h: Forward-declare struct dynamic_prop.
> 	(struct context_stack): Add a static_link field.
> 	(finish_block): Add a static link argument.
> 	* c-exp.y: Remove an obsolete comment (evaluation of variables
> 	already start from the selected frame, and now they climb *up*
> 	the call stack) and propagate the block information to the
> 	produced expression.
> 	* d-exp.y: Likewise.
> 	* f-exp.y: Likewise.
> 	* go-exp.y: Likewise.
> 	* jv-exp.y: Likewise.
> 	* m2-exp.y: Likewise.
> 	* p-exp.y: Likewise.
> 	* coffread.c (coff_symtab_read): Update calls to finish_block.
> 	* dbxread.c (process_one_symbol): Likewise.
> 	* xcoffread.c (read_xcoff_symtab): Likewise.
> 	* compile/compile-c-symbols.c (convert_one_symbol): Promote the
> 	"sym" parameter to struct block_symbol, update its uses and pass
> 	its block to calls to read_var_value.
> 	(convert_symbol_sym): Update the calls to convert_one_symbol.
> 	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
> 	call to read_var_value.
> 	* 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.
> 	* findvar.c (follow_static_link): New.
> 	(get_hosting_frame): New.
> 	(default_read_var_value): Add a var_block argument.  Use
> 	get_hosting_frame to handle non-local references.
> 	(read_var_value): Add a var_block argument and pass it to the
> 	LA_READ_VAR_VALUE method.
> 	* gdbtypes.c (resolve_dynamic_range): Update calls to
> 	dwarf2_evaluate_property.
> 	(resolve_dynamic_type_internal): Likewise.
> 	* guile/scm-frame.c (gdbscm_frame_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* guile/scm-symbol.c (gdbscm_symbol_value): Update call to
> 	read_var_value (TODO).
> 	* infcmd.c (finish_command_continuation): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* infrun.c (insert_exception_resume_breakpoint): Likewise.
> 	* language.h (struct language_defn): Add a var_block argument to
> 	the LA_READ_VAR_VALUE method.
> 	* objfiles.c (struct static_link_htab_entry): New.
> 	(static_link_htab_entry_hash): New.
> 	(static_link_htab_entry_eq): New.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	(free_objfile): Free the STATIC_LINKS hashed map if needed.
> 	* objfiles.h: Include hashtab.h.
> 	(struct objfile): Add a static_links field.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	* printcmd.c (print_variable_and_value): Update call to
> 	read_var_value.
> 	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
> 	* python/py-frame.c (frapy_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* python/py-framefilter.c (extract_sym): Add a sym_block
> 	parameter and set the pointed value to NULL (TODO).
> 	(enumerate_args): Update call to extract_sym.
> 	(enumerate_locals): Update calls to extract_sym and to
> 	read_var_value.
> 	* python/py-symbol.c (sympy_value): Update call to
> 	read_var_value (TODO).
> 	* stack.c (read_frame_local): Update call to read_var_value.
> 	(read_frame_arg): Likewise.
> 	(return_command): Likewise.
> 	* symtab.h (struct symbol_block_ops): Add a get_frame_base
> 	method.
> 	(struct symbol): Add a block field.
> 	(SYMBOL_BLOCK): New accessor.
> 	* valops.c (value_of_variable): Remove frame/block handling and
> 	pass the block argument to read_var_value, which does this job
> 	now.
> 	(value_struct_elt_for_reference): Update calls to
> 	read_var_value.
> 	(value_of_this): Pass the block found to read_var_value.
> 	* value.h (read_var_value): Add a var_block argument.
> 	(default_read_var_value): Likewise.
>
> gdb/testsuite/ChangeLog:
>
> 	* 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.
>...
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 049fb48..3f0bdb1 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -13749,7 +13749,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
>  /* Implement the "la_read_var_value" language_defn method for Ada.  */
>  
>  static struct value *
> -ada_read_var_value (struct symbol *var, struct frame_info *frame)
> +ada_read_var_value (struct symbol *var, const struct block *var_block,
> +		    struct frame_info *frame)
>  {
>    const struct block *frame_block = NULL;
>    struct symbol *renaming_sym = NULL;
> @@ -13765,7 +13766,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
>  
>    /* This is a typical case where we expect the default_read_var_value
>       function to work.  */
> -  return default_read_var_value (var, frame);
> +  return default_read_var_value (var, var_block, frame);
>  }
>  
>  const struct language_defn ada_language_defn = {
> diff --git a/gdb/block.c b/gdb/block.c
> index f7621aa..f4b8e4f 100644
> --- a/gdb/block.c
> +++ b/gdb/block.c
> @@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
>    gb->compunit_symtab = cu;
>  }
>  
> +/* See block.h.  */
> +
> +struct dynamic_prop *
> +block_static_link (const struct block *block)
> +{
> +  struct objfile *objfile = block_objfile (block);
> +
> +  /* Only objfile-owned blocks that materialize top function scopes can have
> +     static links.  */
> +  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
> +    return NULL;
> +
> +  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
> +}
> +
>  /* Return the compunit of the global block.  */
>  
>  static struct compunit_symtab *
> diff --git a/gdb/block.h b/gdb/block.h
> index d8ad343..aac7929 100644
> --- a/gdb/block.h
> +++ b/gdb/block.h
> @@ -190,6 +190,17 @@ extern struct block *allocate_global_block (struct obstack *obstack);
>  extern void set_block_compunit_symtab (struct block *,
>  				       struct compunit_symtab *);
>  
> +/* Return a property to evaluate the static link associated to BLOCK.
> +
> +   In the context of nested functions (available in Pascal, Ada and GNU C, for
> +   instance), a static link (as in DWARF's DW_AT_static_link attribute) for a
> +   function is a way to get the frame corresponding to the enclosing function.
> +
> +   Note that only objfile-owned and function-level blocks can have a static
> +   link.  Return NULL if there is no such property.  */
> +
> +extern struct dynamic_prop *block_static_link (const struct block *block);
> +
>  /* A block iterator.  This structure should be treated as though it
>     were opaque; it is only defined here because we want to support
>     stack allocation of iterators.  */
> diff --git a/gdb/buildsym.c b/gdb/buildsym.c
> index 2a24a25..ba4f219 100644
> --- a/gdb/buildsym.c
> +++ b/gdb/buildsym.c
> @@ -331,8 +331,10 @@ 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 pending **listhead,
>  		       struct pending_block *old_blocks,
> +		       const struct dynamic_prop *static_link,
>  		       CORE_ADDR start, CORE_ADDR end,
>  		       int is_global, int expandable)
>  {
> @@ -422,6 +424,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
>        BLOCK_FUNCTION (block) = NULL;
>      }
>  
> +  if (static_link != NULL)
> +    objfile_register_static_link (objfile, block, static_link);
> +
>    /* Now "free" the links of the list, and empty the list.  */
>  
>    for (next = *listhead; next; next = next1)
> @@ -512,11 +517,13 @@ 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 pending **listhead,
>  	      struct pending_block *old_blocks,
> +	      const struct dynamic_prop *static_link,
>  	      CORE_ADDR start, CORE_ADDR end)
>  {
> -  return finish_block_internal (symbol, listhead, old_blocks,
> +  return finish_block_internal (symbol, listhead, old_blocks, static_link,
>  				start, end, 0, 0);
>  }
>  
> @@ -1218,7 +1225,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, &local_symbols, cstk->old_blocks, NULL,
>  		    cstk->start_addr, end_addr);
>  
>        if (context_stack_depth > 0)
> @@ -1289,7 +1296,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, &file_symbols, NULL, NULL,
>  				    last_source_start_addr, end_addr,
>  				    0, expandable);
>      }
> @@ -1317,7 +1324,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, &global_symbols, NULL, NULL,
>  			 last_source_start_addr, end_addr,
>  			 1, expandable);
>    blockvector = make_blockvector ();
> diff --git a/gdb/buildsym.h b/gdb/buildsym.h
> index f98203e..81c00f3 100644
> --- a/gdb/buildsym.h
> +++ b/gdb/buildsym.h
> @@ -39,6 +39,8 @@ struct compunit_symtab;
>  struct block;
>  struct pending_block;
>  
> +struct dynamic_prop;
> +
>  #ifndef EXTERN
>  #define	EXTERN extern
>  #endif
> @@ -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,11 @@ 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 pending **listhead,
> +				   struct pending_block *old_blocks,
> +				   const struct dynamic_prop *static_link,
> +				   CORE_ADDR start,
> +				   CORE_ADDR end);
>  
>  extern void record_block_range (struct block *,
>                                  CORE_ADDR start, CORE_ADDR end_inclusive);
> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
> index 59cecb5..9504e92 100644
> --- a/gdb/c-exp.y
> +++ b/gdb/c-exp.y
> @@ -1072,10 +1072,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/coffread.c b/gdb/coffread.c
> index 7722cdb..c0f4267 100644
> --- a/gdb/coffread.c
> +++ b/gdb/coffread.c
> @@ -1144,8 +1144,8 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
>  		enter_linenos (fcn_line_ptr, fcn_first_line,
>  			       fcn_last_line, objfile);
>  
> -	      finish_block (newobj->name, &local_symbols,
> -			    newobj->old_blocks, newobj->start_addr,
> +	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> +			    NULL, newobj->start_addr,
>  			    fcn_cs_saved.c_value
>  			    + fcn_aux_saved.x_sym.x_misc.x_fsize
>  			    + ANOFFSET (objfile->section_offsets,
> @@ -1188,7 +1188,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, newobj->old_blocks,
> +		  finish_block (0, &local_symbols, newobj->old_blocks, NULL,
>  				newobj->start_addr, tmpaddr);
>  		}
>  	      /* Now pop locals of block just finished.  */
> diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
> index 21ce655..355b063 100644
> --- a/gdb/compile/compile-c-symbols.c
> +++ b/gdb/compile/compile-c-symbols.c
> @@ -143,26 +143,26 @@ symbol_substitution_name (struct symbol *sym)
>  
>  static void
>  convert_one_symbol (struct compile_c_instance *context,
> -		    struct symbol *sym,
> +		    struct block_symbol sym,
>  		    int is_global,
>  		    int is_local)
>  {
>    gcc_type sym_type;
> -  const char *filename = symbol_symtab (sym)->filename;
> -  unsigned short line = SYMBOL_LINE (sym);
> +  const char *filename = symbol_symtab (sym.symbol)->filename;
> +  unsigned short line = SYMBOL_LINE (sym.symbol);
>  
> -  error_symbol_once (context, sym);
> +  error_symbol_once (context, sym.symbol);
>  
> -  if (SYMBOL_CLASS (sym) == LOC_LABEL)
> +  if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
>      sym_type = 0;
>    else
> -    sym_type = convert_type (context, SYMBOL_TYPE (sym));
> +    sym_type = convert_type (context, SYMBOL_TYPE (sym.symbol));
>  
> -  if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
> +  if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
>      {
>        /* Binding a tag, so we don't need to build a decl.  */
>        C_CTX (context)->c_ops->tagbind (C_CTX (context),
> -				       SYMBOL_NATURAL_NAME (sym),
> +				       SYMBOL_NATURAL_NAME (sym.symbol),
>  				       sym_type, filename, line);
>      }
>    else
> @@ -172,7 +172,7 @@ convert_one_symbol (struct compile_c_instance *context,
>        CORE_ADDR addr = 0;
>        char *symbol_name = NULL;
>  
> -      switch (SYMBOL_CLASS (sym))
> +      switch (SYMBOL_CLASS (sym.symbol))
>  	{
>  	case LOC_TYPEDEF:
>  	  kind = GCC_C_SYMBOL_TYPEDEF;
> @@ -180,45 +180,46 @@ convert_one_symbol (struct compile_c_instance *context,
>  
>  	case LOC_LABEL:
>  	  kind = GCC_C_SYMBOL_LABEL;
> -	  addr = SYMBOL_VALUE_ADDRESS (sym);
> +	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
>  	  break;
>  
>  	case LOC_BLOCK:
>  	  kind = GCC_C_SYMBOL_FUNCTION;
> -	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
> -	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
> +	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
> +	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
>  	    addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
>  	  break;
>  
>  	case LOC_CONST:
> -	  if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
> +	  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
>  	    {
>  	      /* Already handled by convert_enum.  */
>  	      return;
>  	    }
> -	  C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
> -						  SYMBOL_NATURAL_NAME (sym),
> -						  SYMBOL_VALUE (sym),
> -						  filename, line);
> +	  C_CTX (context)->c_ops->build_constant
> +	    (C_CTX (context),
> +	     sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
> +	     SYMBOL_VALUE (sym.symbol),
> +	     filename, line);
>  	  return;
>  
>  	case LOC_CONST_BYTES:
>  	  error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
> -		 SYMBOL_PRINT_NAME (sym));
> +		 SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_UNDEF:
>  	  internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
> -			  SYMBOL_PRINT_NAME (sym));
> +			  SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_COMMON_BLOCK:
>  	  error (_("Fortran common block is unsupported for compilation "
>  		   "evaluaton of symbol \"%s\"."),
> -		 SYMBOL_PRINT_NAME (sym));
> +		 SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_OPTIMIZED_OUT:
>  	  error (_("Symbol \"%s\" cannot be used for compilation evaluation "
>  		   "as it is optimized out."),
> -		 SYMBOL_PRINT_NAME (sym));
> +		 SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	case LOC_COMPUTED:
>  	  if (is_local)
> @@ -227,7 +228,7 @@ convert_one_symbol (struct compile_c_instance *context,
>  	  warning (_("Symbol \"%s\" is thread-local and currently can only "
>  		     "be referenced from the current thread in "
>  		     "compiled code."),
> -		   SYMBOL_PRINT_NAME (sym));
> +		   SYMBOL_PRINT_NAME (sym.symbol));
>  	  /* FALLTHROUGH */
>  	case LOC_UNRESOLVED:
>  	  /* 'symbol_name' cannot be used here as that one is used only for
> @@ -238,20 +239,20 @@ convert_one_symbol (struct compile_c_instance *context,
>  	    struct value *val;
>  	    struct frame_info *frame = NULL;
>  
> -	    if (symbol_read_needs_frame (sym))
> +	    if (symbol_read_needs_frame (sym.symbol))
>  	      {
>  		frame = get_selected_frame (NULL);
>  		if (frame == NULL)
>  		  error (_("Symbol \"%s\" cannot be used because "
>  			   "there is no selected frame"),
> -			 SYMBOL_PRINT_NAME (sym));
> +			 SYMBOL_PRINT_NAME (sym.symbol));
>  	      }
>  
> -	    val = read_var_value (sym, frame);
> +	    val = read_var_value (sym.symbol, sym.block, frame);
>  	    if (VALUE_LVAL (val) != lval_memory)
>  	      error (_("Symbol \"%s\" cannot be used for compilation "
>  		       "evaluation as its address has not been found."),
> -		     SYMBOL_PRINT_NAME (sym));
> +		     SYMBOL_PRINT_NAME (sym.symbol));
>  
>  	    kind = GCC_C_SYMBOL_VARIABLE;
>  	    addr = value_address (val);
> @@ -266,12 +267,12 @@ convert_one_symbol (struct compile_c_instance *context,
>  	case LOC_LOCAL:
>  	substitution:
>  	  kind = GCC_C_SYMBOL_VARIABLE;
> -	  symbol_name = symbol_substitution_name (sym);
> +	  symbol_name = symbol_substitution_name (sym.symbol);
>  	  break;
>  
>  	case LOC_STATIC:
>  	  kind = GCC_C_SYMBOL_VARIABLE;
> -	  addr = SYMBOL_VALUE_ADDRESS (sym);
> +	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
>  	  break;
>  
>  	case LOC_FINAL_VALUE:
> @@ -284,12 +285,13 @@ convert_one_symbol (struct compile_c_instance *context,
>        if (context->base.scope != COMPILE_I_RAW_SCOPE
>  	  || symbol_name == NULL)
>  	{
> -	  decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
> -						     SYMBOL_NATURAL_NAME (sym),
> -						     kind,
> -						     sym_type,
> -						     symbol_name, addr,
> -						     filename, line);
> +	  decl = C_CTX (context)->c_ops->build_decl
> +	    (C_CTX (context),
> +	     SYMBOL_NATURAL_NAME (sym.symbol),
> +	     kind,
> +	     sym_type,
> +	     symbol_name, addr,
> +	     filename, line);
>  
>  	  C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
>  	}
> @@ -338,7 +340,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
>  	    fprintf_unfiltered (gdb_stdlog,
>  				"gcc_convert_symbol \"%s\": global symbol\n",
>  				identifier);
> -	  convert_one_symbol (context, global_sym.symbol, 1, 0);
> +	  convert_one_symbol (context, global_sym, 1, 0);
>  	}
>      }
>  
> @@ -346,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
>      fprintf_unfiltered (gdb_stdlog,
>  			"gcc_convert_symbol \"%s\": local symbol\n",
>  			identifier);
> -  convert_one_symbol (context, sym.symbol, 0, is_local_symbol);
> +  convert_one_symbol (context, sym, 0, is_local_symbol);
>  }
>  
>  /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
> diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
> index 6f53814..18ca4ae 100644
> --- a/gdb/compile/compile-loc2c.c
> +++ b/gdb/compile/compile-loc2c.c
> @@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
>  		 "there is no selected frame"),
>  	       SYMBOL_PRINT_NAME (sym));
>  
> -      val = read_var_value (sym, frame);
> +      val = read_var_value (sym, NULL, frame);
>        if (VALUE_LVAL (val) != lval_memory)
>  	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
>  		 "as its address has not been found."),
> diff --git a/gdb/d-exp.y b/gdb/d-exp.y
> index 1b7a09c..fa4f78c 100644
> --- a/gdb/d-exp.y
> +++ b/gdb/d-exp.y
> @@ -1067,9 +1067,7 @@ push_variable (struct parser_state *ps, struct stoken name)
>          }
>  
>        write_exp_elt_opcode (ps, OP_VAR_VALUE);
> -      /* We want to use the selected frame, not another more inner frame
> -         which happens to be in the same block.  */
> -      write_exp_elt_block (ps, NULL);
> +      write_exp_elt_block (ps, sym.block);
>        write_exp_elt_sym (ps, sym.symbol);
>        write_exp_elt_opcode (ps, OP_VAR_VALUE);
>        return 1;
> diff --git a/gdb/dbxread.c b/gdb/dbxread.c
> index 6098b35..56967a8 100644
> --- a/gdb/dbxread.c
> +++ b/gdb/dbxread.c
> @@ -2767,7 +2767,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  
>  	  /* Make a block for the local symbols within.  */
>  	  block = finish_block (newobj->name, &local_symbols,
> -				newobj->old_blocks,
> +				newobj->old_blocks, NULL,
>  				newobj->start_addr, newobj->start_addr + valu);
>  
>  	  /* For C++, set the block's scope.  */
> @@ -2868,7 +2868,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  		  newobj->start_addr = valu;
>  		}
>  	      /* Make a block for the local symbols within.  */
> -	      finish_block (0, &local_symbols, newobj->old_blocks,
> +	      finish_block (0, &local_symbols, newobj->old_blocks, NULL,
>  			    newobj->start_addr, valu);
>  	    }
>  	}
> @@ -3166,8 +3166,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
>  		  newobj = pop_context ();
>  		  /* Make a block for the local symbols within.  */
>  		  block = finish_block (newobj->name, &local_symbols,
> -					newobj->old_blocks, newobj->start_addr,
> -					valu);
> +					newobj->old_blocks, NULL,
> +					newobj->start_addr, valu);
>  
>  		  /* For C++, set the block's scope.  */
>  		  if (SYMBOL_LANGUAGE (newobj->name) == language_cplus)
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index c75767e..edfa220 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)

====
It's hard for this reader to figure out why this test is here.
If the code gets here, when would find_frame_base_location be NULL?
Seems like we could just assert find_frame_base_location is non-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 f3630ac..2415656 100644
> --- a/gdb/dwarf2loc.h
> +++ b/gdb/dwarf2loc.h
> @@ -122,12 +122,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 24a4022..9359f0d 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -1737,6 +1737,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 *);
> @@ -11398,6 +11402,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>    if (attr)
>      dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
>  
> +  /* If there is a location for the static link, record it.  */
> +  newobj->static_link = NULL;
> +  attr = dwarf2_attr (die, DW_AT_static_link, cu);
> +  if (attr)
> +    {
> +      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
> +					sizeof (*newobj->static_link));
> +      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
> +    }
> +
>    cu->list_in_scope = &local_symbols;
>  
>    if (die->child != NULL)
> @@ -11449,7 +11463,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
>    newobj = pop_context ();
>    /* Make a block for the local symbols within.  */
>    block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> -                        lowpc, highpc);
> +			newobj->static_link, lowpc, highpc);
>  
>    /* For C++, set the block's scope.  */
>    if ((cu->language == language_cplus
> @@ -11534,7 +11548,7 @@ 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, newobj->old_blocks,
> +        = finish_block (0, &local_symbols, newobj->old_blocks, NULL,
>  			newobj->start_addr, highpc);
>  
>        /* Note that recording ranges after traversing children, as we
> diff --git a/gdb/f-exp.y b/gdb/f-exp.y
> index 7f53c72..ee24244 100644
> --- a/gdb/f-exp.y
> +++ b/gdb/f-exp.y
> @@ -521,10 +521,7 @@ variable:	name_not_typename
>  				    innermost_block = sym.block;
>  				}
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			      break;
> diff --git a/gdb/findvar.c b/gdb/findvar.c
> index 83b4fca..cc5420e 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,11 +410,166 @@ 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);
> +
> +      /* Stacks can be quite deep: give the user a chance to stop this.  */
> +      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 != NULL
> +	  && (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
> +   functions.
> +
> +   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, const struct block *var_block,
> +		   struct frame_info *frame)
> +{
> +  const struct block *frame_block = NULL;
> +
> +  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)
> +    {
> +      /* Stacks can be quite deep: give the user a chance to stop this.  */
> +      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 function
> +	 level, the immediate upper lexical block is in an outer function:
> +	 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 function 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)

====
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"));
> +	}
> +    }
> +
> +  return frame;
> +}
> +
>  /* A default implementation for the "la_read_var_value" hook in
>     the language vector which should work in most situations.  */
>  
>  struct value *
> -default_read_var_value (struct symbol *var, struct frame_info *frame)
> +default_read_var_value (struct symbol *var, const struct block *var_block,
> +			struct frame_info *frame)
>  {
>    struct value *v;
>    struct type *type = SYMBOL_TYPE (var);
> @@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
>    check_typedef (type);
>  
>    if (symbol_read_needs_frame (var))
> -    gdb_assert (frame);
> +    gdb_assert (frame != NULL);
> +
> +  if (frame != NULL)
> +    frame = get_hosting_frame (var, var_block, frame);
>  
>    if (SYMBOL_COMPUTED_OPS (var) != NULL)
>      return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
> @@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
>  /* Calls VAR's language la_read_var_value hook with the given arguments.  */
>  
>  struct value *
> -read_var_value (struct symbol *var, struct frame_info *frame)
> +read_var_value (struct symbol *var, const struct block *var_block,
> +		struct frame_info *frame)
>  {
>    const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
>  
>    gdb_assert (lang != NULL);
>    gdb_assert (lang->la_read_var_value != NULL);
>  
> -  return lang->la_read_var_value (var, frame);
> +  return lang->la_read_var_value (var, var_block, frame);
>  }
>  
>  /* Install default attributes for register values.  */
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 125af01..301c6fc 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -1885,7 +1885,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;
> @@ -1897,7 +1897,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;
> @@ -2139,7 +2139,8 @@ resolve_dynamic_type_internal (struct type *type,
>  
>    /* Resolve data_location attribute.  */
>    prop = TYPE_DATA_LOCATION (resolved_type);
> -  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
> +  if (prop != NULL
> +      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
>      {
>        TYPE_DYN_PROP_ADDR (prop) = value;
>        TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
> diff --git a/gdb/go-exp.y b/gdb/go-exp.y
> index c1ddfa9..4e017fe 100644
> --- a/gdb/go-exp.y
> +++ b/gdb/go-exp.y
> @@ -611,10 +611,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
> index 64ac0c0..de77c21 100644
> --- a/gdb/guile/scm-frame.c
> +++ b/gdb/guile/scm-frame.c
> @@ -855,6 +855,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
>    SCM block_scm = SCM_UNDEFINED;
>    struct frame_info *frame = NULL;
>    struct symbol *var = NULL;
> +  const struct block *block = NULL;
>    struct value *value = NULL;
>  
>    f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
> @@ -909,9 +910,13 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
>  
>        TRY
>  	{
> +	  struct block_symbol lookup_sym;
> +
>  	  if (block == NULL)
>  	    block = get_frame_block (frame, NULL);
> -	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
> +	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
> +	  var = lookup_sym.symbol;
> +	  block = lookup_sym.block;
>  	}
>        CATCH (ex, RETURN_MASK_ALL)
>  	{
> @@ -940,7 +945,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
>  
>    TRY
>      {
> -      value = read_var_value (var, frame);
> +      value = read_var_value (var, block, frame);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
> index 01c9eb1..0970a72 100644
> --- a/gdb/guile/scm-symbol.c
> +++ b/gdb/guile/scm-symbol.c
> @@ -550,7 +550,11 @@ gdbscm_symbol_value (SCM self, SCM rest)
>        if (symbol_read_needs_frame (symbol) && frame_info == NULL)
>  	error (_("Symbol requires a frame to compute its value"));
>  
> -      value = read_var_value (symbol, frame_info);
> +      /* TODO: currently, we have no way to recover the block in which SYMBOL
> +	 was found, so we have no block to pass to read_var_value.  This will
> +	 yield an incorrect value when symbol is not local to FRAME_INFO (this
> +	 can happen with nested functions).  */
> +      value = read_var_value (symbol, NULL, frame_info);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 4948d27..2872292 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1660,7 +1660,7 @@ finish_command_continuation (void *arg, int err)
>  	    {
>  	      struct value *func;
>  
> -	      func = read_var_value (a->function, get_current_frame ());
> +	      func = read_var_value (a->function, NULL, get_current_frame ());
>  	      TRY
>  		{
>  		  /* print_return_value can throw an exception in some
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 9a46242..a27e804 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -6082,14 +6082,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
>  {
>    TRY
>      {
> -      struct symbol *vsym;
> +      struct block_symbol vsym;
>        struct value *value;
>        CORE_ADDR handler;
>        struct breakpoint *bp;
>  
> -      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
> -			    NULL).symbol;
> -      value = read_var_value (vsym, frame);
> +      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
> +      value = read_var_value (vsym.symbol, vsym.block, frame);
>        /* If the value was optimized out, revert to the old behavior.  */
>        if (! value_optimized_out (value))
>  	{
> diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
> index 4999848..60b7d2e 100644
> --- a/gdb/jv-exp.y
> +++ b/gdb/jv-exp.y
> @@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
>  	}
>  
>        write_exp_elt_opcode (par_state, OP_VAR_VALUE);
> -      /* We want to use the selected frame, not another more inner frame
> -	 which happens to be in the same block.  */
> -      write_exp_elt_block (par_state, NULL);
> +      write_exp_elt_block (par_state, sym.block);
>        write_exp_elt_sym (par_state, sym.symbol);
>        write_exp_elt_opcode (par_state, OP_VAR_VALUE);
>        return 1;
> diff --git a/gdb/language.h b/gdb/language.h
> index 4ecb103..01654c1 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -241,13 +241,19 @@ struct language_defn
>      void (*la_value_print) (struct value *, struct ui_file *,
>  			    const struct value_print_options *);
>  
> -    /* Given a symbol VAR, and a stack frame id FRAME, read the value
> -       of the variable an return (pointer to a) struct value containing
> -       the value.
> +    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
> +       stack frame id FRAME, read the value of the variable and return (pointer
> +       to a) struct value containing the value.
> +
> +       VAR_BLOCK is needed if there's a possibility for VAR to be outside
> +       FRAME.  This is what happens if FRAME correspond to a nested function
> +       and VAR is defined in the outer function.  If callers know that VAR is
> +       located in FRAME or is global/static, NULL can be passed as VAR_BLOCK.
>  
>         Throw an error if the variable cannot be found.  */
>  
>      struct value *(*la_read_var_value) (struct symbol *var,
> +					const struct block *var_block,
>  					struct frame_info *frame);
>  
>      /* PC is possibly an unknown languages trampoline.
> diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
> index 633c354..360fdea 100644
> --- a/gdb/m2-exp.y
> +++ b/gdb/m2-exp.y
> @@ -637,10 +637,7 @@ variable:	NAME
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			    }
> diff --git a/gdb/objfiles.c b/gdb/objfiles.c
> index c6f9f00..93d8b7d 100644
> --- a/gdb/objfiles.c
> +++ b/gdb/objfiles.c
> @@ -199,6 +199,92 @@ set_objfile_main_name (struct objfile *objfile,
>    objfile->per_bfd->language_of_main = lang;
>  }
>  
> +/* Helper structure to map blocks to static link properties in hash tables.  */
> +
> +struct static_link_htab_entry
> +{
> +  const struct block *block;
> +  const struct dynamic_prop *static_link;
> +};
> +
> +/* Return a hash code for struct static_link_htab_entry *P.  */
> +
> +static hashval_t
> +static_link_htab_entry_hash (const void *p)
> +{
> +  const struct static_link_htab_entry *e
> +    = (const struct static_link_htab_entry *) p;
> +
> +  return htab_hash_pointer (e->block);
> +}
> +
> +/* Return whether P1 an P2 (pointers to struct static_link_htab_entry) are
> +   mappings for the same block.  */
> +
> +static int
> +static_link_htab_entry_eq (const void *p1, const void *p2)
> +{
> +  const struct static_link_htab_entry *e1
> +    = (const struct static_link_htab_entry *) p1;
> +  const struct static_link_htab_entry *e2
> +    = (const struct static_link_htab_entry *) p2;
> +
> +  return e1->block == e2->block;
> +}
> +
> +/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
> +   Must not be called more than once for each BLOCK.  */
> +
> +void
> +objfile_register_static_link (struct objfile *objfile,
> +			      const struct block *block,
> +			      const struct dynamic_prop *static_link)
> +{
> +  void **slot;
> +  struct static_link_htab_entry lookup_entry;
> +  struct static_link_htab_entry *entry;
> +
> +  if (objfile->static_links == NULL)
> +    objfile->static_links = htab_create_alloc
> +      (1, &static_link_htab_entry_hash, static_link_htab_entry_eq, NULL,
> +       xcalloc, xfree);
> +
> +  /* Create a slot for the mapping, make sure it's the first mapping for this
> +     block and then create the mapping itself.  */
> +  lookup_entry.block = block;
> +  slot = htab_find_slot (objfile->static_links, &lookup_entry, INSERT);
> +  gdb_assert (*slot == NULL);
> +
> +  entry = (struct static_link_htab_entry *) obstack_alloc
> +	    (&objfile->objfile_obstack, sizeof (*entry));
> +  entry->block = block;
> +  entry->static_link = static_link;
> +  *slot = (void *) entry;
> +}
> +
> +/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
> +   none was found.  */
> +
> +const struct dynamic_prop *
> +objfile_lookup_static_link (struct objfile *objfile,
> +			    const struct block *block)
> +{
> +  struct static_link_htab_entry *entry;
> +  struct static_link_htab_entry lookup_entry;
> +
> +  if (objfile->static_links == NULL)
> +    return NULL;
> +  lookup_entry.block = block;
> +  entry
> +    = (struct static_link_htab_entry *) htab_find (objfile->static_links,
> +						   &lookup_entry);
> +  if (entry == NULL)
> +    return NULL;
> +
> +  gdb_assert (entry->block == block);
> +  return entry->static_link;
> +}
> +
>  \f
>  
>  /* Called via bfd_map_over_sections to build up the section table that
> @@ -653,6 +739,11 @@ free_objfile (struct objfile *objfile)
>    /* Rebuild section map next time we need it.  */
>    get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
>  
> +  /* Free the map for static links.  There's no need to free static link
> +     themselves since they were allocated on the objstack.  */
> +  if (objfile->static_links != NULL)
> +    htab_delete (objfile->static_links);
> +
>    /* The last thing we do is free the objfile struct itself.  */
>    xfree (objfile);
>  }
> diff --git a/gdb/objfiles.h b/gdb/objfiles.h
> index a0dc69b..653106f 100644
> --- a/gdb/objfiles.h
> +++ b/gdb/objfiles.h
> @@ -20,6 +20,7 @@
>  #if !defined (OBJFILES_H)
>  #define OBJFILES_H
>  
> +#include "hashtab.h"
>  #include "gdb_obstack.h"	/* For obstack internals.  */
>  #include "symfile.h"		/* For struct psymbol_allocation_list.  */
>  #include "progspace.h"
> @@ -412,6 +413,19 @@ struct objfile
>         table, so we have to keep them here to relocate them
>         properly.  */
>      struct symbol *template_symbols;
> +
> +    /* Associate a static link (struct dynamic_prop *) to all blocks (struct
> +       block *) that have one.
> +
> +       In the context of nested functions (available in Pascal, Ada and GNU C,
> +       for instance), a static link (as in DWARF's DW_AT_static_link attribute)
> +       for a function is a way to get the frame corresponding to the enclosing
> +       function.
> +
> +       Very few blocks have a static link, so it's more memory efficient to
> +       store these here rather than in struct block.  Static links must be
> +       allocated on the objfile's obstack.  */
> +    htab_t static_links;
>    };
>  
>  /* Defines for the objfile flag word.  */
> @@ -719,4 +733,12 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
>  extern void set_objfile_main_name (struct objfile *objfile,
>  				   const char *name, enum language lang);
>  
> +extern void objfile_register_static_link
> +  (struct objfile *objfile,
> +   const struct block *block,
> +   const struct dynamic_prop *static_link);
> +
> +extern const struct dynamic_prop *objfile_lookup_static_link
> +  (struct objfile *objfile, const struct block *block);
> +
>  #endif /* !defined (OBJFILES_H) */
> diff --git a/gdb/p-exp.y b/gdb/p-exp.y
> index 191b3d3..c255a57 100644
> --- a/gdb/p-exp.y
> +++ b/gdb/p-exp.y
> @@ -772,10 +772,7 @@ variable:	name_not_typename
>  				}
>  
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
> -			      /* We want to use the selected frame, not
> -				 another more inner frame which happens to
> -				 be in the same block.  */
> -			      write_exp_elt_block (pstate, NULL);
> +			      write_exp_elt_block (pstate, sym.block);
>  			      write_exp_elt_sym (pstate, sym.symbol);
>  			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
>  			      current_type = sym.symbol->type; }
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index f51e25c..553cc71 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
>        struct value *val;
>        struct value_print_options opts;
>  
> -      val = read_var_value (var, frame);
> +      /* READ_VAR_VALUE needs a block in order to deal with non-local
> +	 references (i.e. to handle nested functions).  In this context, we
> +	 print variables that are local to this frame, so we can avoid passing
> +	 a block to it.  */
> +      val = read_var_value (var, NULL, frame);
>        get_user_print_options (&opts);
>        opts.deref_ref = 1;
>        common_val_print (val, stream, indent, &opts, current_language);
> diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
> index e3d4867..345642e 100644
> --- a/gdb/python/py-finishbreakpoint.c
> +++ b/gdb/python/py-finishbreakpoint.c
> @@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>                    /* Ignore Python errors at this stage.  */
>                    self_bpfinish->return_type = type_to_type_object (ret_type);
>                    PyErr_Clear ();
> -                  func_value = read_var_value (function, frame);
> +                  func_value = read_var_value (function, NULL, frame);
>                    self_bpfinish->function_value =
>                        value_to_value_object (func_value);
>                    PyErr_Clear ();
> diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
> index 7290056..1923f64 100644
> --- a/gdb/python/py-frame.c
> +++ b/gdb/python/py-frame.c
> @@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
>    struct frame_info *frame;
>    PyObject *sym_obj, *block_obj = NULL;
>    struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
> +  const struct block *block = NULL;
>    struct value *val = NULL;
>  
>    if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
> @@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
>    else if (gdbpy_is_string (sym_obj))
>      {
>        char *var_name;
> -      const struct block *block = NULL;
>        struct cleanup *cleanup;
>  
>        var_name = python_string_to_target_string (sym_obj);
> @@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
>  
>        TRY
>  	{
> +	  struct block_symbol lookup_sym;
>  	  FRAPY_REQUIRE_VALID (self, frame);
>  
>  	  if (!block)
>  	    block = get_frame_block (frame, NULL);
> -	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
> +	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
> +	  var = lookup_sym.symbol;
> +	  block = lookup_sym.block;
>  	}
>        CATCH (except, RETURN_MASK_ALL)
>  	{
> @@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
>      {
>        FRAPY_REQUIRE_VALID (self, frame);
>  
> -      val = read_var_value (var, frame);
> +      val = read_var_value (var, block, frame);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
> index e3336b1..ac97723 100644
> --- a/gdb/python/py-framefilter.c
> +++ b/gdb/python/py-framefilter.c
> @@ -43,16 +43,17 @@ enum mi_print_types
>     NAME is a  pass-through argument where the name of  the symbol will
>     be written.  NAME is allocated in  this function, but the caller is
>     responsible for clean up.  SYM is a pass-through argument where the
> -   symbol will be written.  In the case of the API returning a string,
> -   this will be set to NULL.  LANGUAGE is also a pass-through argument
> -   denoting the language attributed to the Symbol.  In the case of SYM
> -   being  NULL, this  will be  set to  the current  language.  Returns
> -   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
> -   EXT_LANG_BT_OK on success.  */
> +   symbol will be written and  SYM_BLOCK is a pass-through argument to
> +   write  the block where the symbol lies in.  In the case of the  API
> +   returning a  string,  this will be set to NULL.  LANGUAGE is also a
> +   pass-through  argument  denoting  the  language  attributed  to the
> +   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
> +   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
> +   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
>  
>  static enum ext_lang_bt_status
>  extract_sym (PyObject *obj, char **name, struct symbol **sym,
> -	     const struct language_defn **language)
> +	     struct block **sym_block, const struct language_defn **language)
>  {
>    PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
>  
> @@ -75,12 +76,18 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
>  	python_language.  */
>        *language = python_language;
>        *sym = NULL;
> +      *sym_block = NULL;
>      }
>    else
>      {
>        /* This type checks 'result' during the conversion so we
>  	 just call it unconditionally and check the return.  */
>        *sym = symbol_object_to_symbol (result);
> +      /* TODO: currently, we have no way to recover the block in which SYMBOL
> +	 was found, so we have no block to return.  Trying to evaluate SYMBOL
> +	 will yield an incorrect value when it's located in a FRAME and
> +	 evaluated from another frame (as permitted in nested functions).  */
> +      *sym_block = NULL;
>  
>        Py_DECREF (result);
>  
> @@ -537,10 +544,11 @@ enumerate_args (PyObject *iter,
>        const struct language_defn *language;
>        char *sym_name;
>        struct symbol *sym;
> +      struct block *sym_block;
>        struct value *val;
>        enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
>  
> -      success = extract_sym (item, &sym_name, &sym, &language);
> +      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
>        if (success == EXT_LANG_BT_ERROR)
>  	{
>  	  Py_DECREF (item);
> @@ -736,12 +744,13 @@ enumerate_locals (PyObject *iter,
>        struct value *val;
>        enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
>        struct symbol *sym;
> +      struct block *sym_block;
>        int local_indent = 8 + (8 * indent);
>        struct cleanup *locals_cleanups;
>  
>        locals_cleanups = make_cleanup_py_decref (item);
>  
> -      success = extract_sym (item, &sym_name, &sym, &language);
> +      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
>        if (success == EXT_LANG_BT_ERROR)
>  	{
>  	  do_cleanups (locals_cleanups);
> @@ -769,7 +778,7 @@ enumerate_locals (PyObject *iter,
>  	{
>  	  TRY
>  	    {
> -	      val = read_var_value (sym, frame);
> +	      val = read_var_value (sym, sym_block, frame);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
> index 401e7e9..bbc8b6b 100644
> --- a/gdb/python/py-symbol.c
> +++ b/gdb/python/py-symbol.c
> @@ -278,7 +278,11 @@ sympy_value (PyObject *self, PyObject *args)
>        if (symbol_read_needs_frame (symbol) && frame_info == NULL)
>  	error (_("symbol requires a frame to compute its value"));
>  
> -      value = read_var_value (symbol, frame_info);
> +      /* TODO: currently, we have no way to recover the block in which SYMBOL
> +	 was found, so we have no block to pass to read_var_value.  This will
> +	 yield an incorrect value when symbol is not local to FRAME_INFO (this
> +	 can happen with nested functions).  */
> +      value = read_var_value (symbol, NULL, frame_info);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/stack.c b/gdb/stack.c
> index b4cfdbd..5a18a06 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
>  
>    TRY
>      {
> -      argp->val = read_var_value (sym, frame);
> +      argp->val = read_var_value (sym, NULL, frame);
>      }
>    CATCH (except, RETURN_MASK_ERROR)
>      {
> @@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
>      {
>        TRY
>  	{
> -	  val = read_var_value (sym, frame);
> +	  val = read_var_value (sym, NULL, frame);
>  	}
>        CATCH (except, RETURN_MASK_ERROR)
>  	{
> @@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
>  
>  	  TRY
>  	    {
> -	      val = read_var_value (sym, frame);
> +	      val = read_var_value (sym, NULL, frame);
>  	    }
>  	  CATCH (except, RETURN_MASK_ERROR)
>  	    {
> @@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
>  	value_fetch_lazy (return_value);
>  
>        if (thisfun != NULL)
> -	function = read_var_value (thisfun, thisframe);
> +	function = read_var_value (thisfun, NULL, thisframe);
>  
>        rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
>        if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index 61fc8c5..df781b8 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -665,6 +665,25 @@ 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.  Return 0 on failure (FRAMEFUNC may not hold the
> +     information we need).
> +
> +     This method is designed to work with static links (nested functions
> +     handling).  Static links are function properties whose evaluation returns
> +     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 fuctions, 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.  */
> diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
> new file mode 100644
> index 0000000..967eb2f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp1.c
> @@ -0,0 +1,37 @@
> +/* 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 function 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..9720f5b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp1.exp
> @@ -0,0 +1,55 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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..a6449e34
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp2.c
> @@ -0,0 +1,48 @@
> +/* 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..a107d1c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp2.exp
> @@ -0,0 +1,64 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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..a51f417
> --- /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);
> +
> +extern void process (callback_t cb);
> +extern 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..8f9b522
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/nested-subp3.exp
> @@ -0,0 +1,55 @@
> +# 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/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +#
> +# Test nested functions 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.
> +
> +gdb_test "print first"        "1"
> +gdb_test "print parent_first" "1"
> diff --git a/gdb/valops.c b/gdb/valops.c
> index acaf027..26fdfa6 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -1291,27 +1291,12 @@ value_repeat (struct value *arg1, int count)
>  struct value *
>  value_of_variable (struct symbol *var, const struct block *b)
>  {
> -  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);
> +  return read_var_value (var, b, frame);
>  }
>  
>  struct value *
> @@ -3463,9 +3448,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
>  		return NULL;
>  
>  	      if (want_address)
> -		return value_addr (read_var_value (s, 0));
> +		return value_addr (read_var_value (s, 0, 0));
>  	      else
> -		return read_var_value (s, 0);
> +		return read_var_value (s, 0, 0);
>  	    }
>  
>  	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
> @@ -3493,7 +3478,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
>  	      if (s == NULL)
>  		return NULL;
>  
> -	      v = read_var_value (s, 0);
> +	      v = read_var_value (s, 0, 0);
>  	      if (!want_address)
>  		result = v;
>  	      else
> @@ -3729,7 +3714,7 @@ value_full_object (struct value *argp,
>  struct value *
>  value_of_this (const struct language_defn *lang)
>  {
> -  struct symbol *sym;
> +  struct block_symbol sym;
>    const struct block *b;
>    struct frame_info *frame;
>  
> @@ -3740,12 +3725,12 @@ value_of_this (const struct language_defn *lang)
>  
>    b = get_frame_block (frame, NULL);
>  
> -  sym = lookup_language_this (lang, b).symbol;
> -  if (sym == NULL)
> +  sym = lookup_language_this (lang, b);
> +  if (sym.symbol == NULL)
>      error (_("current stack frame does not contain a variable named `%s'"),
>  	   lang->la_name_of_this);
>  
> -  return read_var_value (sym, frame);
> +  return read_var_value (sym.symbol, sym.block, frame);
>  }
>  
>  /* Return the value of the local variable, if one exists.  Return NULL
> diff --git a/gdb/value.h b/gdb/value.h
> index 82deaf2..0a4bc47 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -674,9 +674,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
>  extern int symbol_read_needs_frame (struct symbol *);
>  
>  extern struct value *read_var_value (struct symbol *var,
> +				     const struct block *var_block,
>  				     struct frame_info *frame);
>  
>  extern struct value *default_read_var_value (struct symbol *var,
> +					     const struct block *var_block,
>  					     struct frame_info *frame);
>  
>  extern struct value *allocate_value (struct type *type);
> diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
> index b5b2a1d..4be7dd2 100644
> --- a/gdb/xcoffread.c
> +++ b/gdb/xcoffread.c
> @@ -1389,7 +1389,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
>  		}
>  
>  	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> -			    newobj->start_addr,
> +			    NULL, newobj->start_addr,
>  			    (fcn_cs_saved.c_value
>  			     + fcn_aux_saved.x_sym.x_misc.x_fsize
>  			     + ANOFFSET (objfile->section_offsets,
> @@ -1480,7 +1480,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
>  	      if (local_symbols && context_stack_depth > 0)
>  		{
>  		  /* Make a block for the local symbols within.  */
> -		  finish_block (newobj->name, &local_symbols, newobj->old_blocks,
> +		  finish_block (newobj->name, &local_symbols,
> +				newobj->old_blocks, NULL,
>  				newobj->start_addr,
>  				(cs->c_value
>  				 + ANOFFSET (objfile->section_offsets,

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-15  5:12                   ` Doug Evans
@ 2015-08-15  6:21                     ` Doug Evans
  2015-08-17 13:27                       ` Pierre-Marie de Rodat
  2015-08-17 13:33                     ` Pierre-Marie de Rodat
  1 sibling, 1 reply; 40+ messages in thread
From: Doug Evans @ 2015-08-15  6:21 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Kevin Buettner, gdb-patches

Doug Evans <xdje42@gmail.com> writes:
> Hi.
> Just a couple of nits.
> Ok with them fixed (not sure what the right fix for the first one is
> though, I could be missing something).
> grep for ^====
>
> Also, I found a 4% performance degradation in a couple of gmonster
> perf tests (e.g., gmonster2-ptype-string.exp).
> Not enough to reject the patch, but it would be interesting
> to find the culprit (assuming it's not a test issue!).

If you want to see if you can see the 4% regression too,
I've updated the wiki with some instructions to get one
using the perf testsuite (hopefully) quickly:

https://sourceware.org/gdb/wiki/GDBPerfTestsuite

You have to be patient with the build, these are big programs.

bash$ sh buildperf.sh

Here are a couple of my results:

Before (trunk):

bash$ sh runperf.sh
bash$ cat perftest.sum
gmonster1:gmonster-pervasive-typedef cpu_time 10-cus 0.007923
gmonster1:gmonster-pervasive-typedef cpu_time 100-cus 0.061346
gmonster1:gmonster-pervasive-typedef cpu_time 1000-cus 0.7087322
gmonster1:gmonster-pervasive-typedef cpu_time 10000-cus 7.6932424
gmonster1:gmonster-pervasive-typedef wall_time 10-cus 0.00795402526855
gmonster1:gmonster-pervasive-typedef wall_time 100-cus 0.061425447464
gmonster1:gmonster-pervasive-typedef wall_time 1000-cus 0.709506464005
gmonster1:gmonster-pervasive-typedef wall_time 10000-cus 7.70150403976
gmonster1:gmonster-pervasive-typedef vmsize 10-cus 110600
gmonster1:gmonster-pervasive-typedef vmsize 100-cus 119276
gmonster1:gmonster-pervasive-typedef vmsize 1000-cus 206218
gmonster1:gmonster-pervasive-typedef vmsize 10000-cus 1079663
gmonster2:gmonster-ptype-string cpu_time 10-sos 0.2961394
gmonster2:gmonster-ptype-string cpu_time 100-sos 1.5917764
gmonster2:gmonster-ptype-string cpu_time 1000-sos 20.6852
gmonster2:gmonster-ptype-string wall_time 10-sos 0.296435832977
gmonster2:gmonster-ptype-string wall_time 100-sos 1.5934440136
gmonster2:gmonster-ptype-string wall_time 1000-sos 20.7090939522
gmonster2:gmonster-ptype-string vmsize 10-sos 283208
gmonster2:gmonster-ptype-string vmsize 100-sos 702776
gmonster2:gmonster-ptype-string vmsize 1000-sos 4908408

After (trunk + patch):

bash$ sh runperf.sh
bash$ cat perftest.sum
gmonster1:gmonster-pervasive-typedef cpu_time 10-cus 0.0077614
gmonster1:gmonster-pervasive-typedef cpu_time 100-cus 0.063923
gmonster1:gmonster-pervasive-typedef cpu_time 1000-cus 0.7615324
gmonster1:gmonster-pervasive-typedef cpu_time 10000-cus 7.898073
gmonster1:gmonster-pervasive-typedef wall_time 10-cus 0.00778799057007
gmonster1:gmonster-pervasive-typedef wall_time 100-cus 0.0640145301819
gmonster1:gmonster-pervasive-typedef wall_time 1000-cus 0.762880802155
gmonster1:gmonster-pervasive-typedef wall_time 10000-cus 7.90763082504
gmonster1:gmonster-pervasive-typedef vmsize 10-cus 108520
gmonster1:gmonster-pervasive-typedef vmsize 100-cus 117200
gmonster1:gmonster-pervasive-typedef vmsize 1000-cus 204180
gmonster1:gmonster-pervasive-typedef vmsize 10000-cus 1077580
gmonster2:gmonster-ptype-string cpu_time 10-sos 0.3188818
gmonster2:gmonster-ptype-string cpu_time 100-sos 1.7196954
gmonster2:gmonster-ptype-string cpu_time 1000-sos 21.5444378
gmonster2:gmonster-ptype-string wall_time 10-sos 0.319199228287
gmonster2:gmonster-ptype-string wall_time 100-sos 1.72196946144
gmonster2:gmonster-ptype-string wall_time 1000-sos 21.5659247875
gmonster2:gmonster-ptype-string vmsize 10-sos 281128
gmonster2:gmonster-ptype-string vmsize 100-sos 700628
gmonster2:gmonster-ptype-string vmsize 1000-sos 4906312

3-4% isn't much, but I wouldn't have expected any slowdown.
I haven't ruled out the problem is elsewhere and not with
the patch, but I have repeated the results a couple of times,
so at least it's consistent. :-)

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-15  6:21                     ` Doug Evans
@ 2015-08-17 13:27                       ` Pierre-Marie de Rodat
  0 siblings, 0 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-17 13:27 UTC (permalink / raw)
  To: Doug Evans; +Cc: Kevin Buettner, gdb-patches

On 08/15/2015 08:20 AM, Doug Evans wrote:
> If you want to see if you can see the 4% regression too,
> I've updated the wiki with some instructions to get one
> using the perf testsuite (hopefully) quickly:
>
> https://sourceware.org/gdb/wiki/GDBPerfTestsuite

Thank you very much for this! :-)

> Before (trunk):
>
> bash$ sh runperf.sh
> bash$ cat perftest.sum
> gmonster1:gmonster-pervasive-typedef cpu_time 10-cus 0.007923
> gmonster1:gmonster-pervasive-typedef cpu_time 100-cus 0.061346
> gmonster1:gmonster-pervasive-typedef cpu_time 1000-cus 0.7087322
> gmonster1:gmonster-pervasive-typedef cpu_time 10000-cus 7.6932424
> gmonster1:gmonster-pervasive-typedef wall_time 10-cus 0.00795402526855
> gmonster1:gmonster-pervasive-typedef wall_time 100-cus 0.061425447464
> gmonster1:gmonster-pervasive-typedef wall_time 1000-cus 0.709506464005
> gmonster1:gmonster-pervasive-typedef wall_time 10000-cus 7.70150403976
> gmonster1:gmonster-pervasive-typedef vmsize 10-cus 110600
> gmonster1:gmonster-pervasive-typedef vmsize 100-cus 119276
> gmonster1:gmonster-pervasive-typedef vmsize 1000-cus 206218
> gmonster1:gmonster-pervasive-typedef vmsize 10000-cus 1079663
> gmonster2:gmonster-ptype-string cpu_time 10-sos 0.2961394
> gmonster2:gmonster-ptype-string cpu_time 100-sos 1.5917764
> gmonster2:gmonster-ptype-string cpu_time 1000-sos 20.6852
> gmonster2:gmonster-ptype-string wall_time 10-sos 0.296435832977
> gmonster2:gmonster-ptype-string wall_time 100-sos 1.5934440136
> gmonster2:gmonster-ptype-string wall_time 1000-sos 20.7090939522
> gmonster2:gmonster-ptype-string vmsize 10-sos 283208
> gmonster2:gmonster-ptype-string vmsize 100-sos 702776
> gmonster2:gmonster-ptype-string vmsize 1000-sos 4908408
>
> After (trunk + patch):
>
> bash$ sh runperf.sh
> bash$ cat perftest.sum
> gmonster1:gmonster-pervasive-typedef cpu_time 10-cus 0.0077614
> gmonster1:gmonster-pervasive-typedef cpu_time 100-cus 0.063923
> gmonster1:gmonster-pervasive-typedef cpu_time 1000-cus 0.7615324
> gmonster1:gmonster-pervasive-typedef cpu_time 10000-cus 7.898073
> gmonster1:gmonster-pervasive-typedef wall_time 10-cus 0.00778799057007
> gmonster1:gmonster-pervasive-typedef wall_time 100-cus 0.0640145301819
> gmonster1:gmonster-pervasive-typedef wall_time 1000-cus 0.762880802155
> gmonster1:gmonster-pervasive-typedef wall_time 10000-cus 7.90763082504
> gmonster1:gmonster-pervasive-typedef vmsize 10-cus 108520
> gmonster1:gmonster-pervasive-typedef vmsize 100-cus 117200
> gmonster1:gmonster-pervasive-typedef vmsize 1000-cus 204180
> gmonster1:gmonster-pervasive-typedef vmsize 10000-cus 1077580
> gmonster2:gmonster-ptype-string cpu_time 10-sos 0.3188818
> gmonster2:gmonster-ptype-string cpu_time 100-sos 1.7196954
> gmonster2:gmonster-ptype-string cpu_time 1000-sos 21.5444378
> gmonster2:gmonster-ptype-string wall_time 10-sos 0.319199228287
> gmonster2:gmonster-ptype-string wall_time 100-sos 1.72196946144
> gmonster2:gmonster-ptype-string wall_time 1000-sos 21.5659247875
> gmonster2:gmonster-ptype-string vmsize 10-sos 281128
> gmonster2:gmonster-ptype-string vmsize 100-sos 700628
> gmonster2:gmonster-ptype-string vmsize 1000-sos 4906312
>
> 3-4% isn't much, but I wouldn't have expected any slowdown.
> I haven't ruled out the problem is elsewhere and not with
> the patch, but I have repeated the results a couple of times,
> so at least it's consistent. :-)

Arg, I cannot reproduce the difference: here are the results on my 
machine (still x86_64-linux) for the same testing:

trunk:
gmonster1:gmonster-pervasive-typedef cpu_time 10-cus 0.0046084
gmonster1:gmonster-pervasive-typedef cpu_time 100-cus 0.0371068
gmonster1:gmonster-pervasive-typedef cpu_time 1000-cus 0.4631964
gmonster1:gmonster-pervasive-typedef cpu_time 10000-cus 5.078225
gmonster1:gmonster-pervasive-typedef wall_time 10-cus 0.00461478233337
gmonster1:gmonster-pervasive-typedef wall_time 100-cus 0.0370876789093
gmonster1:gmonster-pervasive-typedef wall_time 1000-cus 0.462884044647
gmonster1:gmonster-pervasive-typedef wall_time 10000-cus 5.0744289875
gmonster1:gmonster-pervasive-typedef vmsize 10-cus 154345
gmonster1:gmonster-pervasive-typedef vmsize 100-cus 163028
gmonster1:gmonster-pervasive-typedef vmsize 1000-cus 249839
gmonster1:gmonster-pervasive-typedef vmsize 10000-cus 1118777
gmonster2:gmonster-ptype-string cpu_time 10-sos 0.1663808
gmonster2:gmonster-ptype-string cpu_time 100-sos 1.0682334
gmonster2:gmonster-ptype-string cpu_time 1000-sos 15.5775406
gmonster2:gmonster-ptype-string wall_time 10-sos 0.166248464584
gmonster2:gmonster-ptype-string wall_time 100-sos 1.06737132072
gmonster2:gmonster-ptype-string wall_time 1000-sos 15.5648618221
gmonster2:gmonster-ptype-string vmsize 10-sos 278092
gmonster2:gmonster-ptype-string vmsize 100-sos 697980
gmonster2:gmonster-ptype-string vmsize 1000-sos 4902260

trunk + patch:
gmonster1:gmonster-pervasive-typedef cpu_time 10-cus 0.0045336
gmonster1:gmonster-pervasive-typedef cpu_time 100-cus 0.0370356
gmonster1:gmonster-pervasive-typedef cpu_time 1000-cus 0.4546976
gmonster1:gmonster-pervasive-typedef cpu_time 10000-cus 5.0182104
gmonster1:gmonster-pervasive-typedef wall_time 10-cus 0.004541015625
gmonster1:gmonster-pervasive-typedef wall_time 100-cus 0.0370160579681
gmonster1:gmonster-pervasive-typedef wall_time 1000-cus 0.454346561432
gmonster1:gmonster-pervasive-typedef wall_time 10000-cus 5.0142261982
gmonster1:gmonster-pervasive-typedef vmsize 10-cus 154429
gmonster1:gmonster-pervasive-typedef vmsize 100-cus 163112
gmonster1:gmonster-pervasive-typedef vmsize 1000-cus 249923
gmonster1:gmonster-pervasive-typedef vmsize 10000-cus 1118861
gmonster2:gmonster-ptype-string cpu_time 10-sos 0.1646056
gmonster2:gmonster-ptype-string cpu_time 100-sos 1.050177
gmonster2:gmonster-ptype-string cpu_time 1000-sos 15.346854
gmonster2:gmonster-ptype-string wall_time 10-sos 0.16447520256
gmonster2:gmonster-ptype-string wall_time 100-sos 1.04933385849
gmonster2:gmonster-ptype-string wall_time 1000-sos 15.3345376492
gmonster2:gmonster-ptype-string vmsize 10-sos 277932
gmonster2:gmonster-ptype-string vmsize 100-sos 697880
gmonster2:gmonster-ptype-string vmsize 1000-sos 4902008

I re-ran the tests twice, but the only think I get is a really tiny (but 
consistent) performance improvement with the patch… which does not make 
sense! It's concerning as 4% isn't really neglectable and as I would not 
have expected this neither. So I'm not sure what to do at this point.

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-15  5:12                   ` Doug Evans
  2015-08-15  6:21                     ` Doug Evans
@ 2015-08-17 13:33                     ` Pierre-Marie de Rodat
  2015-08-22 17:30                       ` Doug Evans
  2015-09-02 23:50                       ` Joel Brobecker
  1 sibling, 2 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-17 13:33 UTC (permalink / raw)
  To: Doug Evans; +Cc: Kevin Buettner, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1404 bytes --]

Doug,

Once again, thanks for the review!

On 08/15/2015 07:08 AM, Doug Evans wrote:
>> +/* 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)
>
> ====
> It's hard for this reader to figure out why this test is here.
> If the code gets here, when would find_frame_base_location be NULL?
> Seems like we could just assert find_frame_base_location is non-NULL.

Good catch! This is fixed, now, with a comment explaining this.

>> +  /* 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)
>
> ====
> frame == NULL

Done.

> Ok with them fixed (not sure what the right fix for the first one is
> though, I could be missing something).

As said in my previous mail, I'm not sure I want to commit it: I tried 
to investigate this 4% unexpected performance drop, at least to see what 
happens with a profiler but I could not reproduce.

-- 
Pierre-Marie de Rodat

[-- Attachment #2: 0001-DWARF-handle-non-local-references-in-nested-function.patch --]
[-- Type: text/x-diff, Size: 78475 bytes --]

From f8cb12e93bc4b317bf03dd31fc158cc05fc60367 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] DWARF: handle non-local references in nested functions

GDB's current behavior when dealing with non-local references in the
context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
references.

gdb/ChangeLog:

	* ada-lang.c (ada_read_var_value): Add a var_block argument
	and pass it to default_read_var_value.
	* block.c (block_static_link): New accessor.
	* block.h (block_static_link): Declare it.
	* buildsym.c (finish_block_internal): Add a static_link
	argument.  If there is a static link, associate it to the new
	block.
	(finish_block): Add a static link argument and pass it to
	finish_block_internal.
	(end_symtab_get_static_block): Update calls to finish_block and
	to finish_block_internal.
	(end_symtab_with_blockvector): Update call to
	finish_block_internal.
	* buildsym.h: Forward-declare struct dynamic_prop.
	(struct context_stack): Add a static_link field.
	(finish_block): Add a static link argument.
	* c-exp.y: Remove an obsolete comment (evaluation of variables
	already start from the selected frame, and now they climb *up*
	the call stack) and propagate the block information to the
	produced expression.
	* d-exp.y: Likewise.
	* f-exp.y: Likewise.
	* go-exp.y: Likewise.
	* jv-exp.y: Likewise.
	* m2-exp.y: Likewise.
	* p-exp.y: Likewise.
	* coffread.c (coff_symtab_read): Update calls to finish_block.
	* dbxread.c (process_one_symbol): Likewise.
	* xcoffread.c (read_xcoff_symtab): Likewise.
	* compile/compile-c-symbols.c (convert_one_symbol): Promote the
	"sym" parameter to struct block_symbol, update its uses and pass
	its block to calls to read_var_value.
	(convert_symbol_sym): Update the calls to convert_one_symbol.
	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
	call to read_var_value.
	* 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.
	* findvar.c (follow_static_link): New.
	(get_hosting_frame): New.
	(default_read_var_value): Add a var_block argument.  Use
	get_hosting_frame to handle non-local references.
	(read_var_value): Add a var_block argument and pass it to the
	LA_READ_VAR_VALUE method.
	* gdbtypes.c (resolve_dynamic_range): Update calls to
	dwarf2_evaluate_property.
	(resolve_dynamic_type_internal): Likewise.
	* guile/scm-frame.c (gdbscm_frame_read_var): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* guile/scm-symbol.c (gdbscm_symbol_value): Update call to
	read_var_value (TODO).
	* infcmd.c (finish_command_continuation): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* infrun.c (insert_exception_resume_breakpoint): Likewise.
	* language.h (struct language_defn): Add a var_block argument to
	the LA_READ_VAR_VALUE method.
	* objfiles.c (struct static_link_htab_entry): New.
	(static_link_htab_entry_hash): New.
	(static_link_htab_entry_eq): New.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	(free_objfile): Free the STATIC_LINKS hashed map if needed.
	* objfiles.h: Include hashtab.h.
	(struct objfile): Add a static_links field.
	(objfile_register_static_link): New.
	(objfile_lookup_static_link): New.
	* printcmd.c (print_variable_and_value): Update call to
	read_var_value.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
	* python/py-frame.c (frapy_read_var): Update call to
	read_var_value, passing it the block coming from symbol lookup.
	* python/py-framefilter.c (extract_sym): Add a sym_block
	parameter and set the pointed value to NULL (TODO).
	(enumerate_args): Update call to extract_sym.
	(enumerate_locals): Update calls to extract_sym and to
	read_var_value.
	* python/py-symbol.c (sympy_value): Update call to
	read_var_value (TODO).
	* stack.c (read_frame_local): Update call to read_var_value.
	(read_frame_arg): Likewise.
	(return_command): Likewise.
	* symtab.h (struct symbol_block_ops): Add a get_frame_base
	method.
	(struct symbol): Add a block field.
	(SYMBOL_BLOCK): New accessor.
	* valops.c (value_of_variable): Remove frame/block handling and
	pass the block argument to read_var_value, which does this job
	now.
	(value_struct_elt_for_reference): Update calls to
	read_var_value.
	(value_of_this): Pass the block found to read_var_value.
	* value.h (read_var_value): Add a var_block argument.
	(default_read_var_value): Likewise.

gdb/testsuite/ChangeLog:

	* 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                          |   5 +-
 gdb/block.c                             |  15 +++
 gdb/block.h                             |  11 +++
 gdb/buildsym.c                          |  19 ++--
 gdb/buildsym.h                          |  15 ++-
 gdb/c-exp.y                             |   5 +-
 gdb/coffread.c                          |   6 +-
 gdb/compile/compile-c-symbols.c         |  74 +++++++-------
 gdb/compile/compile-loc2c.c             |   2 +-
 gdb/dbxread.c                           |   8 +-
 gdb/dwarf2loc.c                         |  57 +++++++++--
 gdb/dwarf2loc.h                         |  11 ++-
 gdb/dwarf2read.c                        |  18 +++-
 gdb/f-exp.y                             |   5 +-
 gdb/findvar.c                           | 168 +++++++++++++++++++++++++++++++-
 gdb/gdbtypes.c                          |   7 +-
 gdb/go-exp.y                            |   5 +-
 gdb/guile/scm-frame.c                   |   9 +-
 gdb/guile/scm-symbol.c                  |   6 +-
 gdb/infcmd.c                            |   2 +-
 gdb/infrun.c                            |   7 +-
 gdb/jv-exp.y                            |   4 +-
 gdb/language.h                          |  12 ++-
 gdb/m2-exp.y                            |   5 +-
 gdb/objfiles.c                          |  91 +++++++++++++++++
 gdb/objfiles.h                          |  22 +++++
 gdb/p-exp.y                             |   5 +-
 gdb/printcmd.c                          |   6 +-
 gdb/python/py-finishbreakpoint.c        |   2 +-
 gdb/python/py-frame.c                   |   9 +-
 gdb/python/py-framefilter.c             |  29 ++++--
 gdb/python/py-symbol.c                  |   6 +-
 gdb/stack.c                             |   8 +-
 gdb/symtab.h                            |  19 ++++
 gdb/testsuite/gdb.base/nested-subp1.c   |  37 +++++++
 gdb/testsuite/gdb.base/nested-subp1.exp |  55 +++++++++++
 gdb/testsuite/gdb.base/nested-subp2.c   |  48 +++++++++
 gdb/testsuite/gdb.base/nested-subp2.exp |  64 ++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.c   |  66 +++++++++++++
 gdb/testsuite/gdb.base/nested-subp3.exp |  55 +++++++++++
 gdb/valops.c                            |  35 ++-----
 gdb/value.h                             |   2 +
 gdb/xcoffread.c                         |   5 +-
 43 files changed, 885 insertions(+), 155 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 1fa65244..4d7d22e 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13844,7 +13844,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
 /* Implement the "la_read_var_value" language_defn method for Ada.  */
 
 static struct value *
-ada_read_var_value (struct symbol *var, struct frame_info *frame)
+ada_read_var_value (struct symbol *var, const struct block *var_block,
+		    struct frame_info *frame)
 {
   const struct block *frame_block = NULL;
   struct symbol *renaming_sym = NULL;
@@ -13860,7 +13861,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
 
   /* This is a typical case where we expect the default_read_var_value
      function to work.  */
-  return default_read_var_value (var, frame);
+  return default_read_var_value (var, var_block, frame);
 }
 
 const struct language_defn ada_language_defn = {
diff --git a/gdb/block.c b/gdb/block.c
index f7621aa..f4b8e4f 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
   gb->compunit_symtab = cu;
 }
 
+/* See block.h.  */
+
+struct dynamic_prop *
+block_static_link (const struct block *block)
+{
+  struct objfile *objfile = block_objfile (block);
+
+  /* Only objfile-owned blocks that materialize top function scopes can have
+     static links.  */
+  if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
+    return NULL;
+
+  return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
+}
+
 /* Return the compunit of the global block.  */
 
 static struct compunit_symtab *
diff --git a/gdb/block.h b/gdb/block.h
index 3dbcbcb..c15114b 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -179,6 +179,17 @@ extern struct block *allocate_global_block (struct obstack *obstack);
 extern void set_block_compunit_symtab (struct block *,
 				       struct compunit_symtab *);
 
+/* Return a property to evaluate the static link associated to BLOCK.
+
+   In the context of nested functions (available in Pascal, Ada and GNU C, for
+   instance), a static link (as in DWARF's DW_AT_static_link attribute) for a
+   function is a way to get the frame corresponding to the enclosing function.
+
+   Note that only objfile-owned and function-level blocks can have a static
+   link.  Return NULL if there is no such property.  */
+
+extern struct dynamic_prop *block_static_link (const struct block *block);
+
 /* A block iterator.  This structure should be treated as though it
    were opaque; it is only defined here because we want to support
    stack allocation of iterators.  */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 92c42d5..36ec62f 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -331,8 +331,10 @@ 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 pending **listhead,
 		       struct pending_block *old_blocks,
+		       const struct dynamic_prop *static_link,
 		       CORE_ADDR start, CORE_ADDR end,
 		       int is_global, int expandable)
 {
@@ -422,6 +424,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
       BLOCK_FUNCTION (block) = NULL;
     }
 
+  if (static_link != NULL)
+    objfile_register_static_link (objfile, block, static_link);
+
   /* Now "free" the links of the list, and empty the list.  */
 
   for (next = *listhead; next; next = next1)
@@ -519,11 +524,13 @@ 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 pending **listhead,
 	      struct pending_block *old_blocks,
+	      const struct dynamic_prop *static_link,
 	      CORE_ADDR start, CORE_ADDR end)
 {
-  return finish_block_internal (symbol, listhead, old_blocks,
+  return finish_block_internal (symbol, listhead, old_blocks, static_link,
 				start, end, 0, 0);
 }
 
@@ -1229,7 +1236,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, &local_symbols, cstk->old_blocks, NULL,
 		    cstk->start_addr, end_addr);
 
       if (context_stack_depth > 0)
@@ -1301,7 +1308,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, &file_symbols, NULL, NULL,
 				    last_source_start_addr, end_addr,
 				    0, expandable);
     }
@@ -1329,7 +1336,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, &global_symbols, NULL, NULL,
 			 last_source_start_addr, end_addr,
 			 1, expandable);
   blockvector = make_blockvector ();
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 4c0ec15..b1eda8c 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -39,6 +39,8 @@ struct compunit_symtab;
 struct block;
 struct pending_block;
 
+struct dynamic_prop;
+
 #ifndef EXTERN
 #define	EXTERN extern
 #endif
@@ -145,6 +147,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;
@@ -196,9 +203,11 @@ 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 pending **listhead,
+				   struct pending_block *old_blocks,
+				   const struct dynamic_prop *static_link,
+				   CORE_ADDR start,
+				   CORE_ADDR end);
 
 extern void record_block_range (struct block *,
                                 CORE_ADDR start, CORE_ADDR end_inclusive);
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index a8a4caf..351505e 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1072,10 +1072,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 7722cdb..c0f4267 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1144,8 +1144,8 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
 		enter_linenos (fcn_line_ptr, fcn_first_line,
 			       fcn_last_line, objfile);
 
-	      finish_block (newobj->name, &local_symbols,
-			    newobj->old_blocks, newobj->start_addr,
+	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+			    NULL, newobj->start_addr,
 			    fcn_cs_saved.c_value
 			    + fcn_aux_saved.x_sym.x_misc.x_fsize
 			    + ANOFFSET (objfile->section_offsets,
@@ -1188,7 +1188,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, newobj->old_blocks,
+		  finish_block (0, &local_symbols, newobj->old_blocks, NULL,
 				newobj->start_addr, tmpaddr);
 		}
 	      /* Now pop locals of block just finished.  */
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 21ce655..355b063 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -143,26 +143,26 @@ symbol_substitution_name (struct symbol *sym)
 
 static void
 convert_one_symbol (struct compile_c_instance *context,
-		    struct symbol *sym,
+		    struct block_symbol sym,
 		    int is_global,
 		    int is_local)
 {
   gcc_type sym_type;
-  const char *filename = symbol_symtab (sym)->filename;
-  unsigned short line = SYMBOL_LINE (sym);
+  const char *filename = symbol_symtab (sym.symbol)->filename;
+  unsigned short line = SYMBOL_LINE (sym.symbol);
 
-  error_symbol_once (context, sym);
+  error_symbol_once (context, sym.symbol);
 
-  if (SYMBOL_CLASS (sym) == LOC_LABEL)
+  if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
     sym_type = 0;
   else
-    sym_type = convert_type (context, SYMBOL_TYPE (sym));
+    sym_type = convert_type (context, SYMBOL_TYPE (sym.symbol));
 
-  if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
+  if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
     {
       /* Binding a tag, so we don't need to build a decl.  */
       C_CTX (context)->c_ops->tagbind (C_CTX (context),
-				       SYMBOL_NATURAL_NAME (sym),
+				       SYMBOL_NATURAL_NAME (sym.symbol),
 				       sym_type, filename, line);
     }
   else
@@ -172,7 +172,7 @@ convert_one_symbol (struct compile_c_instance *context,
       CORE_ADDR addr = 0;
       char *symbol_name = NULL;
 
-      switch (SYMBOL_CLASS (sym))
+      switch (SYMBOL_CLASS (sym.symbol))
 	{
 	case LOC_TYPEDEF:
 	  kind = GCC_C_SYMBOL_TYPEDEF;
@@ -180,45 +180,46 @@ convert_one_symbol (struct compile_c_instance *context,
 
 	case LOC_LABEL:
 	  kind = GCC_C_SYMBOL_LABEL;
-	  addr = SYMBOL_VALUE_ADDRESS (sym);
+	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
 	  break;
 
 	case LOC_BLOCK:
 	  kind = GCC_C_SYMBOL_FUNCTION;
-	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
-	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
+	  addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+	  if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
 	    addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
 	  break;
 
 	case LOC_CONST:
-	  if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
+	  if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
 	    {
 	      /* Already handled by convert_enum.  */
 	      return;
 	    }
-	  C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
-						  SYMBOL_NATURAL_NAME (sym),
-						  SYMBOL_VALUE (sym),
-						  filename, line);
+	  C_CTX (context)->c_ops->build_constant
+	    (C_CTX (context),
+	     sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+	     SYMBOL_VALUE (sym.symbol),
+	     filename, line);
 	  return;
 
 	case LOC_CONST_BYTES:
 	  error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
-		 SYMBOL_PRINT_NAME (sym));
+		 SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_UNDEF:
 	  internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
-			  SYMBOL_PRINT_NAME (sym));
+			  SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_COMMON_BLOCK:
 	  error (_("Fortran common block is unsupported for compilation "
 		   "evaluaton of symbol \"%s\"."),
-		 SYMBOL_PRINT_NAME (sym));
+		 SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_OPTIMIZED_OUT:
 	  error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		   "as it is optimized out."),
-		 SYMBOL_PRINT_NAME (sym));
+		 SYMBOL_PRINT_NAME (sym.symbol));
 
 	case LOC_COMPUTED:
 	  if (is_local)
@@ -227,7 +228,7 @@ convert_one_symbol (struct compile_c_instance *context,
 	  warning (_("Symbol \"%s\" is thread-local and currently can only "
 		     "be referenced from the current thread in "
 		     "compiled code."),
-		   SYMBOL_PRINT_NAME (sym));
+		   SYMBOL_PRINT_NAME (sym.symbol));
 	  /* FALLTHROUGH */
 	case LOC_UNRESOLVED:
 	  /* 'symbol_name' cannot be used here as that one is used only for
@@ -238,20 +239,20 @@ convert_one_symbol (struct compile_c_instance *context,
 	    struct value *val;
 	    struct frame_info *frame = NULL;
 
-	    if (symbol_read_needs_frame (sym))
+	    if (symbol_read_needs_frame (sym.symbol))
 	      {
 		frame = get_selected_frame (NULL);
 		if (frame == NULL)
 		  error (_("Symbol \"%s\" cannot be used because "
 			   "there is no selected frame"),
-			 SYMBOL_PRINT_NAME (sym));
+			 SYMBOL_PRINT_NAME (sym.symbol));
 	      }
 
-	    val = read_var_value (sym, frame);
+	    val = read_var_value (sym.symbol, sym.block, frame);
 	    if (VALUE_LVAL (val) != lval_memory)
 	      error (_("Symbol \"%s\" cannot be used for compilation "
 		       "evaluation as its address has not been found."),
-		     SYMBOL_PRINT_NAME (sym));
+		     SYMBOL_PRINT_NAME (sym.symbol));
 
 	    kind = GCC_C_SYMBOL_VARIABLE;
 	    addr = value_address (val);
@@ -266,12 +267,12 @@ convert_one_symbol (struct compile_c_instance *context,
 	case LOC_LOCAL:
 	substitution:
 	  kind = GCC_C_SYMBOL_VARIABLE;
-	  symbol_name = symbol_substitution_name (sym);
+	  symbol_name = symbol_substitution_name (sym.symbol);
 	  break;
 
 	case LOC_STATIC:
 	  kind = GCC_C_SYMBOL_VARIABLE;
-	  addr = SYMBOL_VALUE_ADDRESS (sym);
+	  addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
 	  break;
 
 	case LOC_FINAL_VALUE:
@@ -284,12 +285,13 @@ convert_one_symbol (struct compile_c_instance *context,
       if (context->base.scope != COMPILE_I_RAW_SCOPE
 	  || symbol_name == NULL)
 	{
-	  decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
-						     SYMBOL_NATURAL_NAME (sym),
-						     kind,
-						     sym_type,
-						     symbol_name, addr,
-						     filename, line);
+	  decl = C_CTX (context)->c_ops->build_decl
+	    (C_CTX (context),
+	     SYMBOL_NATURAL_NAME (sym.symbol),
+	     kind,
+	     sym_type,
+	     symbol_name, addr,
+	     filename, line);
 
 	  C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
 	}
@@ -338,7 +340,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
 	    fprintf_unfiltered (gdb_stdlog,
 				"gcc_convert_symbol \"%s\": global symbol\n",
 				identifier);
-	  convert_one_symbol (context, global_sym.symbol, 1, 0);
+	  convert_one_symbol (context, global_sym, 1, 0);
 	}
     }
 
@@ -346,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
     fprintf_unfiltered (gdb_stdlog,
 			"gcc_convert_symbol \"%s\": local symbol\n",
 			identifier);
-  convert_one_symbol (context, sym.symbol, 0, is_local_symbol);
+  convert_one_symbol (context, sym, 0, is_local_symbol);
 }
 
 /* Convert a minimal symbol to its gcc form.  CONTEXT is the compiler
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index b201d13..8058cbd 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
 		 "there is no selected frame"),
 	       SYMBOL_PRINT_NAME (sym));
 
-      val = read_var_value (sym, frame);
+      val = read_var_value (sym, NULL, frame);
       if (VALUE_LVAL (val) != lval_memory)
 	error (_("Symbol \"%s\" cannot be used for compilation evaluation "
 		 "as its address has not been found."),
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 1d00432..fdf4e09 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2756,7 +2756,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 
 	  /* Make a block for the local symbols within.  */
 	  block = finish_block (newobj->name, &local_symbols,
-				newobj->old_blocks,
+				newobj->old_blocks, NULL,
 				newobj->start_addr, newobj->start_addr + valu);
 
 	  /* For C++, set the block's scope.  */
@@ -2857,7 +2857,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj->start_addr = valu;
 		}
 	      /* Make a block for the local symbols within.  */
-	      finish_block (0, &local_symbols, newobj->old_blocks,
+	      finish_block (0, &local_symbols, newobj->old_blocks, NULL,
 			    newobj->start_addr, valu);
 	    }
 	}
@@ -3155,8 +3155,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
 		  newobj = pop_context ();
 		  /* Make a block for the local symbols within.  */
 		  block = finish_block (newobj->name, &local_symbols,
-					newobj->old_blocks, newobj->start_addr,
-					valu);
+					newobj->old_blocks, NULL,
+					newobj->start_addr, valu);
 
 		  /* For C++, set the block's scope.  */
 		  if (SYMBOL_LANGUAGE (newobj->name) == language_cplus)
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index d8e432e..efe4357 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -381,12 +381,47 @@ 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)
+{
+  struct gdbarch *gdbarch;
+  struct type *type;
+  struct dwarf2_locexpr_baton *dlbaton;
+  const gdb_byte *start;
+  size_t length;
+  struct value *result;
+
+  /* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
+     Thus, it's supposed to provide the find_frame_base_location method as
+     well.  */
+  gdb_assert (SYMBOL_BLOCK_OPS (framefunc)->find_frame_base_location != NULL);
+
+  gdbarch = get_frame_arch (frame);
+  type = builtin_type (gdbarch)->builtin_data_ptr;
+  dlbaton = SYMBOL_LOCATION_BATON (framefunc);
+
+  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);
+}
+
 /* 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 +441,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 +2432,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 +2454,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 +2498,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 +2532,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 f3630ac..2415656 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -122,12 +122,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 445ad86..60578a2 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1740,6 +1740,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 *);
@@ -11411,6 +11415,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (attr)
     dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
 
+  /* If there is a location for the static link, record it.  */
+  newobj->static_link = NULL;
+  attr = dwarf2_attr (die, DW_AT_static_link, cu);
+  if (attr)
+    {
+      newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
+					sizeof (*newobj->static_link));
+      attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
+    }
+
   cu->list_in_scope = &local_symbols;
 
   if (die->child != NULL)
@@ -11462,7 +11476,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   newobj = pop_context ();
   /* Make a block for the local symbols within.  */
   block = finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-                        lowpc, highpc);
+			newobj->static_link, lowpc, highpc);
 
   /* For C++, set the block's scope.  */
   if ((cu->language == language_cplus
@@ -11547,7 +11561,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (local_symbols != NULL || local_using_directives != NULL)
     {
       struct block *block
-        = finish_block (0, &local_symbols, newobj->old_blocks,
+        = finish_block (0, &local_symbols, newobj->old_blocks, NULL,
 			newobj->start_addr, highpc);
 
       /* Note that recording ranges after traversing children, as we
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 3c486ef..56629dc 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -521,10 +521,7 @@ variable:	name_not_typename
 				    innermost_block = sym.block;
 				}
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			      break;
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 83b4fca..1c077f7 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,11 +410,166 @@ 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);
+
+      /* Stacks can be quite deep: give the user a chance to stop this.  */
+      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 != NULL
+	  && (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
+   functions.
+
+   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, const struct block *var_block,
+		   struct frame_info *frame)
+{
+  const struct block *frame_block = NULL;
+
+  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)
+    {
+      /* Stacks can be quite deep: give the user a chance to stop this.  */
+      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 function
+	 level, the immediate upper lexical block is in an outer function:
+	 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 function 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 == 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"));
+	}
+    }
+
+  return frame;
+}
+
 /* A default implementation for the "la_read_var_value" hook in
    the language vector which should work in most situations.  */
 
 struct value *
-default_read_var_value (struct symbol *var, struct frame_info *frame)
+default_read_var_value (struct symbol *var, const struct block *var_block,
+			struct frame_info *frame)
 {
   struct value *v;
   struct type *type = SYMBOL_TYPE (var);
@@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
   check_typedef (type);
 
   if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
+    gdb_assert (frame != NULL);
+
+  if (frame != NULL)
+    frame = get_hosting_frame (var, var_block, frame);
 
   if (SYMBOL_COMPUTED_OPS (var) != NULL)
     return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
@@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
 /* Calls VAR's language la_read_var_value hook with the given arguments.  */
 
 struct value *
-read_var_value (struct symbol *var, struct frame_info *frame)
+read_var_value (struct symbol *var, const struct block *var_block,
+		struct frame_info *frame)
 {
   const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
 
   gdb_assert (lang != NULL);
   gdb_assert (lang->la_read_var_value != NULL);
 
-  return lang->la_read_var_value (var, frame);
+  return lang->la_read_var_value (var, var_block, frame);
 }
 
 /* Install default attributes for register values.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 125af01..301c6fc 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1885,7 +1885,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;
@@ -1897,7 +1897,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;
@@ -2139,7 +2139,8 @@ resolve_dynamic_type_internal (struct type *type,
 
   /* Resolve data_location attribute.  */
   prop = TYPE_DATA_LOCATION (resolved_type);
-  if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
+  if (prop != NULL
+      && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
     {
       TYPE_DYN_PROP_ADDR (prop) = value;
       TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index c1ddfa9..4e017fe 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -611,10 +611,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 64ac0c0..de77c21 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -855,6 +855,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
   SCM block_scm = SCM_UNDEFINED;
   struct frame_info *frame = NULL;
   struct symbol *var = NULL;
+  const struct block *block = NULL;
   struct value *value = NULL;
 
   f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
@@ -909,9 +910,13 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
 
       TRY
 	{
+	  struct block_symbol lookup_sym;
+
 	  if (block == NULL)
 	    block = get_frame_block (frame, NULL);
-	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  var = lookup_sym.symbol;
+	  block = lookup_sym.block;
 	}
       CATCH (ex, RETURN_MASK_ALL)
 	{
@@ -940,7 +945,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
 
   TRY
     {
-      value = read_var_value (var, frame);
+      value = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 01c9eb1..0970a72 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -550,7 +550,11 @@ gdbscm_symbol_value (SCM self, SCM rest)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("Symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO: currently, we have no way to recover the block in which SYMBOL
+	 was found, so we have no block to pass to read_var_value.  This will
+	 yield an incorrect value when symbol is not local to FRAME_INFO (this
+	 can happen with nested functions).  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 82399a4..393ccb9 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1662,7 +1662,7 @@ finish_command_continuation (void *arg, int err)
 	    {
 	      struct value *func;
 
-	      func = read_var_value (a->function, get_current_frame ());
+	      func = read_var_value (a->function, NULL, get_current_frame ());
 	      TRY
 		{
 		  /* print_return_value can throw an exception in some
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a695f2e..cbacece 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -7198,14 +7198,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
 {
   TRY
     {
-      struct symbol *vsym;
+      struct block_symbol vsym;
       struct value *value;
       CORE_ADDR handler;
       struct breakpoint *bp;
 
-      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
-			    NULL).symbol;
-      value = read_var_value (vsym, frame);
+      vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+      value = read_var_value (vsym.symbol, vsym.block, frame);
       /* If the value was optimized out, revert to the old behavior.  */
       if (! value_optimized_out (value))
 	{
diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
index 4999848..60b7d2e 100644
--- a/gdb/jv-exp.y
+++ b/gdb/jv-exp.y
@@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
 	}
 
       write_exp_elt_opcode (par_state, OP_VAR_VALUE);
-      /* We want to use the selected frame, not another more inner frame
-	 which happens to be in the same block.  */
-      write_exp_elt_block (par_state, NULL);
+      write_exp_elt_block (par_state, sym.block);
       write_exp_elt_sym (par_state, sym.symbol);
       write_exp_elt_opcode (par_state, OP_VAR_VALUE);
       return 1;
diff --git a/gdb/language.h b/gdb/language.h
index 2265afc..8b579a2 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -241,13 +241,19 @@ struct language_defn
     void (*la_value_print) (struct value *, struct ui_file *,
 			    const struct value_print_options *);
 
-    /* Given a symbol VAR, and a stack frame id FRAME, read the value
-       of the variable an return (pointer to a) struct value containing
-       the value.
+    /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
+       stack frame id FRAME, read the value of the variable and return (pointer
+       to a) struct value containing the value.
+
+       VAR_BLOCK is needed if there's a possibility for VAR to be outside
+       FRAME.  This is what happens if FRAME correspond to a nested function
+       and VAR is defined in the outer function.  If callers know that VAR is
+       located in FRAME or is global/static, NULL can be passed as VAR_BLOCK.
 
        Throw an error if the variable cannot be found.  */
 
     struct value *(*la_read_var_value) (struct symbol *var,
+					const struct block *var_block,
 					struct frame_info *frame);
 
     /* PC is possibly an unknown languages trampoline.
diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
index 633c354..360fdea 100644
--- a/gdb/m2-exp.y
+++ b/gdb/m2-exp.y
@@ -637,10 +637,7 @@ variable:	NAME
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			    }
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index c6f9f00..93d8b7d 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -199,6 +199,92 @@ set_objfile_main_name (struct objfile *objfile,
   objfile->per_bfd->language_of_main = lang;
 }
 
+/* Helper structure to map blocks to static link properties in hash tables.  */
+
+struct static_link_htab_entry
+{
+  const struct block *block;
+  const struct dynamic_prop *static_link;
+};
+
+/* Return a hash code for struct static_link_htab_entry *P.  */
+
+static hashval_t
+static_link_htab_entry_hash (const void *p)
+{
+  const struct static_link_htab_entry *e
+    = (const struct static_link_htab_entry *) p;
+
+  return htab_hash_pointer (e->block);
+}
+
+/* Return whether P1 an P2 (pointers to struct static_link_htab_entry) are
+   mappings for the same block.  */
+
+static int
+static_link_htab_entry_eq (const void *p1, const void *p2)
+{
+  const struct static_link_htab_entry *e1
+    = (const struct static_link_htab_entry *) p1;
+  const struct static_link_htab_entry *e2
+    = (const struct static_link_htab_entry *) p2;
+
+  return e1->block == e2->block;
+}
+
+/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
+   Must not be called more than once for each BLOCK.  */
+
+void
+objfile_register_static_link (struct objfile *objfile,
+			      const struct block *block,
+			      const struct dynamic_prop *static_link)
+{
+  void **slot;
+  struct static_link_htab_entry lookup_entry;
+  struct static_link_htab_entry *entry;
+
+  if (objfile->static_links == NULL)
+    objfile->static_links = htab_create_alloc
+      (1, &static_link_htab_entry_hash, static_link_htab_entry_eq, NULL,
+       xcalloc, xfree);
+
+  /* Create a slot for the mapping, make sure it's the first mapping for this
+     block and then create the mapping itself.  */
+  lookup_entry.block = block;
+  slot = htab_find_slot (objfile->static_links, &lookup_entry, INSERT);
+  gdb_assert (*slot == NULL);
+
+  entry = (struct static_link_htab_entry *) obstack_alloc
+	    (&objfile->objfile_obstack, sizeof (*entry));
+  entry->block = block;
+  entry->static_link = static_link;
+  *slot = (void *) entry;
+}
+
+/* Look for a static link for BLOCK, which is part of OBJFILE.  Return NULL if
+   none was found.  */
+
+const struct dynamic_prop *
+objfile_lookup_static_link (struct objfile *objfile,
+			    const struct block *block)
+{
+  struct static_link_htab_entry *entry;
+  struct static_link_htab_entry lookup_entry;
+
+  if (objfile->static_links == NULL)
+    return NULL;
+  lookup_entry.block = block;
+  entry
+    = (struct static_link_htab_entry *) htab_find (objfile->static_links,
+						   &lookup_entry);
+  if (entry == NULL)
+    return NULL;
+
+  gdb_assert (entry->block == block);
+  return entry->static_link;
+}
+
 \f
 
 /* Called via bfd_map_over_sections to build up the section table that
@@ -653,6 +739,11 @@ free_objfile (struct objfile *objfile)
   /* Rebuild section map next time we need it.  */
   get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
 
+  /* Free the map for static links.  There's no need to free static link
+     themselves since they were allocated on the objstack.  */
+  if (objfile->static_links != NULL)
+    htab_delete (objfile->static_links);
+
   /* The last thing we do is free the objfile struct itself.  */
   xfree (objfile);
 }
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index af70715..be2a5ef 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -20,6 +20,7 @@
 #if !defined (OBJFILES_H)
 #define OBJFILES_H
 
+#include "hashtab.h"
 #include "gdb_obstack.h"	/* For obstack internals.  */
 #include "symfile.h"		/* For struct psymbol_allocation_list.  */
 #include "progspace.h"
@@ -428,6 +429,19 @@ struct objfile
      properly.  */
 
   struct symbol *template_symbols;
+
+  /* Associate a static link (struct dynamic_prop *) to all blocks (struct
+     block *) that have one.
+
+     In the context of nested functions (available in Pascal, Ada and GNU C,
+     for instance), a static link (as in DWARF's DW_AT_static_link attribute)
+     for a function is a way to get the frame corresponding to the enclosing
+     function.
+
+     Very few blocks have a static link, so it's more memory efficient to
+     store these here rather than in struct block.  Static links must be
+     allocated on the objfile's obstack.  */
+  htab_t static_links;
 };
 
 /* Defines for the objfile flag word.  */
@@ -735,4 +749,12 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
 extern void set_objfile_main_name (struct objfile *objfile,
 				   const char *name, enum language lang);
 
+extern void objfile_register_static_link
+  (struct objfile *objfile,
+   const struct block *block,
+   const struct dynamic_prop *static_link);
+
+extern const struct dynamic_prop *objfile_lookup_static_link
+  (struct objfile *objfile, const struct block *block);
+
 #endif /* !defined (OBJFILES_H) */
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 191b3d3..c255a57 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -772,10 +772,7 @@ variable:	name_not_typename
 				}
 
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
-			      /* We want to use the selected frame, not
-				 another more inner frame which happens to
-				 be in the same block.  */
-			      write_exp_elt_block (pstate, NULL);
+			      write_exp_elt_block (pstate, sym.block);
 			      write_exp_elt_sym (pstate, sym.symbol);
 			      write_exp_elt_opcode (pstate, OP_VAR_VALUE);
 			      current_type = sym.symbol->type; }
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f51e25c..553cc71 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
       struct value *val;
       struct value_print_options opts;
 
-      val = read_var_value (var, frame);
+      /* READ_VAR_VALUE needs a block in order to deal with non-local
+	 references (i.e. to handle nested functions).  In this context, we
+	 print variables that are local to this frame, so we can avoid passing
+	 a block to it.  */
+      val = read_var_value (var, NULL, frame);
       get_user_print_options (&opts);
       opts.deref_ref = 1;
       common_val_print (val, stream, indent, &opts, current_language);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index e543bb3..351f68c 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  func_value = read_var_value (function, frame);
+                  func_value = read_var_value (function, NULL, frame);
                   self_bpfinish->function_value =
                       value_to_value_object (func_value);
                   PyErr_Clear ();
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 7e5dd17..b448686 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
   struct frame_info *frame;
   PyObject *sym_obj, *block_obj = NULL;
   struct symbol *var = NULL;	/* gcc-4.3.2 false warning.  */
+  const struct block *block = NULL;
   struct value *val = NULL;
 
   if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
@@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
   else if (gdbpy_is_string (sym_obj))
     {
       char *var_name;
-      const struct block *block = NULL;
       struct cleanup *cleanup;
 
       var_name = python_string_to_target_string (sym_obj);
@@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
 
       TRY
 	{
+	  struct block_symbol lookup_sym;
 	  FRAPY_REQUIRE_VALID (self, frame);
 
 	  if (!block)
 	    block = get_frame_block (frame, NULL);
-	  var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+	  lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+	  var = lookup_sym.symbol;
+	  block = lookup_sym.block;
 	}
       CATCH (except, RETURN_MASK_ALL)
 	{
@@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
     {
       FRAPY_REQUIRE_VALID (self, frame);
 
-      val = read_var_value (var, frame);
+      val = read_var_value (var, block, frame);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index e3336b1..ac97723 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -43,16 +43,17 @@ enum mi_print_types
    NAME is a  pass-through argument where the name of  the symbol will
    be written.  NAME is allocated in  this function, but the caller is
    responsible for clean up.  SYM is a pass-through argument where the
-   symbol will be written.  In the case of the API returning a string,
-   this will be set to NULL.  LANGUAGE is also a pass-through argument
-   denoting the language attributed to the Symbol.  In the case of SYM
-   being  NULL, this  will be  set to  the current  language.  Returns
-   EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
-   EXT_LANG_BT_OK on success.  */
+   symbol will be written and  SYM_BLOCK is a pass-through argument to
+   write  the block where the symbol lies in.  In the case of the  API
+   returning a  string,  this will be set to NULL.  LANGUAGE is also a
+   pass-through  argument  denoting  the  language  attributed  to the
+   Symbol.  In the case of SYM being  NULL, this  will be  set to  the
+   current  language.  Returns  EXT_LANG_BT_ERROR  on  error  with the
+   appropriate Python exception set, and EXT_LANG_BT_OK on success.  */
 
 static enum ext_lang_bt_status
 extract_sym (PyObject *obj, char **name, struct symbol **sym,
-	     const struct language_defn **language)
+	     struct block **sym_block, const struct language_defn **language)
 {
   PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
 
@@ -75,12 +76,18 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
 	python_language.  */
       *language = python_language;
       *sym = NULL;
+      *sym_block = NULL;
     }
   else
     {
       /* This type checks 'result' during the conversion so we
 	 just call it unconditionally and check the return.  */
       *sym = symbol_object_to_symbol (result);
+      /* TODO: currently, we have no way to recover the block in which SYMBOL
+	 was found, so we have no block to return.  Trying to evaluate SYMBOL
+	 will yield an incorrect value when it's located in a FRAME and
+	 evaluated from another frame (as permitted in nested functions).  */
+      *sym_block = NULL;
 
       Py_DECREF (result);
 
@@ -537,10 +544,11 @@ enumerate_args (PyObject *iter,
       const struct language_defn *language;
       char *sym_name;
       struct symbol *sym;
+      struct block *sym_block;
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  Py_DECREF (item);
@@ -736,12 +744,13 @@ enumerate_locals (PyObject *iter,
       struct value *val;
       enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
       struct symbol *sym;
+      struct block *sym_block;
       int local_indent = 8 + (8 * indent);
       struct cleanup *locals_cleanups;
 
       locals_cleanups = make_cleanup_py_decref (item);
 
-      success = extract_sym (item, &sym_name, &sym, &language);
+      success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
       if (success == EXT_LANG_BT_ERROR)
 	{
 	  do_cleanups (locals_cleanups);
@@ -769,7 +778,7 @@ enumerate_locals (PyObject *iter,
 	{
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, sym_block, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index f6466bd..3d2fa91 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -278,7 +278,11 @@ sympy_value (PyObject *self, PyObject *args)
       if (symbol_read_needs_frame (symbol) && frame_info == NULL)
 	error (_("symbol requires a frame to compute its value"));
 
-      value = read_var_value (symbol, frame_info);
+      /* TODO: currently, we have no way to recover the block in which SYMBOL
+	 was found, so we have no block to pass to read_var_value.  This will
+	 yield an incorrect value when symbol is not local to FRAME_INFO (this
+	 can happen with nested functions).  */
+      value = read_var_value (symbol, NULL, frame_info);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/stack.c b/gdb/stack.c
index ae53ec8..6d87f6f 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
 
   TRY
     {
-      argp->val = read_var_value (sym, frame);
+      argp->val = read_var_value (sym, NULL, frame);
     }
   CATCH (except, RETURN_MASK_ERROR)
     {
@@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
     {
       TRY
 	{
-	  val = read_var_value (sym, frame);
+	  val = read_var_value (sym, NULL, frame);
 	}
       CATCH (except, RETURN_MASK_ERROR)
 	{
@@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
 
 	  TRY
 	    {
-	      val = read_var_value (sym, frame);
+	      val = read_var_value (sym, NULL, frame);
 	    }
 	  CATCH (except, RETURN_MASK_ERROR)
 	    {
@@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
 	value_fetch_lazy (return_value);
 
       if (thisfun != NULL)
-	function = read_var_value (thisfun, thisframe);
+	function = read_var_value (thisfun, NULL, thisframe);
 
       rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
       if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index e67151f..c6f26e7 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -686,6 +686,25 @@ 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.  Return 0 on failure (FRAMEFUNC may not hold the
+     information we need).
+
+     This method is designed to work with static links (nested functions
+     handling).  Static links are function properties whose evaluation returns
+     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 fuctions, 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.  */
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..967eb2f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.c
@@ -0,0 +1,37 @@
+/* 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 function 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..9720f5b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a6449e34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.c
@@ -0,0 +1,48 @@
+/* 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..a107d1c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.exp
@@ -0,0 +1,64 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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..a51f417
--- /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);
+
+extern void process (callback_t cb);
+extern 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..8f9b522
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.exp
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions 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.
+
+gdb_test "print first"        "1"
+gdb_test "print parent_first" "1"
diff --git a/gdb/valops.c b/gdb/valops.c
index acaf027..26fdfa6 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1291,27 +1291,12 @@ value_repeat (struct value *arg1, int count)
 struct value *
 value_of_variable (struct symbol *var, const struct block *b)
 {
-  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);
+  return read_var_value (var, b, frame);
 }
 
 struct value *
@@ -3463,9 +3448,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 		return NULL;
 
 	      if (want_address)
-		return value_addr (read_var_value (s, 0));
+		return value_addr (read_var_value (s, 0, 0));
 	      else
-		return read_var_value (s, 0);
+		return read_var_value (s, 0, 0);
 	    }
 
 	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -3493,7 +3478,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 	      if (s == NULL)
 		return NULL;
 
-	      v = read_var_value (s, 0);
+	      v = read_var_value (s, 0, 0);
 	      if (!want_address)
 		result = v;
 	      else
@@ -3729,7 +3714,7 @@ value_full_object (struct value *argp,
 struct value *
 value_of_this (const struct language_defn *lang)
 {
-  struct symbol *sym;
+  struct block_symbol sym;
   const struct block *b;
   struct frame_info *frame;
 
@@ -3740,12 +3725,12 @@ value_of_this (const struct language_defn *lang)
 
   b = get_frame_block (frame, NULL);
 
-  sym = lookup_language_this (lang, b).symbol;
-  if (sym == NULL)
+  sym = lookup_language_this (lang, b);
+  if (sym.symbol == NULL)
     error (_("current stack frame does not contain a variable named `%s'"),
 	   lang->la_name_of_this);
 
-  return read_var_value (sym, frame);
+  return read_var_value (sym.symbol, sym.block, frame);
 }
 
 /* Return the value of the local variable, if one exists.  Return NULL
diff --git a/gdb/value.h b/gdb/value.h
index 82deaf2..0a4bc47 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -674,9 +674,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
 extern int symbol_read_needs_frame (struct symbol *);
 
 extern struct value *read_var_value (struct symbol *var,
+				     const struct block *var_block,
 				     struct frame_info *frame);
 
 extern struct value *default_read_var_value (struct symbol *var,
+					     const struct block *var_block,
 					     struct frame_info *frame);
 
 extern struct value *allocate_value (struct type *type);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 2edf8bd..7a0f074 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1389,7 +1389,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 		}
 
 	      finish_block (newobj->name, &local_symbols, newobj->old_blocks,
-			    newobj->start_addr,
+			    NULL, newobj->start_addr,
 			    (fcn_cs_saved.c_value
 			     + fcn_aux_saved.x_sym.x_misc.x_fsize
 			     + ANOFFSET (objfile->section_offsets,
@@ -1480,7 +1480,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
 	      if (local_symbols && context_stack_depth > 0)
 		{
 		  /* Make a block for the local symbols within.  */
-		  finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+		  finish_block (newobj->name, &local_symbols,
+				newobj->old_blocks, NULL,
 				newobj->start_addr,
 				(cs->c_value
 				 + ANOFFSET (objfile->section_offsets,
-- 
2.4.6


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-17 13:33                     ` Pierre-Marie de Rodat
@ 2015-08-22 17:30                       ` Doug Evans
  2015-08-25 12:14                         ` Pierre-Marie de Rodat
  2015-09-02 23:50                       ` Joel Brobecker
  1 sibling, 1 reply; 40+ messages in thread
From: Doug Evans @ 2015-08-22 17:30 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Kevin Buettner, gdb-patches

Pierre-Marie de Rodat <derodat@adacore.com> writes:
> Doug,
>
> Once again, thanks for the review!
>
> On 08/15/2015 07:08 AM, Doug Evans wrote:
>>> +/* 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)
>>
>> ====
>> It's hard for this reader to figure out why this test is here.
>> If the code gets here, when would find_frame_base_location be NULL?
>> Seems like we could just assert find_frame_base_location is non-NULL.
>
> Good catch! This is fixed, now, with a comment explaining this.
>
>>> +  /* 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)
>>
>> ====
>> frame == NULL
>
> Done.
>
>> Ok with them fixed (not sure what the right fix for the first one is
>> though, I could be missing something).
>
> As said in my previous mail, I'm not sure I want to commit it: I tried
> to investigate this 4% unexpected performance drop, at least to see
> what happens with a profiler but I could not reproduce.

I'd say let's go ahead.
It's certainly possible I'm seeing the difference due to local
artifacts. I've tried to rule them out, but TBH I haven't put a whole
lot of time into it (beyond trying twice in two different trees).
If someone else isn't seeing them then that's good data.
I'll play with this a bit more, if it's a local issue
it'd be good to find out what it is. :-)

> Pierre-Marie de Rodat
>
> From f8cb12e93bc4b317bf03dd31fc158cc05fc60367 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] DWARF: handle non-local references in nested functions
>
> GDB's current behavior when dealing with non-local references in the
> context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
> references.
>
> gdb/ChangeLog:
>
> 	* ada-lang.c (ada_read_var_value): Add a var_block argument
> 	and pass it to default_read_var_value.
> 	* block.c (block_static_link): New accessor.
> 	* block.h (block_static_link): Declare it.
> 	* buildsym.c (finish_block_internal): Add a static_link
> 	argument.  If there is a static link, associate it to the new
> 	block.
> 	(finish_block): Add a static link argument and pass it to
> 	finish_block_internal.
> 	(end_symtab_get_static_block): Update calls to finish_block and
> 	to finish_block_internal.
> 	(end_symtab_with_blockvector): Update call to
> 	finish_block_internal.
> 	* buildsym.h: Forward-declare struct dynamic_prop.
> 	(struct context_stack): Add a static_link field.
> 	(finish_block): Add a static link argument.
> 	* c-exp.y: Remove an obsolete comment (evaluation of variables
> 	already start from the selected frame, and now they climb *up*
> 	the call stack) and propagate the block information to the
> 	produced expression.
> 	* d-exp.y: Likewise.
> 	* f-exp.y: Likewise.
> 	* go-exp.y: Likewise.
> 	* jv-exp.y: Likewise.
> 	* m2-exp.y: Likewise.
> 	* p-exp.y: Likewise.
> 	* coffread.c (coff_symtab_read): Update calls to finish_block.
> 	* dbxread.c (process_one_symbol): Likewise.
> 	* xcoffread.c (read_xcoff_symtab): Likewise.
> 	* compile/compile-c-symbols.c (convert_one_symbol): Promote the
> 	"sym" parameter to struct block_symbol, update its uses and pass
> 	its block to calls to read_var_value.
> 	(convert_symbol_sym): Update the calls to convert_one_symbol.
> 	* compile/compile-loc2c.c (do_compile_dwarf_expr_to_c): Update
> 	call to read_var_value.
> 	* 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.
> 	* findvar.c (follow_static_link): New.
> 	(get_hosting_frame): New.
> 	(default_read_var_value): Add a var_block argument.  Use
> 	get_hosting_frame to handle non-local references.
> 	(read_var_value): Add a var_block argument and pass it to the
> 	LA_READ_VAR_VALUE method.
> 	* gdbtypes.c (resolve_dynamic_range): Update calls to
> 	dwarf2_evaluate_property.
> 	(resolve_dynamic_type_internal): Likewise.
> 	* guile/scm-frame.c (gdbscm_frame_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* guile/scm-symbol.c (gdbscm_symbol_value): Update call to
> 	read_var_value (TODO).
> 	* infcmd.c (finish_command_continuation): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* infrun.c (insert_exception_resume_breakpoint): Likewise.
> 	* language.h (struct language_defn): Add a var_block argument to
> 	the LA_READ_VAR_VALUE method.
> 	* objfiles.c (struct static_link_htab_entry): New.
> 	(static_link_htab_entry_hash): New.
> 	(static_link_htab_entry_eq): New.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	(free_objfile): Free the STATIC_LINKS hashed map if needed.
> 	* objfiles.h: Include hashtab.h.
> 	(struct objfile): Add a static_links field.
> 	(objfile_register_static_link): New.
> 	(objfile_lookup_static_link): New.
> 	* printcmd.c (print_variable_and_value): Update call to
> 	read_var_value.
> 	* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
> 	* python/py-frame.c (frapy_read_var): Update call to
> 	read_var_value, passing it the block coming from symbol lookup.
> 	* python/py-framefilter.c (extract_sym): Add a sym_block
> 	parameter and set the pointed value to NULL (TODO).
> 	(enumerate_args): Update call to extract_sym.
> 	(enumerate_locals): Update calls to extract_sym and to
> 	read_var_value.
> 	* python/py-symbol.c (sympy_value): Update call to
> 	read_var_value (TODO).
> 	* stack.c (read_frame_local): Update call to read_var_value.
> 	(read_frame_arg): Likewise.
> 	(return_command): Likewise.
> 	* symtab.h (struct symbol_block_ops): Add a get_frame_base
> 	method.
> 	(struct symbol): Add a block field.
> 	(SYMBOL_BLOCK): New accessor.
> 	* valops.c (value_of_variable): Remove frame/block handling and
> 	pass the block argument to read_var_value, which does this job
> 	now.
> 	(value_struct_elt_for_reference): Update calls to
> 	read_var_value.
> 	(value_of_this): Pass the block found to read_var_value.
> 	* value.h (read_var_value): Add a var_block argument.
> 	(default_read_var_value): Likewise.
>
> gdb/testsuite/ChangeLog:
>
> 	* 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.

LGTM.
Thanks for the patch!

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-22 17:30                       ` Doug Evans
@ 2015-08-25 12:14                         ` Pierre-Marie de Rodat
  0 siblings, 0 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-08-25 12:14 UTC (permalink / raw)
  To: Doug Evans; +Cc: Kevin Buettner, gdb-patches

On 08/22/2015 01:28 PM, Doug Evans wrote:
> I'd say let's go ahead.
> It's certainly possible I'm seeing the difference due to local
> artifacts. I've tried to rule them out, but TBH I haven't put a whole
> lot of time into it (beyond trying twice in two different trees).
> If someone else isn't seeing them then that's good data.
> I'll play with this a bit more, if it's a local issue
> it'd be good to find out what it is. :-)

Understood. As I said, I'm completely willing to investigate this, but I 
cannot do anything as long as I don't reproduce. ;-)

> LGTM.
> Thanks for the patch!

I just rebased it on master, checked that it builds and regtested it 
another time on x86_64-linux, just to be sure. It's pushed, now. Thank 
you for the review effort!

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-08-17 13:33                     ` Pierre-Marie de Rodat
  2015-08-22 17:30                       ` Doug Evans
@ 2015-09-02 23:50                       ` Joel Brobecker
  2015-09-03  7:31                         ` Pierre-Marie de Rodat
  2015-09-16 16:16                         ` Doug Evans
  1 sibling, 2 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-09-02 23:50 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Doug Evans, Kevin Buettner, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 2517 bytes --]

Hi Pierre-Marie,

> >From f8cb12e93bc4b317bf03dd31fc158cc05fc60367 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] DWARF: handle non-local references in nested functions
> 
> GDB's current behavior when dealing with non-local references in the
> context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
> references.
> 
> gdb/ChangeLog:
> 
> 	* ada-lang.c (ada_read_var_value): Add a var_block argument
> 	and pass it to default_read_var_value.
> 	* block.c (block_static_link): New accessor.
> 	* block.h (block_static_link): Declare it.
> 	* buildsym.c (finish_block_internal): Add a static_link
>       [...]

This patch is causing a crash on some platforms, as explained by
the revision log of the attached patch.

gdb/ChangeLog:

        * dwarf2loc.c (locexpr_get_frame_base): Renames
        block_op_get_frame_base.
        (dwarf2_block_frame_base_locexpr_funcs): Replace reference to
        block_op_get_frame_base by reference to locexpr_get_frame_base.
        (loclist_get_frame_base): New function, near identical copy of
        locexpr_get_frame_base.
        (dwarf2_block_frame_base_loclist_funcs): Replace reference to
        block_op_get_frame_base by reference to loclist_get_frame_base.

Tested on x86_64-darwin (AdaCore testsuite), and x86_64-linux
(official testsuite).

As also mentioned in the revision log of the patch, we can probably
do some refactoring, or perhaps a different API in the vector that
just extracts the needed data (per_cu, at the moment) from symbol's
SYMBOL_LOCATION_BATON. Then, instead of calling the method to get
the function frame_base, you have a function that gets it by using
that different symbol_block_ops function.

But, I'd suggest fixing the issue the obvious way first, and doing
the cleanup that as a follow up. I wanted to help with the cleanup,
but I am not going to be available for a while, so here goes...

Thanks!
-- 
Joel

[-- Attachment #2: 0001-crash-printing-non-local-variable-from-nested-subpro.patch --]
[-- Type: text/x-diff, Size: 7790 bytes --]

From 684ce5200125d14c5a31fe28b251966ced472b19 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Tue, 1 Sep 2015 22:20:32 +0200
Subject: [PATCH] crash printing non-local variable from nested subprogram

We have noticed that GDB would sometimes crash trying to print
from a nested function the value of a variable declared in an
enclosing scope. This appears to be target dependent, although
that correlation might only be fortuitious.  We noticed the issue
on x86_64-darwin, x86-vxworks6 and x86-solaris.  The investigation
was done on Darwin.

This is a new feature that was introduced by:

    commit 63e43d3aedb8b1112899c2d0ad74cbbee687e5d6
    Date:   Thu Feb 5 17:00:06 2015 +0100
    DWARF: handle non-local references in nested functions

We can reproduce the problem with one of the testcases that was
added with the patch (gdb.base/nested-subp1.exp), where we have...

    18 int
    19 foo (int i1)
    20 {
    21   int
    22   nested (int i2)
    23   {
    [...]
    27     return i1 * i2; /* STOP */
    28   }

...  After building the example program, and running until line 27,
try printing the value of "i1":

    % gdb gdb.base/nested-subp1
    (gdb) break foo.c:27
    (gdb) run
    Breakpoint 1, nested (i2=2) at /[...]/nested-subp1.c:27
    27          return i1 * i2; /* STOP */
    (gdb) p i1
    [1]    73090 segmentation fault  ../gdb -q gdb.base/nested-subp1

Ooops!

What happens is that, because the reference is non-local, we are trying
to follow the function's static link, which does...

    /* 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 != NULL
        && (SYMBOL_BLOCK_OPS (framefunc)->get_frame_base (framefunc, frame)
            == upper_frame_base))

... or, in other words, calls the get_frame_base "method" of
framefunc's struct symbol_block_ops data. This resolves to
the block_op_get_frame_base function.

Looking at the function's implementation, we see:

  struct dwarf2_locexpr_baton *dlbaton;
  [...]
  dlbaton = SYMBOL_LOCATION_BATON (framefunc);
  [...]
  result = dwarf2_evaluate_loc_desc (type, frame, start, length,
                                     dlbaton->per_cu);
                                     ^^^^^^^^^^^^^^^

Printing dlbaton->per_cu gives a value that seems fairly bogus for
a memory address (0x60). Because of it, dwarf2_evaluate_loc_desc
then crashes trying to dereference it.

What's different on Darwin compared to Linux is that the function's
frame base is encoded using the following form:

        .byte   0x40    # uleb128 0x40; (DW_AT_frame_base)
        .byte   0x6     # uleb128 0x6; (DW_FORM_data4)

... and so dwarf2_symbol_mark_computed ends up creating
a SYMBOL_LOCATION_BATON as a struct dwarf2_loclist_baton:

  if (attr_form_is_section_offset (attr)
      /* .debug_loc{,.dwo} may not exist at all, or the offset may be outside
         the section.  If so, fall through to the complaint in the
         other branch.  */
      && DW_UNSND (attr) < dwarf2_section_size (objfile, section))
    {
      struct dwarf2_loclist_baton *baton;
      [...]
      SYMBOL_LOCATION_BATON (sym) = baton;

However, if you look more closely at block_op_get_frame_base's
implementation, you'll notice that the function extracts the
symbol's SYMBOL_LOCATION_BATON as a dwarf2_locexpr_baton
(a DWARF _expression_ rather than a _location list_).
That's why we end up decoding the DLBATON improperly, and thus
pass a random dlbaton->per_cu when calling dwarf2_evaluate_loc_desc.

This works on x86_64-linux, because we indeed have the frame base
described using a different form:

        .uleb128 0x40   # (DW_AT_frame_base)
        .uleb128 0x18   # (DW_FORM_exprloc)

This patch fixes the issue by doing what we do for most (if not all)
other such methods: providing one implementation each for loc-list,
and loc-expr. Both implementations are nearly identical, so perhaps
we might later want to improve this. But this patch first tries to
fix the crash first, leaving the design issue for later.

gdb/ChangeLog:

        * dwarf2loc.c (locexpr_get_frame_base): Renames
        block_op_get_frame_base.
        (dwarf2_block_frame_base_locexpr_funcs): Replace reference to
        block_op_get_frame_base by reference to locexpr_get_frame_base.
        (loclist_get_frame_base): New function, near identical copy of
        locexpr_get_frame_base.
        (dwarf2_block_frame_base_loclist_funcs): Replace reference to
        block_op_get_frame_base by reference to loclist_get_frame_base.

Tested on x86_64-darwin (AdaCore testsuite), and x86_64-linux
(official testsuite).
---
 gdb/dwarf2loc.c | 44 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 40 insertions(+), 4 deletions(-)

diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 91cb99a..dd8dd0b 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -381,10 +381,11 @@ locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
   *start = symbaton->data;
 }
 
-/* Implement the struct symbol_block_ops::get_frame_base method.  */
+/* Implement the struct symbol_block_ops::get_frame_base method for
+   LOC_BLOCK functions using a DWARF expression as its DW_AT_frame_base.  */
 
 static CORE_ADDR
-block_op_get_frame_base (struct symbol *framefunc, struct frame_info *frame)
+locexpr_get_frame_base (struct symbol *framefunc, struct frame_info *frame)
 {
   struct gdbarch *gdbarch;
   struct type *type;
@@ -421,7 +422,7 @@ block_op_get_frame_base (struct symbol *framefunc, struct frame_info *frame)
 const struct symbol_block_ops dwarf2_block_frame_base_locexpr_funcs =
 {
   locexpr_find_frame_base_location,
-  block_op_get_frame_base
+  locexpr_get_frame_base
 };
 
 /* Implement find_frame_base_location method for LOC_BLOCK functions using
@@ -436,13 +437,48 @@ loclist_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
   *start = dwarf2_find_location_expression (symbaton, length, pc);
 }
 
+/* Implement the struct symbol_block_ops::get_frame_base method for
+   LOC_BLOCK functions using a DWARF location list as its DW_AT_frame_base.  */
+
+static CORE_ADDR
+loclist_get_frame_base (struct symbol *framefunc, struct frame_info *frame)
+{
+  struct gdbarch *gdbarch;
+  struct type *type;
+  struct dwarf2_loclist_baton *dlbaton;
+  const gdb_byte *start;
+  size_t length;
+  struct value *result;
+
+  /* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
+     Thus, it's supposed to provide the find_frame_base_location method as
+     well.  */
+  gdb_assert (SYMBOL_BLOCK_OPS (framefunc)->find_frame_base_location != NULL);
+
+  gdbarch = get_frame_arch (frame);
+  type = builtin_type (gdbarch)->builtin_data_ptr;
+  dlbaton = SYMBOL_LOCATION_BATON (framefunc);
+
+  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);
+}
+
 /* Vector for inferior functions as represented by LOC_BLOCK, if the inferior
    function uses DWARF location list for its DW_AT_frame_base.  */
 
 const struct symbol_block_ops dwarf2_block_frame_base_loclist_funcs =
 {
   loclist_find_frame_base_location,
-  block_op_get_frame_base
+  loclist_get_frame_base
 };
 
 /* See dwarf2loc.h.  */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-09-02 23:50                       ` Joel Brobecker
@ 2015-09-03  7:31                         ` Pierre-Marie de Rodat
  2015-09-03 12:40                           ` Joel Brobecker
  2015-09-16 16:16                         ` Doug Evans
  1 sibling, 1 reply; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-09-03  7:31 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Doug Evans, Kevin Buettner, gdb-patches

Joel,

On 09/03/2015 01:49 AM, Joel Brobecker wrote:
> This patch is causing a crash on some platforms, as explained by
> the revision log of the attached patch.
>
> gdb/ChangeLog:
> [...]

Thank you very much for the investigation and the fix!

> As also mentioned in the revision log of the patch, we can probably
> do some refactoring, or perhaps a different API in the vector that
> just extracts the needed data (per_cu, at the moment) from symbol's
> SYMBOL_LOCATION_BATON. Then, instead of calling the method to get
> the function frame_base, you have a function that gets it by using
> that different symbol_block_ops function.

I will give it a try and submit a patch but indeed, let's first do fix 
the crash first.

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-09-03  7:31                         ` Pierre-Marie de Rodat
@ 2015-09-03 12:40                           ` Joel Brobecker
  2015-09-03 14:03                             ` Pierre-Marie de Rodat
  0 siblings, 1 reply; 40+ messages in thread
From: Joel Brobecker @ 2015-09-03 12:40 UTC (permalink / raw)
  To: Pierre-Marie de Rodat; +Cc: Doug Evans, Kevin Buettner, gdb-patches

> Thank you very much for the investigation and the fix!

You are welcome.
> 
> >As also mentioned in the revision log of the patch, we can probably
> >do some refactoring, or perhaps a different API in the vector that
> >just extracts the needed data (per_cu, at the moment) from symbol's
> >SYMBOL_LOCATION_BATON. Then, instead of calling the method to get
> >the function frame_base, you have a function that gets it by using
> >that different symbol_block_ops function.
> 
> I will give it a try and submit a patch but indeed, let's first do fix the
> crash first.

Doug will probably be the person reviewing the change. If it gets
approved while I am away, would you mind pushing it for me?

Thanks!
-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-09-03 12:40                           ` Joel Brobecker
@ 2015-09-03 14:03                             ` Pierre-Marie de Rodat
  0 siblings, 0 replies; 40+ messages in thread
From: Pierre-Marie de Rodat @ 2015-09-03 14:03 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Doug Evans, Kevin Buettner, gdb-patches

On 09/03/2015 02:40 PM, Joel Brobecker wrote:
> Doug will probably be the person reviewing the change. If it gets
> approved while I am away, would you mind pushing it for me?

Sure!

-- 
Pierre-Marie de Rodat

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] Add proper handling for non-local references in nested functions
  2015-09-02 23:50                       ` Joel Brobecker
  2015-09-03  7:31                         ` Pierre-Marie de Rodat
@ 2015-09-16 16:16                         ` Doug Evans
  2015-09-20 18:20                           ` pushed: " Joel Brobecker
  1 sibling, 1 reply; 40+ messages in thread
From: Doug Evans @ 2015-09-16 16:16 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Pierre-Marie de Rodat, Kevin Buettner, gdb-patches

Joel Brobecker <brobecker@adacore.com> writes:
> Hi Pierre-Marie,
>
>> >From f8cb12e93bc4b317bf03dd31fc158cc05fc60367 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] DWARF: handle non-local references in nested functions
>> 
>> GDB's current behavior when dealing with non-local references in the
>> context of nested fuctions 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 the necessary context to symbol reads (to get 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 varibale
>> references.
>> 
>> gdb/ChangeLog:
>> 
>> 	* ada-lang.c (ada_read_var_value): Add a var_block argument
>> 	and pass it to default_read_var_value.
>> 	* block.c (block_static_link): New accessor.
>> 	* block.h (block_static_link): Declare it.
>> 	* buildsym.c (finish_block_internal): Add a static_link
>>       [...]
>
> This patch is causing a crash on some platforms, as explained by
> the revision log of the attached patch.
>
> gdb/ChangeLog:
>
>         * dwarf2loc.c (locexpr_get_frame_base): Renames
>         block_op_get_frame_base.
>         (dwarf2_block_frame_base_locexpr_funcs): Replace reference to
>         block_op_get_frame_base by reference to locexpr_get_frame_base.
>         (loclist_get_frame_base): New function, near identical copy of
>         locexpr_get_frame_base.
>         (dwarf2_block_frame_base_loclist_funcs): Replace reference to
>         block_op_get_frame_base by reference to loclist_get_frame_base.

LGTM.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* pushed: [PATCH] Add proper handling for non-local references in nested functions
  2015-09-16 16:16                         ` Doug Evans
@ 2015-09-20 18:20                           ` Joel Brobecker
  0 siblings, 0 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-09-20 18:20 UTC (permalink / raw)
  To: Doug Evans; +Cc: Pierre-Marie de Rodat, Kevin Buettner, gdb-patches

> > gdb/ChangeLog:
> >
> >         * dwarf2loc.c (locexpr_get_frame_base): Renames
> >         block_op_get_frame_base.
> >         (dwarf2_block_frame_base_locexpr_funcs): Replace reference to
> >         block_op_get_frame_base by reference to locexpr_get_frame_base.
> >         (loclist_get_frame_base): New function, near identical copy of
> >         locexpr_get_frame_base.
> >         (dwarf2_block_frame_base_loclist_funcs): Replace reference to
> >         block_op_get_frame_base by reference to loclist_get_frame_base.
> 
> LGTM.

Thank you, pushed!

-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2015-09-20 18:20 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-02 14:36 [PATCH] Add proper handling for non-local references in nested subprograms Pierre-Marie de Rodat
2015-03-10 15:26 ` Pedro Alves
2015-03-20 12:24   ` [PATCH] Add proper handling for non-local references in nested functions Pierre-Marie de Rodat
2015-05-29 12:28     ` Pedro Alves
2015-06-09 21:46       ` Pierre-Marie de Rodat
2015-07-22  9:16         ` Pierre-Marie de Rodat
2015-07-22 14:26           ` Doug Evans
2015-07-22 15:14             ` Pierre-Marie de Rodat
2015-07-26 17:28               ` Doug Evans
2015-07-22 17:58             ` Kevin Buettner
2015-07-23  1:36           ` Kevin Buettner
2015-07-23 10:44             ` Pierre-Marie de Rodat
2015-07-23 13:44               ` Kevin Buettner
2015-07-23 16:14                 ` Pierre-Marie de Rodat
2015-07-23 17:22                   ` Kevin Buettner
2015-07-23 17:33                     ` Pierre-Marie de Rodat
2015-07-23 17:51                       ` Kevin Buettner
2015-07-23 18:06                   ` Kevin Buettner
2015-07-23 18:23                     ` Kevin Buettner
2015-07-24 10:38                       ` Pierre-Marie de Rodat
2015-07-26 17:39                         ` Doug Evans
2015-07-24  9:26                     ` Pierre-Marie de Rodat
2015-07-26 20:35               ` Doug Evans
2015-07-31 10:53                 ` Pierre-Marie de Rodat
2015-08-10  8:34                   ` Pierre-Marie de Rodat
2015-08-13 15:03                     ` Doug Evans
2015-08-14  6:31                       ` Pierre-Marie de Rodat
2015-08-15  5:12                   ` Doug Evans
2015-08-15  6:21                     ` Doug Evans
2015-08-17 13:27                       ` Pierre-Marie de Rodat
2015-08-17 13:33                     ` Pierre-Marie de Rodat
2015-08-22 17:30                       ` Doug Evans
2015-08-25 12:14                         ` Pierre-Marie de Rodat
2015-09-02 23:50                       ` Joel Brobecker
2015-09-03  7:31                         ` Pierre-Marie de Rodat
2015-09-03 12:40                           ` Joel Brobecker
2015-09-03 14:03                             ` Pierre-Marie de Rodat
2015-09-16 16:16                         ` Doug Evans
2015-09-20 18:20                           ` pushed: " Joel Brobecker
2015-08-15  5:13                   ` Doug Evans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).