aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog109
-rw-r--r--gdb/ada-lang.c5
-rw-r--r--gdb/block.c15
-rw-r--r--gdb/block.h11
-rw-r--r--gdb/buildsym.c19
-rw-r--r--gdb/buildsym.h15
-rw-r--r--gdb/c-exp.y5
-rw-r--r--gdb/coffread.c6
-rw-r--r--gdb/compile/compile-c-symbols.c74
-rw-r--r--gdb/compile/compile-loc2c.c2
-rw-r--r--gdb/dbxread.c8
-rw-r--r--gdb/dwarf2loc.c57
-rw-r--r--gdb/dwarf2loc.h11
-rw-r--r--gdb/dwarf2read.c18
-rw-r--r--gdb/f-exp.y5
-rw-r--r--gdb/findvar.c168
-rw-r--r--gdb/gdbtypes.c7
-rw-r--r--gdb/go-exp.y5
-rw-r--r--gdb/guile/scm-frame.c9
-rw-r--r--gdb/guile/scm-symbol.c6
-rw-r--r--gdb/infcmd.c2
-rw-r--r--gdb/infrun.c7
-rw-r--r--gdb/jv-exp.y4
-rw-r--r--gdb/language.h12
-rw-r--r--gdb/m2-exp.y5
-rw-r--r--gdb/objfiles.c91
-rw-r--r--gdb/objfiles.h22
-rw-r--r--gdb/p-exp.y5
-rw-r--r--gdb/printcmd.c6
-rw-r--r--gdb/python/py-finishbreakpoint.c2
-rw-r--r--gdb/python/py-frame.c9
-rw-r--r--gdb/python/py-framefilter.c29
-rw-r--r--gdb/python/py-symbol.c6
-rw-r--r--gdb/stack.c8
-rw-r--r--gdb/symtab.h19
-rw-r--r--gdb/testsuite/ChangeLog9
-rw-r--r--gdb/testsuite/gdb.base/nested-subp1.c37
-rw-r--r--gdb/testsuite/gdb.base/nested-subp1.exp55
-rw-r--r--gdb/testsuite/gdb.base/nested-subp2.c48
-rw-r--r--gdb/testsuite/gdb.base/nested-subp2.exp64
-rw-r--r--gdb/testsuite/gdb.base/nested-subp3.c66
-rw-r--r--gdb/testsuite/gdb.base/nested-subp3.exp55
-rw-r--r--gdb/valops.c35
-rw-r--r--gdb/value.h2
-rw-r--r--gdb/xcoffread.c5
45 files changed, 1003 insertions, 155 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5dd90e7..8746f60 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,112 @@
+2015-08-25 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * ada-lang.c (ada_read_var_value): Add a var_block argument
+ and pass it to default_read_var_value.
+ * block.c (block_static_link): New accessor.
+ * block.h (block_static_link): Declare it.
+ * buildsym.c (finish_block_internal): Add a static_link
+ argument. If there is a static link, associate it to the new
+ block.
+ (finish_block): Add a static link argument and pass it to
+ finish_block_internal.
+ (end_symtab_get_static_block): Update calls to finish_block and
+ to finish_block_internal.
+ (end_symtab_with_blockvector): Update call to
+ finish_block_internal.
+ * buildsym.h: Forward-declare struct dynamic_prop.
+ (struct context_stack): Add a static_link field.
+ (finish_block): Add a static link argument.
+ * 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.
+
2015-08-25 Yao Qi <yao.qi@linaro.org>
* aarch64-linux-nat.c (aarch64_linux_new_thread): Move it to ...
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 1fa6524..4d7d22e 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13844,7 +13844,8 @@ ada_get_symbol_name_cmp (const char *lookup_name)
/* Implement the "la_read_var_value" language_defn method for Ada. */
static struct value *
-ada_read_var_value (struct symbol *var, struct frame_info *frame)
+ada_read_var_value (struct symbol *var, const struct block *var_block,
+ struct frame_info *frame)
{
const struct block *frame_block = NULL;
struct symbol *renaming_sym = NULL;
@@ -13860,7 +13861,7 @@ ada_read_var_value (struct symbol *var, struct frame_info *frame)
/* This is a typical case where we expect the default_read_var_value
function to work. */
- return default_read_var_value (var, frame);
+ return default_read_var_value (var, var_block, frame);
}
const struct language_defn ada_language_defn = {
diff --git a/gdb/block.c b/gdb/block.c
index f7621aa..f4b8e4f 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -428,6 +428,21 @@ set_block_compunit_symtab (struct block *block, struct compunit_symtab *cu)
gb->compunit_symtab = cu;
}
+/* See block.h. */
+
+struct dynamic_prop *
+block_static_link (const struct block *block)
+{
+ struct objfile *objfile = block_objfile (block);
+
+ /* Only objfile-owned blocks that materialize top function scopes can have
+ static links. */
+ if (objfile == NULL || BLOCK_FUNCTION (block) == NULL)
+ return NULL;
+
+ return (struct dynamic_prop *) objfile_lookup_static_link (objfile, block);
+}
+
/* Return the compunit of the global block. */
static struct compunit_symtab *
diff --git a/gdb/block.h b/gdb/block.h
index 3dbcbcb..c15114b 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -179,6 +179,17 @@ extern struct block *allocate_global_block (struct obstack *obstack);
extern void set_block_compunit_symtab (struct block *,
struct compunit_symtab *);
+/* Return a property to evaluate the static link associated to BLOCK.
+
+ In the context of nested functions (available in Pascal, Ada and GNU C, for
+ instance), a static link (as in DWARF's DW_AT_static_link attribute) for a
+ function is a way to get the frame corresponding to the enclosing function.
+
+ Note that only objfile-owned and function-level blocks can have a static
+ link. Return NULL if there is no such property. */
+
+extern struct dynamic_prop *block_static_link (const struct block *block);
+
/* A block iterator. This structure should be treated as though it
were opaque; it is only defined here because we want to support
stack allocation of iterators. */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 92c42d5..36ec62f 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -331,8 +331,10 @@ free_pending_blocks (void)
file). Put the block on the list of pending blocks. */
static struct block *
-finish_block_internal (struct symbol *symbol, struct pending **listhead,
+finish_block_internal (struct symbol *symbol,
+ struct pending **listhead,
struct pending_block *old_blocks,
+ const struct dynamic_prop *static_link,
CORE_ADDR start, CORE_ADDR end,
int is_global, int expandable)
{
@@ -422,6 +424,9 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
BLOCK_FUNCTION (block) = NULL;
}
+ if (static_link != NULL)
+ objfile_register_static_link (objfile, block, static_link);
+
/* Now "free" the links of the list, and empty the list. */
for (next = *listhead; next; next = next1)
@@ -519,11 +524,13 @@ finish_block_internal (struct symbol *symbol, struct pending **listhead,
}
struct block *
-finish_block (struct symbol *symbol, struct pending **listhead,
+finish_block (struct symbol *symbol,
+ struct pending **listhead,
struct pending_block *old_blocks,
+ const struct dynamic_prop *static_link,
CORE_ADDR start, CORE_ADDR end)
{
- return finish_block_internal (symbol, listhead, old_blocks,
+ return finish_block_internal (symbol, listhead, old_blocks, static_link,
start, end, 0, 0);
}
@@ -1229,7 +1236,7 @@ end_symtab_get_static_block (CORE_ADDR end_addr, int expandable, int required)
struct context_stack *cstk = pop_context ();
/* Make a block for the local symbols within. */
- finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks, NULL,
cstk->start_addr, end_addr);
if (context_stack_depth > 0)
@@ -1301,7 +1308,7 @@ end_symtab_get_static_block (CORE_ADDR end_addr, int expandable, int required)
else
{
/* Define the STATIC_BLOCK. */
- return finish_block_internal (NULL, &file_symbols, NULL,
+ return finish_block_internal (NULL, &file_symbols, NULL, NULL,
last_source_start_addr, end_addr,
0, expandable);
}
@@ -1329,7 +1336,7 @@ end_symtab_with_blockvector (struct block *static_block,
end_addr = BLOCK_END (static_block);
/* Create the GLOBAL_BLOCK and build the blockvector. */
- finish_block_internal (NULL, &global_symbols, NULL,
+ finish_block_internal (NULL, &global_symbols, NULL, NULL,
last_source_start_addr, end_addr,
1, expandable);
blockvector = make_blockvector ();
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 4c0ec15..b1eda8c 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -39,6 +39,8 @@ struct compunit_symtab;
struct block;
struct pending_block;
+struct dynamic_prop;
+
#ifndef EXTERN
#define EXTERN extern
#endif
@@ -145,6 +147,11 @@ struct context_stack
struct symbol *name;
+ /* Expression that computes the frame base of the lexically enclosing
+ function, if any. NULL otherwise. */
+
+ struct dynamic_prop *static_link;
+
/* PC where this context starts */
CORE_ADDR start_addr;
@@ -196,9 +203,11 @@ extern struct symbol *find_symbol_in_list (struct pending *list,
char *name, int length);
extern struct block *finish_block (struct symbol *symbol,
- struct pending **listhead,
- struct pending_block *old_blocks,
- CORE_ADDR start, CORE_ADDR end);
+ struct pending **listhead,
+ struct pending_block *old_blocks,
+ const struct dynamic_prop *static_link,
+ CORE_ADDR start,
+ CORE_ADDR end);
extern void record_block_range (struct block *,
CORE_ADDR start, CORE_ADDR end_inclusive);
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index a8a4caf..351505e 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1072,10 +1072,7 @@ variable: name_not_typename
}
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
- /* We want to use the selected frame, not
- another more inner frame which happens to
- be in the same block. */
- write_exp_elt_block (pstate, NULL);
+ write_exp_elt_block (pstate, sym.block);
write_exp_elt_sym (pstate, sym.symbol);
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
}
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 7722cdb..c0f4267 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1144,8 +1144,8 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
enter_linenos (fcn_line_ptr, fcn_first_line,
fcn_last_line, objfile);
- finish_block (newobj->name, &local_symbols,
- newobj->old_blocks, newobj->start_addr,
+ finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+ NULL, newobj->start_addr,
fcn_cs_saved.c_value
+ fcn_aux_saved.x_sym.x_misc.x_fsize
+ ANOFFSET (objfile->section_offsets,
@@ -1188,7 +1188,7 @@ coff_symtab_read (long symtab_offset, unsigned int nsyms,
cs->c_value + ANOFFSET (objfile->section_offsets,
SECT_OFF_TEXT (objfile));
/* Make a block for the local symbols within. */
- finish_block (0, &local_symbols, newobj->old_blocks,
+ finish_block (0, &local_symbols, newobj->old_blocks, NULL,
newobj->start_addr, tmpaddr);
}
/* Now pop locals of block just finished. */
diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
index 21ce655..355b063 100644
--- a/gdb/compile/compile-c-symbols.c
+++ b/gdb/compile/compile-c-symbols.c
@@ -143,26 +143,26 @@ symbol_substitution_name (struct symbol *sym)
static void
convert_one_symbol (struct compile_c_instance *context,
- struct symbol *sym,
+ struct block_symbol sym,
int is_global,
int is_local)
{
gcc_type sym_type;
- const char *filename = symbol_symtab (sym)->filename;
- unsigned short line = SYMBOL_LINE (sym);
+ const char *filename = symbol_symtab (sym.symbol)->filename;
+ unsigned short line = SYMBOL_LINE (sym.symbol);
- error_symbol_once (context, sym);
+ error_symbol_once (context, sym.symbol);
- if (SYMBOL_CLASS (sym) == LOC_LABEL)
+ if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
sym_type = 0;
else
- sym_type = convert_type (context, SYMBOL_TYPE (sym));
+ sym_type = convert_type (context, SYMBOL_TYPE (sym.symbol));
- if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
+ if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
{
/* Binding a tag, so we don't need to build a decl. */
C_CTX (context)->c_ops->tagbind (C_CTX (context),
- SYMBOL_NATURAL_NAME (sym),
+ SYMBOL_NATURAL_NAME (sym.symbol),
sym_type, filename, line);
}
else
@@ -172,7 +172,7 @@ convert_one_symbol (struct compile_c_instance *context,
CORE_ADDR addr = 0;
char *symbol_name = NULL;
- switch (SYMBOL_CLASS (sym))
+ switch (SYMBOL_CLASS (sym.symbol))
{
case LOC_TYPEDEF:
kind = GCC_C_SYMBOL_TYPEDEF;
@@ -180,45 +180,46 @@ convert_one_symbol (struct compile_c_instance *context,
case LOC_LABEL:
kind = GCC_C_SYMBOL_LABEL;
- addr = SYMBOL_VALUE_ADDRESS (sym);
+ addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
break;
case LOC_BLOCK:
kind = GCC_C_SYMBOL_FUNCTION;
- addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
- if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
+ addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
+ if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
break;
case LOC_CONST:
- if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
+ if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
{
/* Already handled by convert_enum. */
return;
}
- C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
- SYMBOL_NATURAL_NAME (sym),
- SYMBOL_VALUE (sym),
- filename, line);
+ C_CTX (context)->c_ops->build_constant
+ (C_CTX (context),
+ sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
+ SYMBOL_VALUE (sym.symbol),
+ filename, line);
return;
case LOC_CONST_BYTES:
error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
case LOC_UNDEF:
internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
case LOC_COMMON_BLOCK:
error (_("Fortran common block is unsupported for compilation "
"evaluaton of symbol \"%s\"."),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
case LOC_OPTIMIZED_OUT:
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
"as it is optimized out."),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
case LOC_COMPUTED:
if (is_local)
@@ -227,7 +228,7 @@ convert_one_symbol (struct compile_c_instance *context,
warning (_("Symbol \"%s\" is thread-local and currently can only "
"be referenced from the current thread in "
"compiled code."),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
/* FALLTHROUGH */
case LOC_UNRESOLVED:
/* 'symbol_name' cannot be used here as that one is used only for
@@ -238,20 +239,20 @@ convert_one_symbol (struct compile_c_instance *context,
struct value *val;
struct frame_info *frame = NULL;
- if (symbol_read_needs_frame (sym))
+ if (symbol_read_needs_frame (sym.symbol))
{
frame = get_selected_frame (NULL);
if (frame == NULL)
error (_("Symbol \"%s\" cannot be used because "
"there is no selected frame"),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
}
- val = read_var_value (sym, frame);
+ val = read_var_value (sym.symbol, sym.block, frame);
if (VALUE_LVAL (val) != lval_memory)
error (_("Symbol \"%s\" cannot be used for compilation "
"evaluation as its address has not been found."),
- SYMBOL_PRINT_NAME (sym));
+ SYMBOL_PRINT_NAME (sym.symbol));
kind = GCC_C_SYMBOL_VARIABLE;
addr = value_address (val);
@@ -266,12 +267,12 @@ convert_one_symbol (struct compile_c_instance *context,
case LOC_LOCAL:
substitution:
kind = GCC_C_SYMBOL_VARIABLE;
- symbol_name = symbol_substitution_name (sym);
+ symbol_name = symbol_substitution_name (sym.symbol);
break;
case LOC_STATIC:
kind = GCC_C_SYMBOL_VARIABLE;
- addr = SYMBOL_VALUE_ADDRESS (sym);
+ addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
break;
case LOC_FINAL_VALUE:
@@ -284,12 +285,13 @@ convert_one_symbol (struct compile_c_instance *context,
if (context->base.scope != COMPILE_I_RAW_SCOPE
|| symbol_name == NULL)
{
- decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
- SYMBOL_NATURAL_NAME (sym),
- kind,
- sym_type,
- symbol_name, addr,
- filename, line);
+ decl = C_CTX (context)->c_ops->build_decl
+ (C_CTX (context),
+ SYMBOL_NATURAL_NAME (sym.symbol),
+ kind,
+ sym_type,
+ symbol_name, addr,
+ filename, line);
C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
}
@@ -338,7 +340,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": global symbol\n",
identifier);
- convert_one_symbol (context, global_sym.symbol, 1, 0);
+ convert_one_symbol (context, global_sym, 1, 0);
}
}
@@ -346,7 +348,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": local symbol\n",
identifier);
- convert_one_symbol (context, sym.symbol, 0, is_local_symbol);
+ convert_one_symbol (context, sym, 0, is_local_symbol);
}
/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index b201d13..8058cbd 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -636,7 +636,7 @@ do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
"there is no selected frame"),
SYMBOL_PRINT_NAME (sym));
- val = read_var_value (sym, frame);
+ val = read_var_value (sym, NULL, frame);
if (VALUE_LVAL (val) != lval_memory)
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
"as its address has not been found."),
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 1d00432..fdf4e09 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2756,7 +2756,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
/* Make a block for the local symbols within. */
block = finish_block (newobj->name, &local_symbols,
- newobj->old_blocks,
+ newobj->old_blocks, NULL,
newobj->start_addr, newobj->start_addr + valu);
/* For C++, set the block's scope. */
@@ -2857,7 +2857,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
newobj->start_addr = valu;
}
/* Make a block for the local symbols within. */
- finish_block (0, &local_symbols, newobj->old_blocks,
+ finish_block (0, &local_symbols, newobj->old_blocks, NULL,
newobj->start_addr, valu);
}
}
@@ -3155,8 +3155,8 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name,
newobj = pop_context ();
/* Make a block for the local symbols within. */
block = finish_block (newobj->name, &local_symbols,
- newobj->old_blocks, newobj->start_addr,
- valu);
+ newobj->old_blocks, NULL,
+ newobj->start_addr, valu);
/* For C++, set the block's scope. */
if (SYMBOL_LANGUAGE (newobj->name) == language_cplus)
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index d8e432e..efe4357 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -381,12 +381,47 @@ locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
*start = symbaton->data;
}
+/* Implement the struct symbol_block_ops::get_frame_base method. */
+
+static CORE_ADDR
+block_op_get_frame_base (struct symbol *framefunc, struct frame_info *frame)
+{
+ struct gdbarch *gdbarch;
+ struct type *type;
+ struct dwarf2_locexpr_baton *dlbaton;
+ const gdb_byte *start;
+ size_t length;
+ struct value *result;
+
+ /* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
+ Thus, it's supposed to provide the find_frame_base_location method as
+ well. */
+ gdb_assert (SYMBOL_BLOCK_OPS (framefunc)->find_frame_base_location != NULL);
+
+ gdbarch = get_frame_arch (frame);
+ type = builtin_type (gdbarch)->builtin_data_ptr;
+ dlbaton = SYMBOL_LOCATION_BATON (framefunc);
+
+ SYMBOL_BLOCK_OPS (framefunc)->find_frame_base_location
+ (framefunc, get_frame_pc (frame), &start, &length);
+ result = dwarf2_evaluate_loc_desc (type, frame, start, length,
+ dlbaton->per_cu);
+
+ /* The DW_AT_frame_base attribute contains a location description which
+ computes the base address itself. However, the call to
+ dwarf2_evaluate_loc_desc returns a value representing a variable at
+ that address. The frame base address is thus this variable's
+ address. */
+ return value_address (result);
+}
+
/* Vector for inferior functions as represented by LOC_BLOCK, if the inferior
function uses DWARF expression for its DW_AT_frame_base. */
const struct symbol_block_ops dwarf2_block_frame_base_locexpr_funcs =
{
- locexpr_find_frame_base_location
+ locexpr_find_frame_base_location,
+ block_op_get_frame_base
};
/* Implement find_frame_base_location method for LOC_BLOCK functions using
@@ -406,7 +441,8 @@ loclist_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
const struct symbol_block_ops dwarf2_block_frame_base_loclist_funcs =
{
- loclist_find_frame_base_location
+ loclist_find_frame_base_location,
+ block_op_get_frame_base
};
/* See dwarf2loc.h. */
@@ -2396,13 +2432,14 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame,
}
/* Evaluates a dwarf expression and stores the result in VAL, expecting
- that the dwarf expression only produces a single CORE_ADDR. ADDR is a
- context (location of a variable) and might be needed to evaluate the
- location expression.
+ that the dwarf expression only produces a single CORE_ADDR. FRAME is the
+ frame in which the expression is evaluated. ADDR is a context (location of
+ a variable) and might be needed to evaluate the location expression.
Returns 1 on success, 0 otherwise. */
static int
dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
+ struct frame_info *frame,
CORE_ADDR addr,
CORE_ADDR *valp)
{
@@ -2417,7 +2454,7 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
ctx = new_dwarf_expr_context ();
cleanup = make_cleanup_free_dwarf_expr_context (ctx);
- baton.frame = get_selected_frame (NULL);
+ baton.frame = frame;
baton.per_cu = dlbaton->per_cu;
baton.obj_address = addr;
@@ -2461,19 +2498,24 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
int
dwarf2_evaluate_property (const struct dynamic_prop *prop,
+ struct frame_info *frame,
struct property_addr_info *addr_stack,
CORE_ADDR *value)
{
if (prop == NULL)
return 0;
+ if (frame == NULL && has_stack_frames ())
+ frame = get_selected_frame (NULL);
+
switch (prop->kind)
{
case PROP_LOCEXPR:
{
const struct dwarf2_property_baton *baton = prop->data.baton;
- if (dwarf2_locexpr_baton_eval (&baton->locexpr, addr_stack->addr,
+ if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame,
+ addr_stack ? addr_stack->addr : 0,
value))
{
if (baton->referenced_type)
@@ -2490,7 +2532,6 @@ dwarf2_evaluate_property (const struct dynamic_prop *prop,
case PROP_LOCLIST:
{
struct dwarf2_property_baton *baton = prop->data.baton;
- struct frame_info *frame = get_selected_frame (NULL);
CORE_ADDR pc = get_frame_address_in_block (frame);
const gdb_byte *data;
struct value *val;
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index f3630ac..2415656 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -122,12 +122,19 @@ struct property_addr_info
struct property_addr_info *next;
};
-/* Converts a dynamic property into a static one. ADDR_STACK is the stack
- of addresses that might be needed to evaluate the property.
+/* Converts a dynamic property into a static one. FRAME is the frame in which
+ the property is evaluated; if NULL, the selected frame (if any) is used
+ instead.
+
+ ADDR_STACK is the stack of addresses that might be needed to evaluate the
+ property. When evaluating a property that is not related to a type, it can
+ be NULL.
+
Returns 1 if PROP could be converted and the static value is passed back
into VALUE, otherwise returns 0. */
int dwarf2_evaluate_property (const struct dynamic_prop *prop,
+ struct frame_info *frame,
struct property_addr_info *addr_stack,
CORE_ADDR *value);
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 67b4a6d..77d37dd 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1743,6 +1743,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 *);
@@ -11392,6 +11396,16 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
if (attr)
dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
+ /* If there is a location for the static link, record it. */
+ newobj->static_link = NULL;
+ attr = dwarf2_attr (die, DW_AT_static_link, cu);
+ if (attr)
+ {
+ newobj->static_link = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (*newobj->static_link));
+ attr_to_dynamic_prop (attr, die, cu, newobj->static_link);
+ }
+
cu->list_in_scope = &local_symbols;
if (die->child != NULL)
@@ -11443,7 +11457,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
@@ -11528,7 +11542,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
if (local_symbols != NULL || local_using_directives != NULL)
{
struct block *block
- = finish_block (0, &local_symbols, newobj->old_blocks,
+ = finish_block (0, &local_symbols, newobj->old_blocks, NULL,
newobj->start_addr, highpc);
/* Note that recording ranges after traversing children, as we
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 3c486ef..56629dc 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -521,10 +521,7 @@ variable: name_not_typename
innermost_block = sym.block;
}
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
- /* We want to use the selected frame, not
- another more inner frame which happens to
- be in the same block. */
- write_exp_elt_block (pstate, NULL);
+ write_exp_elt_block (pstate, sym.block);
write_exp_elt_sym (pstate, sym.symbol);
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
break;
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 83b4fca..1c077f7 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -32,6 +32,7 @@
#include "block.h"
#include "objfiles.h"
#include "language.h"
+#include "dwarf2loc.h"
/* Basic byte-swapping routines. All 'extract' functions return a
host-format integer from a target-format integer at ADDR which is
@@ -409,11 +410,166 @@ minsym_lookup_iterator_cb (struct objfile *objfile, void *cb_data)
return (data->result.minsym != NULL);
}
+/* Given static link expression and the frame it lives in, look for the frame
+ the static links points to and return it. Return NULL if we could not find
+ such a frame. */
+
+static struct frame_info *
+follow_static_link (struct frame_info *frame,
+ const struct dynamic_prop *static_link)
+{
+ CORE_ADDR upper_frame_base;
+
+ if (!dwarf2_evaluate_property (static_link, frame, NULL, &upper_frame_base))
+ return NULL;
+
+ /* Now climb up the stack frame until we reach the frame we are interested
+ in. */
+ for (; frame != NULL; frame = get_prev_frame (frame))
+ {
+ struct symbol *framefunc = get_frame_function (frame);
+
+ /* Stacks can be quite deep: give the user a chance to stop this. */
+ QUIT;
+
+ /* If we don't know how to compute FRAME's base address, don't give up:
+ maybe the frame we are looking for is upper in the stace frame. */
+ if (framefunc != NULL
+ && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base != NULL
+ && (SYMBOL_BLOCK_OPS (framefunc)->get_frame_base (framefunc, frame)
+ == upper_frame_base))
+ break;
+ }
+
+ return frame;
+}
+
+/* Assuming VAR is a symbol that can be reached from FRAME thanks to lexical
+ rules, look for the frame that is actually hosting VAR and return it. If,
+ for some reason, we found no such frame, return NULL.
+
+ This kind of computation is necessary to correctly handle lexically nested
+ functions.
+
+ Note that in some cases, we know what scope VAR comes from but we cannot
+ reach the specific frame that hosts the instance of VAR we are looking for.
+ For backward compatibility purposes (with old compilers), we then look for
+ the first frame that can host it. */
+
+static struct frame_info *
+get_hosting_frame (struct symbol *var, const struct block *var_block,
+ struct frame_info *frame)
+{
+ const struct block *frame_block = NULL;
+
+ if (!symbol_read_needs_frame (var))
+ return NULL;
+
+ /* Some symbols for local variables have no block: this happens when they are
+ not produced by a debug information reader, for instance when GDB creates
+ synthetic symbols. Without block information, we must assume they are
+ local to FRAME. In this case, there is nothing to do. */
+ else if (var_block == NULL)
+ return frame;
+
+ /* We currently assume that all symbols with a location list need a frame.
+ This is true in practice because selecting the location description
+ requires to compute the CFA, hence requires a frame. However we have
+ tests that embed global/static symbols with null location lists.
+ We want to get <optimized out> instead of <frame required> when evaluating
+ them so return a frame instead of raising an error. */
+ else if (var_block == block_global_block (var_block)
+ || var_block == block_static_block (var_block))
+ return frame;
+
+ /* We have to handle the "my_func::my_local_var" notation. This requires us
+ to look for upper frames when we find no block for the current frame: here
+ and below, handle when frame_block == NULL. */
+ if (frame != NULL)
+ frame_block = get_frame_block (frame, NULL);
+
+ /* Climb up the call stack until reaching the frame we are looking for. */
+ while (frame != NULL && frame_block != var_block)
+ {
+ /* Stacks can be quite deep: give the user a chance to stop this. */
+ QUIT;
+
+ if (frame_block == NULL)
+ {
+ frame = get_prev_frame (frame);
+ if (frame == NULL)
+ break;
+ frame_block = get_frame_block (frame, NULL);
+ }
+
+ /* If we failed to find the proper frame, fallback to the heuristic
+ method below. */
+ else if (frame_block == block_global_block (frame_block))
+ {
+ frame = NULL;
+ break;
+ }
+
+ /* Assuming we have a block for this frame: if we are at the function
+ level, the immediate upper lexical block is in an outer function:
+ follow the static link. */
+ else if (BLOCK_FUNCTION (frame_block))
+ {
+ const struct dynamic_prop *static_link
+ = block_static_link (frame_block);
+ int could_climb_up = 0;
+
+ if (static_link != NULL)
+ {
+ frame = follow_static_link (frame, static_link);
+ if (frame != NULL)
+ {
+ frame_block = get_frame_block (frame, NULL);
+ could_climb_up = frame_block != NULL;
+ }
+ }
+ if (!could_climb_up)
+ {
+ frame = NULL;
+ break;
+ }
+ }
+
+ else
+ /* We must be in some function nested lexical block. Just get the
+ outer block: both must share the same frame. */
+ frame_block = BLOCK_SUPERBLOCK (frame_block);
+ }
+
+ /* Old compilers may not provide a static link, or they may provide an
+ invalid one. For such cases, fallback on the old way to evaluate
+ non-local references: just climb up the call stack and pick the first
+ frame that contains the variable we are looking for. */
+ if (frame == NULL)
+ {
+ frame = block_innermost_frame (var_block);
+ if (frame == NULL)
+ {
+ if (BLOCK_FUNCTION (var_block)
+ && !block_inlined_p (var_block)
+ && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block)))
+ error (_("No frame is currently executing in block %s."),
+ SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block)));
+ else
+ error (_("No frame is currently executing in specified"
+ " block"));
+ }
+ }
+
+ return frame;
+}
+
/* A default implementation for the "la_read_var_value" hook in
the language vector which should work in most situations. */
struct value *
-default_read_var_value (struct symbol *var, struct frame_info *frame)
+default_read_var_value (struct symbol *var, const struct block *var_block,
+ struct frame_info *frame)
{
struct value *v;
struct type *type = SYMBOL_TYPE (var);
@@ -427,7 +583,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
check_typedef (type);
if (symbol_read_needs_frame (var))
- gdb_assert (frame);
+ gdb_assert (frame != NULL);
+
+ if (frame != NULL)
+ frame = get_hosting_frame (var, var_block, frame);
if (SYMBOL_COMPUTED_OPS (var) != NULL)
return SYMBOL_COMPUTED_OPS (var)->read_variable (var, frame);
@@ -610,14 +769,15 @@ default_read_var_value (struct symbol *var, struct frame_info *frame)
/* Calls VAR's language la_read_var_value hook with the given arguments. */
struct value *
-read_var_value (struct symbol *var, struct frame_info *frame)
+read_var_value (struct symbol *var, const struct block *var_block,
+ struct frame_info *frame)
{
const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var));
gdb_assert (lang != NULL);
gdb_assert (lang->la_read_var_value != NULL);
- return lang->la_read_var_value (var, frame);
+ return lang->la_read_var_value (var, var_block, frame);
}
/* Install default attributes for register values. */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 125af01..301c6fc 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1885,7 +1885,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
gdb_assert (TYPE_CODE (dyn_range_type) == TYPE_CODE_RANGE);
prop = &TYPE_RANGE_DATA (dyn_range_type)->low;
- if (dwarf2_evaluate_property (prop, addr_stack, &value))
+ if (dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
{
low_bound.kind = PROP_CONST;
low_bound.data.const_val = value;
@@ -1897,7 +1897,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
}
prop = &TYPE_RANGE_DATA (dyn_range_type)->high;
- if (dwarf2_evaluate_property (prop, addr_stack, &value))
+ if (dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
{
high_bound.kind = PROP_CONST;
high_bound.data.const_val = value;
@@ -2139,7 +2139,8 @@ resolve_dynamic_type_internal (struct type *type,
/* Resolve data_location attribute. */
prop = TYPE_DATA_LOCATION (resolved_type);
- if (prop != NULL && dwarf2_evaluate_property (prop, addr_stack, &value))
+ if (prop != NULL
+ && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
{
TYPE_DYN_PROP_ADDR (prop) = value;
TYPE_DYN_PROP_KIND (prop) = PROP_CONST;
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index c1ddfa9..4e017fe 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -611,10 +611,7 @@ variable: name_not_typename
}
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
- /* We want to use the selected frame, not
- another more inner frame which happens to
- be in the same block. */
- write_exp_elt_block (pstate, NULL);
+ write_exp_elt_block (pstate, sym.block);
write_exp_elt_sym (pstate, sym.symbol);
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
}
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 64ac0c0..de77c21 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -855,6 +855,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
SCM block_scm = SCM_UNDEFINED;
struct frame_info *frame = NULL;
struct symbol *var = NULL;
+ const struct block *block = NULL;
struct value *value = NULL;
f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
@@ -909,9 +910,13 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
TRY
{
+ struct block_symbol lookup_sym;
+
if (block == NULL)
block = get_frame_block (frame, NULL);
- var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+ lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+ var = lookup_sym.symbol;
+ block = lookup_sym.block;
}
CATCH (ex, RETURN_MASK_ALL)
{
@@ -940,7 +945,7 @@ gdbscm_frame_read_var (SCM self, SCM symbol_scm, SCM rest)
TRY
{
- value = read_var_value (var, frame);
+ value = read_var_value (var, block, frame);
}
CATCH (except, RETURN_MASK_ALL)
{
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 01c9eb1..0970a72 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -550,7 +550,11 @@ gdbscm_symbol_value (SCM self, SCM rest)
if (symbol_read_needs_frame (symbol) && frame_info == NULL)
error (_("Symbol requires a frame to compute its value"));
- value = read_var_value (symbol, frame_info);
+ /* TODO: currently, we have no way to recover the block in which SYMBOL
+ was found, so we have no block to pass to read_var_value. This will
+ yield an incorrect value when symbol is not local to FRAME_INFO (this
+ can happen with nested functions). */
+ value = read_var_value (symbol, NULL, frame_info);
}
CATCH (except, RETURN_MASK_ALL)
{
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 82399a4..393ccb9 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1662,7 +1662,7 @@ finish_command_continuation (void *arg, int err)
{
struct value *func;
- func = read_var_value (a->function, get_current_frame ());
+ func = read_var_value (a->function, NULL, get_current_frame ());
TRY
{
/* print_return_value can throw an exception in some
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 25036a4..1e224b1 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -7198,14 +7198,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
{
TRY
{
- struct symbol *vsym;
+ struct block_symbol vsym;
struct value *value;
CORE_ADDR handler;
struct breakpoint *bp;
- vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN,
- NULL).symbol;
- value = read_var_value (vsym, frame);
+ vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+ value = read_var_value (vsym.symbol, vsym.block, frame);
/* If the value was optimized out, revert to the old behavior. */
if (! value_optimized_out (value))
{
diff --git a/gdb/jv-exp.y b/gdb/jv-exp.y
index 4999848..60b7d2e 100644
--- a/gdb/jv-exp.y
+++ b/gdb/jv-exp.y
@@ -1284,9 +1284,7 @@ push_variable (struct parser_state *par_state, struct stoken name)
}
write_exp_elt_opcode (par_state, OP_VAR_VALUE);
- /* We want to use the selected frame, not another more inner frame
- which happens to be in the same block. */
- write_exp_elt_block (par_state, NULL);
+ write_exp_elt_block (par_state, sym.block);
write_exp_elt_sym (par_state, sym.symbol);
write_exp_elt_opcode (par_state, OP_VAR_VALUE);
return 1;
diff --git a/gdb/language.h b/gdb/language.h
index 2265afc..8b579a2 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -241,13 +241,19 @@ struct language_defn
void (*la_value_print) (struct value *, struct ui_file *,
const struct value_print_options *);
- /* Given a symbol VAR, and a stack frame id FRAME, read the value
- of the variable an return (pointer to a) struct value containing
- the value.
+ /* Given a symbol VAR, the corresponding block VAR_BLOCK (if any) and a
+ stack frame id FRAME, read the value of the variable and return (pointer
+ to a) struct value containing the value.
+
+ VAR_BLOCK is needed if there's a possibility for VAR to be outside
+ FRAME. This is what happens if FRAME correspond to a nested function
+ and VAR is defined in the outer function. If callers know that VAR is
+ located in FRAME or is global/static, NULL can be passed as VAR_BLOCK.
Throw an error if the variable cannot be found. */
struct value *(*la_read_var_value) (struct symbol *var,
+ const struct block *var_block,
struct frame_info *frame);
/* PC is possibly an unknown languages trampoline.
diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y
index 633c354..360fdea 100644
--- a/gdb/m2-exp.y
+++ b/gdb/m2-exp.y
@@ -637,10 +637,7 @@ variable: NAME
}
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
- /* We want to use the selected frame, not
- another more inner frame which happens to
- be in the same block. */
- write_exp_elt_block (pstate, NULL);
+ write_exp_elt_block (pstate, sym.block);
write_exp_elt_sym (pstate, sym.symbol);
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
}
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index c6f9f00..93d8b7d 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -199,6 +199,92 @@ set_objfile_main_name (struct objfile *objfile,
objfile->per_bfd->language_of_main = lang;
}
+/* Helper structure to map blocks to static link properties in hash tables. */
+
+struct static_link_htab_entry
+{
+ const struct block *block;
+ const struct dynamic_prop *static_link;
+};
+
+/* Return a hash code for struct static_link_htab_entry *P. */
+
+static hashval_t
+static_link_htab_entry_hash (const void *p)
+{
+ const struct static_link_htab_entry *e
+ = (const struct static_link_htab_entry *) p;
+
+ return htab_hash_pointer (e->block);
+}
+
+/* Return whether P1 an P2 (pointers to struct static_link_htab_entry) are
+ mappings for the same block. */
+
+static int
+static_link_htab_entry_eq (const void *p1, const void *p2)
+{
+ const struct static_link_htab_entry *e1
+ = (const struct static_link_htab_entry *) p1;
+ const struct static_link_htab_entry *e2
+ = (const struct static_link_htab_entry *) p2;
+
+ return e1->block == e2->block;
+}
+
+/* Register STATIC_LINK as the static link for BLOCK, which is part of OBJFILE.
+ Must not be called more than once for each BLOCK. */
+
+void
+objfile_register_static_link (struct objfile *objfile,
+ const struct block *block,
+ const struct dynamic_prop *static_link)
+{
+ void **slot;
+ struct static_link_htab_entry lookup_entry;
+ struct static_link_htab_entry *entry;
+
+ if (objfile->static_links == NULL)
+ objfile->static_links = htab_create_alloc
+ (1, &static_link_htab_entry_hash, static_link_htab_entry_eq, NULL,
+ xcalloc, xfree);
+
+ /* Create a slot for the mapping, make sure it's the first mapping for this
+ block and then create the mapping itself. */
+ lookup_entry.block = block;
+ slot = htab_find_slot (objfile->static_links, &lookup_entry, INSERT);
+ gdb_assert (*slot == NULL);
+
+ entry = (struct static_link_htab_entry *) obstack_alloc
+ (&objfile->objfile_obstack, sizeof (*entry));
+ entry->block = block;
+ entry->static_link = static_link;
+ *slot = (void *) entry;
+}
+
+/* Look for a static link for BLOCK, which is part of OBJFILE. Return NULL if
+ none was found. */
+
+const struct dynamic_prop *
+objfile_lookup_static_link (struct objfile *objfile,
+ const struct block *block)
+{
+ struct static_link_htab_entry *entry;
+ struct static_link_htab_entry lookup_entry;
+
+ if (objfile->static_links == NULL)
+ return NULL;
+ lookup_entry.block = block;
+ entry
+ = (struct static_link_htab_entry *) htab_find (objfile->static_links,
+ &lookup_entry);
+ if (entry == NULL)
+ return NULL;
+
+ gdb_assert (entry->block == block);
+ return entry->static_link;
+}
+
/* Called via bfd_map_over_sections to build up the section table that
@@ -653,6 +739,11 @@ free_objfile (struct objfile *objfile)
/* Rebuild section map next time we need it. */
get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
+ /* Free the map for static links. There's no need to free static link
+ themselves since they were allocated on the objstack. */
+ if (objfile->static_links != NULL)
+ htab_delete (objfile->static_links);
+
/* The last thing we do is free the objfile struct itself. */
xfree (objfile);
}
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index af70715..be2a5ef 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -20,6 +20,7 @@
#if !defined (OBJFILES_H)
#define OBJFILES_H
+#include "hashtab.h"
#include "gdb_obstack.h" /* For obstack internals. */
#include "symfile.h" /* For struct psymbol_allocation_list. */
#include "progspace.h"
@@ -428,6 +429,19 @@ struct objfile
properly. */
struct symbol *template_symbols;
+
+ /* Associate a static link (struct dynamic_prop *) to all blocks (struct
+ block *) that have one.
+
+ In the context of nested functions (available in Pascal, Ada and GNU C,
+ for instance), a static link (as in DWARF's DW_AT_static_link attribute)
+ for a function is a way to get the frame corresponding to the enclosing
+ function.
+
+ Very few blocks have a static link, so it's more memory efficient to
+ store these here rather than in struct block. Static links must be
+ allocated on the objfile's obstack. */
+ htab_t static_links;
};
/* Defines for the objfile flag word. */
@@ -735,4 +749,12 @@ extern const char *objfile_debug_name (const struct objfile *objfile);
extern void set_objfile_main_name (struct objfile *objfile,
const char *name, enum language lang);
+extern void objfile_register_static_link
+ (struct objfile *objfile,
+ const struct block *block,
+ const struct dynamic_prop *static_link);
+
+extern const struct dynamic_prop *objfile_lookup_static_link
+ (struct objfile *objfile, const struct block *block);
+
#endif /* !defined (OBJFILES_H) */
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 191b3d3..c255a57 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -772,10 +772,7 @@ variable: name_not_typename
}
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
- /* We want to use the selected frame, not
- another more inner frame which happens to
- be in the same block. */
- write_exp_elt_block (pstate, NULL);
+ write_exp_elt_block (pstate, sym.block);
write_exp_elt_sym (pstate, sym.symbol);
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
current_type = sym.symbol->type; }
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f51e25c..553cc71 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1988,7 +1988,11 @@ print_variable_and_value (const char *name, struct symbol *var,
struct value *val;
struct value_print_options opts;
- val = read_var_value (var, frame);
+ /* READ_VAR_VALUE needs a block in order to deal with non-local
+ references (i.e. to handle nested functions). In this context, we
+ print variables that are local to this frame, so we can avoid passing
+ a block to it. */
+ val = read_var_value (var, NULL, frame);
get_user_print_options (&opts);
opts.deref_ref = 1;
common_val_print (val, stream, indent, &opts, current_language);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index e543bb3..351f68c 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -265,7 +265,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
/* Ignore Python errors at this stage. */
self_bpfinish->return_type = type_to_type_object (ret_type);
PyErr_Clear ();
- func_value = read_var_value (function, frame);
+ func_value = read_var_value (function, NULL, frame);
self_bpfinish->function_value =
value_to_value_object (func_value);
PyErr_Clear ();
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 7e5dd17..b448686 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -504,6 +504,7 @@ frapy_read_var (PyObject *self, PyObject *args)
struct frame_info *frame;
PyObject *sym_obj, *block_obj = NULL;
struct symbol *var = NULL; /* gcc-4.3.2 false warning. */
+ const struct block *block = NULL;
struct value *val = NULL;
if (!PyArg_ParseTuple (args, "O|O", &sym_obj, &block_obj))
@@ -514,7 +515,6 @@ frapy_read_var (PyObject *self, PyObject *args)
else if (gdbpy_is_string (sym_obj))
{
char *var_name;
- const struct block *block = NULL;
struct cleanup *cleanup;
var_name = python_string_to_target_string (sym_obj);
@@ -536,11 +536,14 @@ frapy_read_var (PyObject *self, PyObject *args)
TRY
{
+ struct block_symbol lookup_sym;
FRAPY_REQUIRE_VALID (self, frame);
if (!block)
block = get_frame_block (frame, NULL);
- var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL).symbol;
+ lookup_sym = lookup_symbol (var_name, block, VAR_DOMAIN, NULL);
+ var = lookup_sym.symbol;
+ block = lookup_sym.block;
}
CATCH (except, RETURN_MASK_ALL)
{
@@ -572,7 +575,7 @@ frapy_read_var (PyObject *self, PyObject *args)
{
FRAPY_REQUIRE_VALID (self, frame);
- val = read_var_value (var, frame);
+ val = read_var_value (var, block, frame);
}
CATCH (except, RETURN_MASK_ALL)
{
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index e3336b1..ac97723 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -43,16 +43,17 @@ enum mi_print_types
NAME is a pass-through argument where the name of the symbol will
be written. NAME is allocated in this function, but the caller is
responsible for clean up. SYM is a pass-through argument where the
- symbol will be written. In the case of the API returning a string,
- this will be set to NULL. LANGUAGE is also a pass-through argument
- denoting the language attributed to the Symbol. In the case of SYM
- being NULL, this will be set to the current language. Returns
- EXT_LANG_BT_ERROR on error with the appropriate Python exception set, and
- EXT_LANG_BT_OK on success. */
+ symbol will be written and SYM_BLOCK is a pass-through argument to
+ write the block where the symbol lies in. In the case of the API
+ returning a string, this will be set to NULL. LANGUAGE is also a
+ pass-through argument denoting the language attributed to the
+ Symbol. In the case of SYM being NULL, this will be set to the
+ current language. Returns EXT_LANG_BT_ERROR on error with the
+ appropriate Python exception set, and EXT_LANG_BT_OK on success. */
static enum ext_lang_bt_status
extract_sym (PyObject *obj, char **name, struct symbol **sym,
- const struct language_defn **language)
+ struct block **sym_block, const struct language_defn **language)
{
PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
@@ -75,12 +76,18 @@ extract_sym (PyObject *obj, char **name, struct symbol **sym,
python_language. */
*language = python_language;
*sym = NULL;
+ *sym_block = NULL;
}
else
{
/* This type checks 'result' during the conversion so we
just call it unconditionally and check the return. */
*sym = symbol_object_to_symbol (result);
+ /* TODO: currently, we have no way to recover the block in which SYMBOL
+ was found, so we have no block to return. Trying to evaluate SYMBOL
+ will yield an incorrect value when it's located in a FRAME and
+ evaluated from another frame (as permitted in nested functions). */
+ *sym_block = NULL;
Py_DECREF (result);
@@ -537,10 +544,11 @@ enumerate_args (PyObject *iter,
const struct language_defn *language;
char *sym_name;
struct symbol *sym;
+ struct block *sym_block;
struct value *val;
enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
- success = extract_sym (item, &sym_name, &sym, &language);
+ success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
if (success == EXT_LANG_BT_ERROR)
{
Py_DECREF (item);
@@ -736,12 +744,13 @@ enumerate_locals (PyObject *iter,
struct value *val;
enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
struct symbol *sym;
+ struct block *sym_block;
int local_indent = 8 + (8 * indent);
struct cleanup *locals_cleanups;
locals_cleanups = make_cleanup_py_decref (item);
- success = extract_sym (item, &sym_name, &sym, &language);
+ success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
if (success == EXT_LANG_BT_ERROR)
{
do_cleanups (locals_cleanups);
@@ -769,7 +778,7 @@ enumerate_locals (PyObject *iter,
{
TRY
{
- val = read_var_value (sym, frame);
+ val = read_var_value (sym, sym_block, frame);
}
CATCH (except, RETURN_MASK_ERROR)
{
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index f6466bd..3d2fa91 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -278,7 +278,11 @@ sympy_value (PyObject *self, PyObject *args)
if (symbol_read_needs_frame (symbol) && frame_info == NULL)
error (_("symbol requires a frame to compute its value"));
- value = read_var_value (symbol, frame_info);
+ /* TODO: currently, we have no way to recover the block in which SYMBOL
+ was found, so we have no block to pass to read_var_value. This will
+ yield an incorrect value when symbol is not local to FRAME_INFO (this
+ can happen with nested functions). */
+ value = read_var_value (symbol, NULL, frame_info);
}
CATCH (except, RETURN_MASK_ALL)
{
diff --git a/gdb/stack.c b/gdb/stack.c
index ae53ec8..6d87f6f 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -318,7 +318,7 @@ read_frame_local (struct symbol *sym, struct frame_info *frame,
TRY
{
- argp->val = read_var_value (sym, frame);
+ argp->val = read_var_value (sym, NULL, frame);
}
CATCH (except, RETURN_MASK_ERROR)
{
@@ -344,7 +344,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
{
TRY
{
- val = read_var_value (sym, frame);
+ val = read_var_value (sym, NULL, frame);
}
CATCH (except, RETURN_MASK_ERROR)
{
@@ -471,7 +471,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
TRY
{
- val = read_var_value (sym, frame);
+ val = read_var_value (sym, NULL, frame);
}
CATCH (except, RETURN_MASK_ERROR)
{
@@ -2424,7 +2424,7 @@ return_command (char *retval_exp, int from_tty)
value_fetch_lazy (return_value);
if (thisfun != NULL)
- function = read_var_value (thisfun, thisframe);
+ function = read_var_value (thisfun, NULL, thisframe);
rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index e67151f..c6f26e7 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -686,6 +686,25 @@ struct symbol_block_ops
uninitialized in such case. */
void (*find_frame_base_location) (struct symbol *framefunc, CORE_ADDR pc,
const gdb_byte **start, size_t *length);
+
+ /* Return the frame base address. FRAME is the frame for which we want to
+ compute the base address while FRAMEFUNC is the symbol for the
+ corresponding function. Return 0 on failure (FRAMEFUNC may not hold the
+ information we need).
+
+ This method is designed to work with static links (nested functions
+ handling). Static links are function properties whose evaluation returns
+ the frame base address for the enclosing frame. However, there are
+ multiple definitions for "frame base": the content of the frame base
+ register, the CFA as defined by DWARF unwinding information, ...
+
+ So this specific method is supposed to compute the frame base address such
+ as for nested fuctions, the static link computes the same address. For
+ instance, considering DWARF debugging information, the static link is
+ computed with DW_AT_static_link and this method must be used to compute
+ the corresponding DW_AT_frame_base attribute. */
+ CORE_ADDR (*get_frame_base) (struct symbol *framefunc,
+ struct frame_info *frame);
};
/* Functions used with LOC_REGISTER and LOC_REGPARM_ADDR. */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index bf7f1eb..15ad42c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2015-08-25 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * gdb.base/nested-subp1.exp: New file.
+ * gdb.base/nested-subp1.c: New file.
+ * gdb.base/nested-subp2.exp: New file.
+ * gdb.base/nested-subp2.c: New file.
+ * gdb.base/nested-subp3.exp: New file.
+ * gdb.base/nested-subp3.c: New file.
+
2015-08-24 Pedro Alves <palves@redhat.com>
* gdb.server/connect-without-multi-process.c: New file.
diff --git a/gdb/testsuite/gdb.base/nested-subp1.c b/gdb/testsuite/gdb.base/nested-subp1.c
new file mode 100644
index 0000000..967eb2f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.c
@@ -0,0 +1,37 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2015 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+foo (int i1)
+{
+ int
+ nested (int i2)
+ {
+ /* Here with i1 and i2, we can test that GDB can fetch both a local and a
+ non-local variable in the most simple nested function situation: the
+ parent block instance is accessible as the directly upper frame. */
+ return i1 * i2; /* STOP */
+ }
+
+ return nested (i1 + 1);
+}
+
+int
+main ()
+{
+ return !foo (1);
+}
diff --git a/gdb/testsuite/gdb.base/nested-subp1.exp b/gdb/testsuite/gdb.base/nested-subp1.exp
new file mode 100644
index 0000000..9720f5b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp1.exp
@@ -0,0 +1,55 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions related functionality.
+#
+
+standard_testfile
+
+
+set testcase "nested-subp1"
+
+if { [gdb_compile "${srcdir}/${subdir}/${testcase}.c" \
+ [standard_output_file "${testcase}"] \
+ "${testcase}" \
+ [list debug "additional_flags=-std=gnu99"]] != "" } {
+ return -1
+}
+
+
+# Run until the variables we are interested in are visible.
+
+clean_restart "${testcase}"
+if ![runto_main] {
+ perror "could not run to main"
+ continue
+}
+
+set bp_location [gdb_get_line_number "STOP" "${testcase}.c"]
+gdb_test "break ${testcase}.c:${bp_location}" \
+ "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
+ "breakpoint to the STOP marker"
+gdb_test "continue" \
+ "Breakpoint \[0-9\]+, nested .*" \
+ "continue to the STOP marker"
+
+
+# Check we get correct values for both local and non-local variable references.
+
+gdb_test "print i1" "1"
+gdb_test "print i2" "2"
diff --git a/gdb/testsuite/gdb.base/nested-subp2.c b/gdb/testsuite/gdb.base/nested-subp2.c
new file mode 100644
index 0000000..a6449e34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.c
@@ -0,0 +1,48 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2015 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+void
+iter_str (const char *str, void (*callback) (char c))
+{
+ for (; *str != '\0'; ++str)
+ callback (*str);
+}
+
+int
+length_str (const char *str)
+{
+ int count = 0;
+
+ void
+ increment (char c)
+ {
+ /* Here with COUNT, we can test that GDB can read a non-local variable even
+ though it's not directly in the upper stack frame. */
+ count += 1; /* STOP */
+ }
+
+ iter_str (str, &increment);
+ return count;
+}
+
+int
+main ()
+{
+ if (length_str ("foo") == 3)
+ return 0;
+ return 1;
+}
diff --git a/gdb/testsuite/gdb.base/nested-subp2.exp b/gdb/testsuite/gdb.base/nested-subp2.exp
new file mode 100644
index 0000000..a107d1c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp2.exp
@@ -0,0 +1,64 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions related functionality.
+#
+
+standard_testfile
+
+
+set testcase "nested-subp2"
+
+if { [gdb_compile "${srcdir}/${subdir}/${testcase}.c" \
+ [standard_output_file "${testcase}"] \
+ "${testcase}" \
+ [list debug "additional_flags=-std=gnu99"]] != "" } {
+ return -1
+}
+
+
+# Run until the variables we are interested in are visible.
+
+clean_restart "${testcase}"
+if ![runto_main] {
+ perror "could not run to main"
+ continue
+}
+
+set bp_location [gdb_get_line_number "STOP" "${testcase}.c"]
+gdb_test "break ${testcase}.c:${bp_location}" \
+ "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
+ "breakpoint to the STOP marker"
+gdb_test "continue" \
+ "Breakpoint \[0-9\]+, increment .*" \
+ "continue to the STOP marker"
+
+
+# Check we get correct values for both local and non-local variable references.
+
+gdb_test "print c" "102 'f'"
+gdb_test "print count" "0"
+
+
+# Same but a little later: make sure we were looking at the proper places.
+
+gdb_test "continue" \
+ "Breakpoint \[0-9\]+, increment .*" \
+ "continue to the STOP marker"
+gdb_test "print c" "111 'o'"
+gdb_test "print count" "1"
diff --git a/gdb/testsuite/gdb.base/nested-subp3.c b/gdb/testsuite/gdb.base/nested-subp3.c
new file mode 100644
index 0000000..a51f417
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.c
@@ -0,0 +1,66 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2015 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+typedef void (*callback_t) (void);
+
+extern void process (callback_t cb);
+extern void parent (int first, callback_t cb);
+
+void
+ignore (int unused)
+{
+ (void) unused;
+}
+
+void
+process (callback_t cb)
+{
+ parent (0, cb);
+}
+
+void
+parent (int first, callback_t cb)
+{
+ void child (void)
+ {
+ /* When reaching this, there are two block instances for PARENT on the
+ stack: the one that is right in the upper frame is not the one actually
+ used for non-local references, so GDB has to follow the static link in
+ order to get the correct instance, and thus in order to read the proper
+ variables.
+
+ As a simple check, we can verify that under GDB, the following is true:
+ parent_first == first (which should be one: see the IF block below). */
+ const int parent_first = first;
+ ignore (parent_first); /* STOP */
+ ignore (first);
+ }
+
+ if (first)
+ process (&child);
+ else
+ cb ();
+}
+
+int
+main ()
+{
+ parent (1, NULL);
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/nested-subp3.exp b/gdb/testsuite/gdb.base/nested-subp3.exp
new file mode 100644
index 0000000..8f9b522
--- /dev/null
+++ b/gdb/testsuite/gdb.base/nested-subp3.exp
@@ -0,0 +1,55 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+#
+# Test nested functions related functionality.
+#
+
+standard_testfile
+
+
+set testcase "nested-subp3"
+
+if { [gdb_compile "${srcdir}/${subdir}/${testcase}.c" \
+ [standard_output_file "${testcase}"] \
+ "${testcase}" \
+ [list debug "additional_flags=-std=gnu99"]] != "" } {
+ return -1
+}
+
+
+# Run until the variables we are interested in are visible.
+
+clean_restart "${testcase}"
+if ![runto_main] {
+ perror "could not run to main"
+ continue
+}
+
+set bp_location [gdb_get_line_number "STOP" "${testcase}.c"]
+gdb_test "break ${testcase}.c:${bp_location}" \
+ "Breakpoint \[0-9\]+ at 0x\[0-9a-fA-F\]+: .*" \
+ "breakpoint to the STOP marker"
+gdb_test "continue" \
+ "Breakpoint \[0-9\]+, child .*" \
+ "continue to the STOP marker"
+
+
+# Check we get correct values for both local and non-local variable references.
+
+gdb_test "print first" "1"
+gdb_test "print parent_first" "1"
diff --git a/gdb/valops.c b/gdb/valops.c
index acaf027..26fdfa6 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1291,27 +1291,12 @@ value_repeat (struct value *arg1, int count)
struct value *
value_of_variable (struct symbol *var, const struct block *b)
{
- struct frame_info *frame;
+ struct frame_info *frame = NULL;
- if (!symbol_read_needs_frame (var))
- frame = NULL;
- else if (!b)
+ if (symbol_read_needs_frame (var))
frame = get_selected_frame (_("No frame selected."));
- else
- {
- frame = block_innermost_frame (b);
- if (!frame)
- {
- if (BLOCK_FUNCTION (b) && !block_inlined_p (b)
- && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)))
- error (_("No frame is currently executing in block %s."),
- SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)));
- else
- error (_("No frame is currently executing in specified block"));
- }
- }
- return read_var_value (var, frame);
+ return read_var_value (var, b, frame);
}
struct value *
@@ -3463,9 +3448,9 @@ value_struct_elt_for_reference (struct type *domain, int offset,
return NULL;
if (want_address)
- return value_addr (read_var_value (s, 0));
+ return value_addr (read_var_value (s, 0, 0));
else
- return read_var_value (s, 0);
+ return read_var_value (s, 0, 0);
}
if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -3493,7 +3478,7 @@ value_struct_elt_for_reference (struct type *domain, int offset,
if (s == NULL)
return NULL;
- v = read_var_value (s, 0);
+ v = read_var_value (s, 0, 0);
if (!want_address)
result = v;
else
@@ -3729,7 +3714,7 @@ value_full_object (struct value *argp,
struct value *
value_of_this (const struct language_defn *lang)
{
- struct symbol *sym;
+ struct block_symbol sym;
const struct block *b;
struct frame_info *frame;
@@ -3740,12 +3725,12 @@ value_of_this (const struct language_defn *lang)
b = get_frame_block (frame, NULL);
- sym = lookup_language_this (lang, b).symbol;
- if (sym == NULL)
+ sym = lookup_language_this (lang, b);
+ if (sym.symbol == NULL)
error (_("current stack frame does not contain a variable named `%s'"),
lang->la_name_of_this);
- return read_var_value (sym, frame);
+ return read_var_value (sym.symbol, sym.block, frame);
}
/* Return the value of the local variable, if one exists. Return NULL
diff --git a/gdb/value.h b/gdb/value.h
index 82deaf2..0a4bc47 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -674,9 +674,11 @@ struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
extern int symbol_read_needs_frame (struct symbol *);
extern struct value *read_var_value (struct symbol *var,
+ const struct block *var_block,
struct frame_info *frame);
extern struct value *default_read_var_value (struct symbol *var,
+ const struct block *var_block,
struct frame_info *frame);
extern struct value *allocate_value (struct type *type);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 2edf8bd..7a0f074 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -1389,7 +1389,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
}
finish_block (newobj->name, &local_symbols, newobj->old_blocks,
- newobj->start_addr,
+ NULL, newobj->start_addr,
(fcn_cs_saved.c_value
+ fcn_aux_saved.x_sym.x_misc.x_fsize
+ ANOFFSET (objfile->section_offsets,
@@ -1480,7 +1480,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst)
if (local_symbols && context_stack_depth > 0)
{
/* Make a block for the local symbols within. */
- finish_block (newobj->name, &local_symbols, newobj->old_blocks,
+ finish_block (newobj->name, &local_symbols,
+ newobj->old_blocks, NULL,
newobj->start_addr,
(cs->c_value
+ ANOFFSET (objfile->section_offsets,