aboutsummaryrefslogtreecommitdiff
path: root/gdb/eval.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2017-09-04 20:21:15 +0100
committerPedro Alves <palves@redhat.com>2017-09-04 20:21:15 +0100
commit46a4882b3c7d9ec981568b8b13a3c9c39c8f8e61 (patch)
tree77ce5110d97ebc03e6aefd50bab539e4fcb037f5 /gdb/eval.c
parentfe13dfecbf7d5a9ba3a5d9f52e33e0ddacb39bcc (diff)
downloadfsf-binutils-gdb-46a4882b3c7d9ec981568b8b13a3c9c39c8f8e61.zip
fsf-binutils-gdb-46a4882b3c7d9ec981568b8b13a3c9c39c8f8e61.tar.gz
fsf-binutils-gdb-46a4882b3c7d9ec981568b8b13a3c9c39c8f8e61.tar.bz2
Stop assuming no-debug-info variables have type int
An earlier commit made GDB no longer assume no-debug-info functions return int. This commit gives the same treatment to variables. Currently, you can end misled by GDB over output like this: (gdb) p var $1 = -1 (gdb) p /x var $2 = 0xffffffff until you realize that GDB is assuming that the variable is an "int", because: (gdb) ptype var type = <data variable, no debug info> You may try to fix it by casting, but that doesn't really help: (gdb) p /x (unsigned long long) var $3 = 0xffffffffffffffff # incorrect ^^ That's incorrect output, because the variable was defined like this: uint64_t var = 0x7fffffffffffffff; ^^ What happened is that with the cast, GDB did an int -> 'unsigned long long' conversion instead of reinterpreting the variable as the cast-to type. To get at the variable properly you have to reinterpret the variable's address manually instead, with either: (gdb) p /x *(unsigned long long *) &var $4 = 0x7fffffffffffffff (gdb) p /x {unsigned long long} &var $5 = 0x7fffffffffffffff After this commit GDB does it for you. This is what you'll get instead: (gdb) p var 'var' has unknown type; cast it to its declared type (gdb) p /x (unsigned long long) var $1 = 0x7fffffffffffffff As in the functions patch, the "compile" machinery doesn't currently have the cast-to type handy, so it continues assuming no-debug variables have int type, though now at least it warns. The change to gdb.cp/m-static.exp deserves an explanation: - gdb_test "print 'gnu_obj_1::method()::sintvar'" "\\$\[0-9\]+ = 4" \ + gdb_test "print (int) 'gnu_obj_1::method()::sintvar'" "\\$\[0-9\]+ = 4" \ That's printing the "sintvar" function local static of the "gnu_obj_1::method()" method. The problem with that test is that that "'S::method()::static_var'" syntax doesn't really work in C++ as you'd expect. The way to make it work correctly currently is to quote the method part, not the whole expression, like: (gdb) print 'gnu_obj_1::method()'::sintvar If you wrap the whole expression in quotes, like in m-static.exp, what really happens is that the parser considers the whole string as a symbol name, but there's no debug symbol with that name. However, local statics have linkage and are given a mangled name that demangles to the same string as the full expression, so that's what GDB prints. After this commit, and without the cast, the print in m-static.exp would error out saying that the variable has unknown type: (gdb) p 'gnu_obj_1::method()::sintvar' 'gnu_obj_1::method()::sintvar' has unknown type; cast it to its declared type TBC, if currently (even before this series) you try to print any function local static variable of type other than int, you'll get bogus results. You can see that with m-static.cc as is, even. Printing the "svar" local, which is a boolean (1 byte) still prints as "int" (4 bytes): (gdb) p 'gnu_obj_1::method()::svar' $1 = 1 (gdb) ptype 'gnu_obj_1::method()::svar' type = <data variable, no debug info> This probably prints some random bogus value on big endian machines. If 'svar' was of some aggregate type (etc.) we'd still print it as int, so the problem would have been more obvious... After this commit, you'll get instead: (gdb) p 'gnu_obj_1::method()::svar' 'gnu_obj_1::method()::svar' has unknown type; cast it to its declared type ... so at least GDB is no longer misleading. Making GDB find the real local static debug symbol is the subject of the following patches. In the end, it'll all "Just Work". gdb/ChangeLog: 2017-09-04 Pedro Alves <palves@redhat.com> * ax-gdb.c: Include "typeprint.h". (gen_expr_for_cast): New function. (gen_expr) <OP_CAST, OP_CAST_TYPE>: Use it. <OP_VAR_VALUE, OP_MSYM_VAR_VALUE>: Error out if the variable's type is unknown. * dwarf2read.c (new_symbol_full): Fallback to int instead of nodebug_data_symbol. * eval.c: Include "typeprint.h". (evaluate_subexp_standard) <OP_VAR_VALUE, OP_VAR_MSYM_VALUE>: Error out if symbol has unknown type. <UNOP_CAST, UNOP_CAST_TYPE>: Common bits factored out to evaluate_subexp_for_cast. (evaluate_subexp_for_address, evaluate_subexp_for_sizeof): Handle OP_VAR_MSYM_VALUE. (evaluate_subexp_for_cast): New function. * gdbtypes.c (init_nodebug_var_type): New function. (objfile_type): Use it to initialize types of variables with no debug info. * typeprint.c (error_unknown_type): New. * typeprint.h (error_unknown_type): New declaration. * compile/compile-c-types.c (convert_type_basic): Handle TYPE_CODE_ERROR; warn and fallback to int for variables with unknown type. gdb/testsuite/ChangeLog: 2017-09-04 Pedro Alves <palves@redhat.com> * gdb.asm/asm-source.exp: Add casts to int. * gdb.base/nodebug.c (dataglobal8, dataglobal32_1, dataglobal32_2) (dataglobal64_1, dataglobal64_2): New globals. * gdb.base/nodebug.exp: Test different expressions involving the new globals, with print, whatis and ptype. Add casts to int. * gdb.base/solib-display.exp: Add casts to int. * gdb.compile/compile-ifunc.exp: Expect warning. Add cast to int. * gdb.cp/m-static.exp: Add cast to int. * gdb.dwarf2/dw2-skip-prologue.exp: Add cast to int. * gdb.threads/tls-nodebug.exp: Check that gdb errors out printing tls variable with no debug info without a cast. Test with a cast to int too. * gdb.trace/entry-values.exp: Add casts.
Diffstat (limited to 'gdb/eval.c')
-rw-r--r--gdb/eval.c137
1 files changed, 118 insertions, 19 deletions
diff --git a/gdb/eval.c b/gdb/eval.c
index a97f4a9..75d3c86 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -39,6 +39,7 @@
#include "valprint.h"
#include "gdb_obstack.h"
#include "objfiles.h"
+#include "typeprint.h"
#include <ctype.h>
/* This is defined in valops.c */
@@ -52,6 +53,10 @@ static struct value *evaluate_subexp_for_sizeof (struct expression *, int *,
static struct value *evaluate_subexp_for_address (struct expression *,
int *, enum noside);
+static value *evaluate_subexp_for_cast (expression *exp, int *pos,
+ enum noside noside,
+ struct type *type);
+
static struct value *evaluate_struct_tuple (struct value *,
struct expression *, int *,
enum noside, int);
@@ -796,14 +801,30 @@ evaluate_subexp_standard (struct type *expect_type,
(*pos) += 3;
if (noside == EVAL_SKIP)
return eval_skip_value (exp);
- return evaluate_var_value (noside,
- exp->elts[pc + 1].block,
- exp->elts[pc + 2].symbol);
+
+ {
+ symbol *var = exp->elts[pc + 2].symbol;
+ if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_ERROR)
+ error_unknown_type (SYMBOL_PRINT_NAME (var));
+
+ return evaluate_var_value (noside, exp->elts[pc + 1].block, var);
+ }
+
case OP_VAR_MSYM_VALUE:
- (*pos) += 3;
- return evaluate_var_msym_value (noside,
- exp->elts[pc + 1].objfile,
- exp->elts[pc + 2].msymbol);
+ {
+ (*pos) += 3;
+
+ minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
+ value *val = evaluate_var_msym_value (noside,
+ exp->elts[pc + 1].objfile,
+ msymbol);
+
+ type = value_type (val);
+ if (TYPE_CODE (type) == TYPE_CODE_ERROR
+ && (noside != EVAL_AVOID_SIDE_EFFECTS || pc != 0))
+ error_unknown_type (MSYMBOL_PRINT_NAME (msymbol));
+ return val;
+ }
case OP_VAR_ENTRY_VALUE:
(*pos) += 2;
@@ -2589,22 +2610,12 @@ evaluate_subexp_standard (struct type *expect_type,
case UNOP_CAST:
(*pos) += 2;
type = exp->elts[pc + 1].type;
- arg1 = evaluate_subexp (type, exp, pos, noside);
- if (noside == EVAL_SKIP)
- return eval_skip_value (exp);
- if (type != value_type (arg1))
- arg1 = value_cast (type, arg1);
- return arg1;
+ return evaluate_subexp_for_cast (exp, pos, noside, type);
case UNOP_CAST_TYPE:
arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
type = value_type (arg1);
- arg1 = evaluate_subexp (type, exp, pos, noside);
- if (noside == EVAL_SKIP)
- return eval_skip_value (exp);
- if (type != value_type (arg1))
- arg1 = value_cast (type, arg1);
- return arg1;
+ return evaluate_subexp_for_cast (exp, pos, noside, type);
case UNOP_DYNAMIC_CAST:
arg1 = evaluate_subexp (NULL, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
@@ -2927,6 +2938,22 @@ evaluate_subexp_for_address (struct expression *exp, int *pos,
else
return address_of_variable (var, exp->elts[pc + 1].block);
+ case OP_VAR_MSYM_VALUE:
+ {
+ (*pos) += 4;
+
+ value *val = evaluate_var_msym_value (noside,
+ exp->elts[pc + 1].objfile,
+ exp->elts[pc + 2].msymbol);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ {
+ struct type *type = lookup_pointer_type (value_type (val));
+ return value_zero (type, not_lval);
+ }
+ else
+ return value_addr (val);
+ }
+
case OP_SCOPE:
tem = longest_to_int (exp->elts[pc + 2].longconst);
(*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1);
@@ -3065,6 +3092,23 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos,
(*pos) += 4;
break;
+ case OP_VAR_MSYM_VALUE:
+ {
+ (*pos) += 4;
+
+ minimal_symbol *msymbol = exp->elts[pc + 2].msymbol;
+ value *val = evaluate_var_msym_value (noside,
+ exp->elts[pc + 1].objfile,
+ msymbol);
+
+ type = value_type (val);
+ if (TYPE_CODE (type) == TYPE_CODE_ERROR)
+ error_unknown_type (MSYMBOL_PRINT_NAME (msymbol));
+
+ return value_from_longest (size_type, TYPE_LENGTH (type));
+ }
+ break;
+
/* Deal with the special case if NOSIDE is EVAL_NORMAL and the resulting
type of the subscript is a variable length array type. In this case we
must re-evaluate the right hand side of the subcription to allow
@@ -3112,6 +3156,61 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos,
return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
}
+/* Evaluate a subexpression of EXP, at index *POS, and return a value
+ for that subexpression cast to TO_TYPE. Advance *POS over the
+ subexpression. */
+
+static value *
+evaluate_subexp_for_cast (expression *exp, int *pos,
+ enum noside noside,
+ struct type *to_type)
+{
+ int pc = *pos;
+
+ /* Don't let symbols be evaluated with evaluate_subexp because that
+ throws an "unknown type" error for no-debug data symbols.
+ Instead, we want the cast to reinterpret the symbol. */
+ if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE
+ || exp->elts[pc].opcode == OP_VAR_VALUE)
+ {
+ (*pos) += 4;
+
+ value *val;
+ if (exp->elts[pc].opcode == OP_VAR_MSYM_VALUE)
+ {
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (to_type, not_lval);
+
+ val = evaluate_var_msym_value (noside,
+ exp->elts[pc + 1].objfile,
+ exp->elts[pc + 2].msymbol);
+ }
+ else
+ val = evaluate_var_value (noside,
+ exp->elts[pc + 1].block,
+ exp->elts[pc + 2].symbol);
+
+ if (noside == EVAL_SKIP)
+ return eval_skip_value (exp);
+
+ val = value_cast (to_type, val);
+
+ /* Don't allow e.g. '&(int)var_with_no_debug_info'. */
+ if (VALUE_LVAL (val) == lval_memory)
+ {
+ if (value_lazy (val))
+ value_fetch_lazy (val);
+ VALUE_LVAL (val) = not_lval;
+ }
+ return val;
+ }
+
+ value *val = evaluate_subexp (to_type, exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ return eval_skip_value (exp);
+ return value_cast (to_type, val);
+}
+
/* Parse a type expression in the string [P..P+LENGTH). */
struct type *