This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH] Add proper handling for non-local references in nested functions
- From: Doug Evans <xdje42 at gmail dot com>
- To: Pierre-Marie de Rodat <derodat at adacore dot com>
- Cc: Kevin Buettner <kevinb at redhat dot com>, gdb-patches at sourceware dot org
- Date: Fri, 14 Aug 2015 22:09:40 -0700
- Subject: Re: [PATCH] Add proper handling for non-local references in nested functions
- Authentication-results: sourceware.org; auth=none
- References: <54F47563 dot 4050103 at adacore dot com> <54FF0D05 dot 70907 at redhat dot com> <550C1170 dot 9070208 at adacore dot com> <55685B60 dot 3000004 at redhat dot com> <55775EB0 dot 4080701 at adacore dot com> <55AF5F7E dot 5000600 at adacore dot com> <20150722173957 dot 7ed51f18 at pinnacle dot lan> <55B0C583 dot 6050601 at adacore dot com> <m3380azmij dot fsf at sspiff dot org> <55BB538B dot 7090104 at adacore dot com>
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,