2004-08-24 Jim Blandy <jimb@redhat.com>
+ * dwarf2expr.h (struct dwarf_expr_context): New members
+ 'num_pieces' and 'pieces', for returning the result of an
+ expression that uses DW_OP_piece.
+ (struct dwarf_expr_piece): New struct type.
+ * dwarf2expr.c (new_dwarf_expr_context): Initialize num_pieces and
+ pieces.
+ (free_dwarf_expr_context): Free pieces, if any.
+ (add_piece): New function.
+ (execute_stack_op): Implement DW_OP_piece.
+ * dwarf2loc.c (dwarf2_evaluate_loc_desc): If the result of the
+ expression is a list of pieces, print an error message.
+ (dwarf2_loc_desc_needs_frame): If the expression yields
+ pieces, and any piece is in a register, then we need a frame.
+
* dwarf2loc.c (dwarf2_evaluate_loc_desc): Wait to fetch the top of
the stack until we've decided what sort of result the evaluation
has produced. Use separate variables, with more specific names.
retval->stack_len = 0;
retval->stack_allocated = 10;
retval->stack = xmalloc (retval->stack_allocated * sizeof (CORE_ADDR));
+ retval->num_pieces = 0;
+ retval->pieces = 0;
return retval;
}
free_dwarf_expr_context (struct dwarf_expr_context *ctx)
{
xfree (ctx->stack);
+ xfree (ctx->pieces);
xfree (ctx);
}
}
+/* Add a new piece to CTX's piece list. */
+static void
+add_piece (struct dwarf_expr_context *ctx,
+ int in_reg, CORE_ADDR value, ULONGEST size)
+{
+ struct dwarf_expr_piece *p;
+
+ ctx->num_pieces++;
+
+ if (ctx->pieces)
+ ctx->pieces = xrealloc (ctx->pieces,
+ (ctx->num_pieces
+ * sizeof (struct dwarf_expr_piece)));
+ else
+ ctx->pieces = xmalloc (ctx->num_pieces
+ * sizeof (struct dwarf_expr_piece));
+
+ p = &ctx->pieces[ctx->num_pieces - 1];
+ p->in_reg = in_reg;
+ p->value = value;
+ p->size = size;
+}
+
/* Evaluate the expression at ADDR (LEN bytes long) using the context
CTX. */
case DW_OP_nop:
goto no_push;
+ case DW_OP_piece:
+ {
+ ULONGEST size;
+ CORE_ADDR addr_or_regnum;
+
+ /* Record the piece. */
+ op_ptr = read_uleb128 (op_ptr, op_end, &size);
+ addr_or_regnum = dwarf_expr_fetch (ctx, 0);
+ add_piece (ctx, ctx->in_reg, addr_or_regnum, size);
+
+ /* Pop off the address/regnum, and clear the in_reg flag. */
+ dwarf_expr_pop (ctx);
+ ctx->in_reg = 0;
+ }
+ goto no_push;
+
default:
error ("Unhandled dwarf expression opcode 0x%x", op);
}
/* Non-zero if the result is in a register. The register number
will be on the expression stack. */
int in_reg;
+
+ /* An array of pieces. PIECES points to its first element;
+ NUM_PIECES is its length.
+
+ Each time DW_OP_piece is executed, we add a new element to the
+ end of this array, recording the current top of the stack, the
+ current in_reg flag, and the size given as the operand to
+ DW_OP_piece. We then pop the top value from the stack, clear the
+ in_reg flag, and resume evaluation.
+
+ The Dwarf spec doesn't say whether DW_OP_piece pops the top value
+ from the stack. We do, ensuring that clients of this interface
+ expecting to see a value left on the top of the stack (say, code
+ evaluating frame base expressions or CFA's specified with
+ DW_CFA_def_cfa_expression) will get an error if the expression
+ actually marks all the values it computes as pieces.
+
+ If an expression never uses DW_OP_piece, num_pieces will be zero.
+ (It would be nice to present these cases as expressions yielding
+ a single piece, with in_reg clear, so that callers need not
+ distinguish between the no-DW_OP_piece and one-DW_OP_piece cases.
+ But expressions with no DW_OP_piece operations have no value to
+ place in a piece's 'size' field; the size comes from the
+ surrounding data. So the two cases need to be handled
+ separately.) */
+ int num_pieces;
+ struct dwarf_expr_piece *pieces;
+};
+
+
+/* A piece of an object, as recorded by DW_OP_piece. */
+struct dwarf_expr_piece
+{
+ /* If IN_REG is zero, then the piece is in memory, and VALUE is its address.
+ If IN_REG is non-zero, then the piece is in a register, and VALUE
+ is the register number. */
+ int in_reg;
+
+ /* This piece's address or register number. */
+ CORE_ADDR value;
+
+ /* The length of the piece, in bytes. */
+ ULONGEST size;
};
struct dwarf_expr_context *new_dwarf_expr_context (void);
unsigned char *data, unsigned short size,
struct objfile *objfile)
{
+ struct gdbarch *arch = get_frame_arch (frame);
struct value *retval;
struct dwarf_expr_baton baton;
struct dwarf_expr_context *ctx;
ctx->get_tls_address = dwarf_expr_tls_address;
dwarf_expr_eval (ctx, data, size);
-
- if (ctx->in_reg)
+ if (ctx->num_pieces > 0)
+ {
+ /* We haven't implemented splicing together pieces from
+ arbitrary sources yet. */
+ error ("The value of variable '%s' is distributed across several\n"
+ "locations, and GDB cannot access its value.\n",
+ SYMBOL_NATURAL_NAME (var));
+ }
+ else if (ctx->in_reg)
{
CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0);
int gdb_regnum = DWARF2_REG_TO_REGNUM (dwarf_regnum);
in_reg = ctx->in_reg;
+ if (ctx->num_pieces > 0)
+ {
+ int i;
+
+ /* If the location has several pieces, and any of them are in
+ registers, then we will need a frame to fetch them from. */
+ for (i = 0; i < ctx->num_pieces; i++)
+ if (ctx->pieces[i].in_reg)
+ in_reg = 1;
+ }
+
free_dwarf_expr_context (ctx);
return baton.needs_frame || in_reg;