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

Doug Evans xdje42@gmail.com
Sat Aug 15 05:13:00 GMT 2015


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;
> +}
> +
>  
>  
>  /* 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,



More information about the Gdb-patches mailing list