From 400c6af0377b41453355299e9393a52263f4a834 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Wed, 17 Mar 2010 22:04:43 +0000 Subject: [PATCH] 2010-03-17 Stan Shebs * ax-gdb.h (struct axs_value): New field optimized_out. (gen_trace_for_var): Add gdbarch argument. * ax-gdb.c (gen_trace_static_fields): New function. (gen_traced_pop): Call it, add gdbarch argument. (gen_trace_for_expr): Update call to it. (gen_trace_for_var): Ditto, and report optimized-out variables. (gen_struct_ref_recursive): Check for optimized-out value. (gen_struct_elt_for_reference): Ditto. (gen_static_field): Pass gdbarch instead of expression, assume optimization if field not found. (gen_var_ref): Set the optimized_out flag. (gen_expr): Error on optimized-out variable. * tracepoint.c (collect_symbol): Handle struct-valued vars as expressions, skip optimized-out variables with computed locations. * dwarf2loc.c (dwarf2_tracepoint_var_ref): Flag instead of erroring out if location expression missing. (loclist_tracepoint_var_ref): Don't error out here. --- gdb/ChangeLog | 20 +++++++++ gdb/ax-gdb.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++------- gdb/ax-gdb.h | 7 ++- gdb/dwarf2loc.c | 12 +++-- gdb/tracepoint.c | 103 +++++++++++++++++++++++++----------------- 5 files changed, 210 insertions(+), 66 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index da6e1f8..af86e48 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +2010-03-17 Stan Shebs + + * ax-gdb.h (struct axs_value): New field optimized_out. + (gen_trace_for_var): Add gdbarch argument. + * ax-gdb.c (gen_trace_static_fields): New function. + (gen_traced_pop): Call it, add gdbarch argument. + (gen_trace_for_expr): Update call to it. + (gen_trace_for_var): Ditto, and report optimized-out variables. + (gen_struct_ref_recursive): Check for optimized-out value. + (gen_struct_elt_for_reference): Ditto. + (gen_static_field): Pass gdbarch instead of expression, assume + optimization if field not found. + (gen_var_ref): Set the optimized_out flag. + (gen_expr): Error on optimized-out variable. + * tracepoint.c (collect_symbol): Handle struct-valued vars as + expressions, skip optimized-out variables with computed locations. + * dwarf2loc.c (dwarf2_tracepoint_var_ref): Flag instead of + erroring out if location expression missing. + (loclist_tracepoint_var_ref): Don't error out here. + 2010-03-17 Tom Tromey * dwarf2read.c (dwarf2_get_section_info): Handle case where no diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c index 0e95bdf..091fd95 100644 --- a/gdb/ax-gdb.c +++ b/gdb/ax-gdb.c @@ -70,7 +70,7 @@ static struct value *const_var_ref (struct symbol *var); static struct value *const_expr (union exp_element **pc); static struct value *maybe_const_expr (union exp_element **pc); -static void gen_traced_pop (struct agent_expr *, struct axs_value *); +static void gen_traced_pop (struct gdbarch *, struct agent_expr *, struct axs_value *); static void gen_sign_extend (struct agent_expr *, struct type *); static void gen_extend (struct agent_expr *, struct type *); @@ -144,7 +144,7 @@ static void gen_struct_ref (struct expression *exp, struct agent_expr *ax, struct axs_value *value, char *field, char *operator_name, char *operand_name); -static void gen_static_field (struct expression *exp, +static void gen_static_field (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value, struct type *type, int fieldno); static void gen_repeat (struct expression *exp, union exp_element **pc, @@ -331,11 +331,64 @@ maybe_const_expr (union exp_element **pc) emits the trace bytecodes at the appropriate points. */ static int trace_kludge; +/* Scan for all static fields in the given class, including any base + classes, and generate tracing bytecodes for each. */ + +static void +gen_trace_static_fields (struct gdbarch *gdbarch, + struct agent_expr *ax, + struct type *type) +{ + int i, nbases = TYPE_N_BASECLASSES (type); + struct axs_value value; + + CHECK_TYPEDEF (type); + + for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--) + { + if (field_is_static (&TYPE_FIELD (type, i))) + { + gen_static_field (gdbarch, ax, &value, type, i); + if (value.optimized_out) + continue; + switch (value.kind) + { + case axs_lvalue_memory: + { + int length = TYPE_LENGTH (check_typedef (value.type)); + + ax_const_l (ax, length); + ax_simple (ax, aop_trace); + } + break; + + case axs_lvalue_register: + /* We need to mention the register somewhere in the bytecode, + so ax_reqs will pick it up and add it to the mask of + registers used. */ + ax_reg (ax, value.u.reg); + + default: + break; + } + } + } + + /* Now scan through base classes recursively. */ + for (i = 0; i < nbases; i++) + { + struct type *basetype = check_typedef (TYPE_BASECLASS (type, i)); + + gen_trace_static_fields (gdbarch, ax, basetype); + } +} + /* Trace the lvalue on the stack, if it needs it. In either case, pop the value. Useful on the left side of a comma, and at the end of an expression being used for tracing. */ static void -gen_traced_pop (struct agent_expr *ax, struct axs_value *value) +gen_traced_pop (struct gdbarch *gdbarch, + struct agent_expr *ax, struct axs_value *value) { if (trace_kludge) switch (value->kind) @@ -371,6 +424,12 @@ gen_traced_pop (struct agent_expr *ax, struct axs_value *value) else /* If we're not tracing, just pop the value. */ ax_simple (ax, aop_pop); + + /* To trace C++ classes with static fields stored elsewhere. */ + if (trace_kludge + && (TYPE_CODE (value->type) == TYPE_CODE_STRUCT + || TYPE_CODE (value->type) == TYPE_CODE_UNION)) + gen_trace_static_fields (gdbarch, ax, value->type); } @@ -554,6 +613,7 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax, { /* Dereference any typedefs. */ value->type = check_typedef (SYMBOL_TYPE (var)); + value->optimized_out = 0; /* I'm imitating the code in read_var_value. */ switch (SYMBOL_CLASS (var)) @@ -650,8 +710,9 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax, break; case LOC_OPTIMIZED_OUT: - error (_("The variable `%s' has been optimized out."), - SYMBOL_PRINT_NAME (var)); + /* Flag this, but don't say anything; leave it up to callers to + warn the user. */ + value->optimized_out = 1; break; default: @@ -1342,7 +1403,10 @@ gen_struct_ref_recursive (struct expression *exp, struct agent_expr *ax, being handled as a global. */ if (field_is_static (&TYPE_FIELD (type, i))) { - gen_static_field (exp, ax, value, type, i); + gen_static_field (exp->gdbarch, ax, value, type, i); + if (value->optimized_out) + error (_("static field `%s' has been optimized out, cannot use"), + field); return 1; } @@ -1425,7 +1489,7 @@ gen_maybe_namespace_elt (struct expression *exp, const struct type *curtype, char *name); static void -gen_static_field (struct expression *exp, +gen_static_field (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value, struct type *type, int fieldno) { @@ -1434,15 +1498,27 @@ gen_static_field (struct expression *exp, ax_const_l (ax, TYPE_FIELD_STATIC_PHYSADDR (type, fieldno)); value->kind = axs_lvalue_memory; value->type = TYPE_FIELD_TYPE (type, fieldno); + value->optimized_out = 0; } else { char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno); struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0); - if (sym == NULL) - error (_("symbol not found")); - gen_var_ref (exp->gdbarch, ax, value, sym); + if (sym) + { + gen_var_ref (gdbarch, ax, value, sym); + + /* Don't error if the value was optimized out, we may be + scanning all static fields and just want to pass over this + and continue with the rest. */ + } + else + { + /* Silently assume this was optimized out; class printing + will let the user know why the data is missing. */ + value->optimized_out = 1; + } } } @@ -1468,7 +1544,10 @@ gen_struct_elt_for_reference (struct expression *exp, { if (field_is_static (&TYPE_FIELD (t, i))) { - gen_static_field (exp, ax, value, t, i); + gen_static_field (exp->gdbarch, ax, value, t, i); + if (value->optimized_out) + error (_("static field `%s' has been optimized out, cannot use"), + fieldname); return 1; } if (TYPE_FIELD_PACKED (t, i)) @@ -1526,6 +1605,10 @@ gen_maybe_namespace_elt (struct expression *exp, gen_var_ref (exp->gdbarch, ax, value, sym); + if (value->optimized_out) + error (_("`%s' has been optimized out, cannot use"), + SYMBOL_PRINT_NAME (sym)); + return 1; } @@ -1815,7 +1898,7 @@ gen_expr (struct expression *exp, union exp_element **pc, /* Don't just dispose of the left operand. We might be tracing, in which case we want to emit code to trace it if it's an lvalue. */ - gen_traced_pop (ax, &value1); + gen_traced_pop (exp->gdbarch, ax, &value1); gen_expr (exp, pc, ax, value); /* It's the consumer's responsibility to trace the right operand. */ break; @@ -1831,6 +1914,11 @@ gen_expr (struct expression *exp, union exp_element **pc, case OP_VAR_VALUE: gen_var_ref (exp->gdbarch, ax, value, (*pc)[2].symbol); + + if (value->optimized_out) + error (_("`%s' has been optimized out, cannot use"), + SYMBOL_PRINT_NAME ((*pc)[2].symbol)); + (*pc) += 4; break; @@ -2004,6 +2092,11 @@ gen_expr (struct expression *exp, union exp_element **pc, error (_("no `%s' found"), this_name); gen_var_ref (exp->gdbarch, ax, value, sym); + + if (value->optimized_out) + error (_("`%s' has been optimized out, cannot use"), + SYMBOL_PRINT_NAME (sym)); + (*pc) += 2; } break; @@ -2199,7 +2292,8 @@ cannot subscript requested type: cannot call user defined functions")); name comes from a list of local variables of a function. */ struct agent_expr * -gen_trace_for_var (CORE_ADDR scope, struct symbol *var) +gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch, + struct symbol *var) { struct cleanup *old_chain = 0; struct agent_expr *ax = new_agent_expr (scope); @@ -2208,10 +2302,18 @@ gen_trace_for_var (CORE_ADDR scope, struct symbol *var) old_chain = make_cleanup_free_agent_expr (ax); trace_kludge = 1; - gen_var_ref (NULL, ax, &value, var); + gen_var_ref (gdbarch, ax, &value, var); + + /* If there is no actual variable to trace, flag it by returning + an empty agent expression. */ + if (value.optimized_out) + { + do_cleanups (old_chain); + return NULL; + } /* Make sure we record the final object, and get rid of it. */ - gen_traced_pop (ax, &value); + gen_traced_pop (gdbarch, ax, &value); /* Oh, and terminate. */ ax_simple (ax, aop_end); @@ -2245,7 +2347,7 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr) gen_expr (expr, &pc, ax, &value); /* Make sure we record the final object, and get rid of it. */ - gen_traced_pop (ax, &value); + gen_traced_pop (expr->gdbarch, ax, &value); /* Oh, and terminate. */ ax_simple (ax, aop_end); diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h index a5f3768..4ec21e1 100644 --- a/gdb/ax-gdb.h +++ b/gdb/ax-gdb.h @@ -81,6 +81,10 @@ struct axs_value "pointer to" an object of this type. */ struct type *type; + /* If nonzero, this is a variable which does not actually exist in + the program. */ + char optimized_out; + union { /* if kind == axs_lvalue_register, this is the register number */ @@ -99,7 +103,8 @@ struct axs_value function to discover which registers the expression uses. */ extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *); -extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct symbol *); +extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct gdbarch *, + struct symbol *); extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *); diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 20ede3e..ed7dfb9 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -619,11 +619,11 @@ dwarf2_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value, gdb_byte *data, int size) { - if (size == 0) - error (_("Symbol \"%s\" has been optimized out."), - SYMBOL_PRINT_NAME (symbol)); - - if (size == 1 + if (!data || size == 0) + { + value->optimized_out = 1; + } + else if (size == 1 && data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31) { @@ -883,8 +883,6 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch, size_t size; data = find_location_expression (dlbaton, &size, ax->scope); - if (data == NULL) - error (_("Variable \"%s\" is not available."), SYMBOL_NATURAL_NAME (symbol)); dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value, data, size); } diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index e1679fa..b621334 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -949,6 +949,7 @@ collect_symbol (struct collection_list *collect, unsigned long len; unsigned int reg; bfd_signed_vma offset; + int treat_as_expr = 0; len = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym))); switch (SYMBOL_CLASS (sym)) @@ -973,7 +974,12 @@ collect_symbol (struct collection_list *collect, SYMBOL_PRINT_NAME (sym), len, tmp /* address */); } - add_memrange (collect, memrange_absolute, offset, len); + /* A struct may be a C++ class with static fields, go to general + expression handling. */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT) + treat_as_expr = 1; + else + add_memrange (collect, memrange_absolute, offset, len); break; case LOC_REGISTER: reg = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch); @@ -1038,49 +1044,62 @@ collect_symbol (struct collection_list *collect, break; case LOC_COMPUTED: - { - struct agent_expr *aexpr; - struct cleanup *old_chain1 = NULL; - struct agent_reqs areqs; - - aexpr = gen_trace_for_var (scope, sym); - - old_chain1 = make_cleanup_free_agent_expr (aexpr); - - ax_reqs (aexpr, &areqs); - if (areqs.flaw != agent_flaw_none) - error (_("malformed expression")); - - if (areqs.min_height < 0) - error (_("gdb: Internal error: expression has min height < 0")); - if (areqs.max_height > 20) - error (_("expression too complicated, try simplifying")); - - discard_cleanups (old_chain1); - add_aexpr (collect, aexpr); - - /* take care of the registers */ - if (areqs.reg_mask_len > 0) - { - int ndx1, ndx2; - - for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) - { - QUIT; /* allow user to bail out with ^C */ - if (areqs.reg_mask[ndx1] != 0) - { - /* assume chars have 8 bits */ - for (ndx2 = 0; ndx2 < 8; ndx2++) - if (areqs.reg_mask[ndx1] & (1 << ndx2)) - /* it's used -- record it */ - add_register (collect, - ndx1 * 8 + ndx2); - } - } - } - } + treat_as_expr = 1; break; } + + /* Expressions are the most general case. */ + if (treat_as_expr) + { + struct agent_expr *aexpr; + struct cleanup *old_chain1 = NULL; + struct agent_reqs areqs; + + aexpr = gen_trace_for_var (scope, gdbarch, sym); + + /* It can happen that the symbol is recorded as a computed + location, but it's been optimized away and doesn't actually + have a location expression. */ + if (!aexpr) + { + printf_filtered ("%s has been optimized out of existence.\n", + SYMBOL_PRINT_NAME (sym)); + return; + } + + old_chain1 = make_cleanup_free_agent_expr (aexpr); + + ax_reqs (aexpr, &areqs); + if (areqs.flaw != agent_flaw_none) + error (_("malformed expression")); + + if (areqs.min_height < 0) + error (_("gdb: Internal error: expression has min height < 0")); + if (areqs.max_height > 20) + error (_("expression too complicated, try simplifying")); + + discard_cleanups (old_chain1); + add_aexpr (collect, aexpr); + + /* take care of the registers */ + if (areqs.reg_mask_len > 0) + { + int ndx1, ndx2; + + for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) + { + QUIT; /* allow user to bail out with ^C */ + if (areqs.reg_mask[ndx1] != 0) + { + /* assume chars have 8 bits */ + for (ndx2 = 0; ndx2 < 8; ndx2++) + if (areqs.reg_mask[ndx1] & (1 << ndx2)) + /* it's used -- record it */ + add_register (collect, ndx1 * 8 + ndx2); + } + } + } + } } /* Add all locals (or args) symbols to collection list */ -- 2.7.4