aboutsummaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorPierre-Marie de Rodat <derodat@adacore.com>2015-02-05 17:00:06 +0100
committerPierre-Marie de Rodat <derodat@adacore.com>2015-08-25 08:13:28 -0400
commit63e43d3aedb8b1112899c2d0ad74cbbee687e5d6 (patch)
tree9e35fea0ccd74ee5d2d27bc7fe957ec19c360dbb /gdb/python
parent7c2bea1ad1c779b893eb9cad4c92732583ae0eb5 (diff)
downloadgdb-63e43d3aedb8b1112899c2d0ad74cbbee687e5d6.zip
gdb-63e43d3aedb8b1112899c2d0ad74cbbee687e5d6.tar.gz
gdb-63e43d3aedb8b1112899c2d0ad74cbbee687e5d6.tar.bz2
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.
Diffstat (limited to 'gdb/python')
-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
4 files changed, 31 insertions, 15 deletions
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)
{