From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 122313 invoked by alias); 15 Aug 2015 05:13:16 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 116148 invoked by uid 89); 15 Aug 2015 05:12:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.8 required=5.0 tests=AWL,BAYES_50,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_LOW,SPF_PASS,TBC autolearn=no version=3.3.2 X-HELO: mail-pa0-f46.google.com Received: from mail-pa0-f46.google.com (HELO mail-pa0-f46.google.com) (209.85.220.46) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sat, 15 Aug 2015 05:10:51 +0000 Received: by pacrr5 with SMTP id rr5so73136710pac.3 for ; Fri, 14 Aug 2015 22:10:35 -0700 (PDT) X-Received: by 10.66.119.136 with SMTP id ku8mr93362424pab.26.1439615435367; Fri, 14 Aug 2015 22:10:35 -0700 (PDT) Received: from seba.sebabeach.org.gmail.com (173-13-178-53-sfba.hfc.comcastbusiness.net. [173.13.178.53]) by smtp.gmail.com with ESMTPSA id os7sm7727506pbb.23.2015.08.14.22.10.34 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Aug 2015 22:10:34 -0700 (PDT) From: Doug Evans To: Pierre-Marie de Rodat Cc: Kevin Buettner , gdb-patches@sourceware.org Subject: Re: [PATCH] Add proper handling for non-local references in nested functions In-Reply-To: <55BB538B.7090104@adacore.com> (Pierre-Marie de Rodat's message of "Fri, 31 Jul 2015 12:52:59 +0200") References: <54F47563.4050103@adacore.com> <54FF0D05.70907@redhat.com> <550C1170.9070208@adacore.com> <55685B60.3000004@redhat.com> <55775EB0.4080701@adacore.com> <55AF5F7E.5000600@adacore.com> <20150722173957.7ed51f18@pinnacle.lan> <55B0C583.6050601@adacore.com> <55BB538B.7090104@adacore.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) Date: Sat, 15 Aug 2015 05:13:00 -0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes X-SW-Source: 2015-08/txt/msg00399.txt.bz2 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 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 > 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 instead of 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 . */ > + > +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 . > + > +# 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 . */ > + > +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 . > + > +# 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 . */ > + > +#include > + > +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 . > + > +# 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,