-/* Dwarf2 Expression Evaluator
- Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+/* DWARF 2 Expression Evaluator.
+
+ Copyright (C) 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+
Contributed by Daniel Berlin (dan@dberlin.org)
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "symtab.h"
/* Local prototypes. */
static void execute_stack_op (struct dwarf_expr_context *,
- unsigned char *, unsigned char *);
+ gdb_byte *, gdb_byte *);
+static struct type *unsigned_address_type (void);
/* Create a new context for the expression evaluator. */
{
struct dwarf_expr_context *retval;
retval = xcalloc (1, sizeof (struct dwarf_expr_context));
- retval->stack_len = 10;
- retval->stack = xmalloc (10 * sizeof (CORE_ADDR));
+ 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);
}
{
if (ctx->stack_len + need > ctx->stack_allocated)
{
- size_t templen = ctx->stack_len * 2;
- while (templen < (ctx->stack_len + need))
- templen *= 2;
+ size_t newlen = ctx->stack_len + need + 10;
ctx->stack = xrealloc (ctx->stack,
- templen * sizeof (CORE_ADDR));
- ctx->stack_allocated = templen;
+ newlen * sizeof (CORE_ADDR));
+ ctx->stack_allocated = newlen;
}
}
dwarf_expr_pop (struct dwarf_expr_context *ctx)
{
if (ctx->stack_len <= 0)
- error ("dwarf expression stack underflow");
+ error (_("dwarf expression stack underflow"));
ctx->stack_len--;
}
CORE_ADDR
dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n)
{
- if (ctx->stack_len < n)
- error ("Asked for position %d of stack, stack only has %d elements on it\n",
+ if (ctx->stack_len <= n)
+ error (_("Asked for position %d of stack, stack only has %d elements on it."),
n, ctx->stack_len);
return ctx->stack[ctx->stack_len - (1 + n)];
}
+/* 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. */
void
-dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr,
- size_t len)
+dwarf_expr_eval (struct dwarf_expr_context *ctx, gdb_byte *addr, size_t len)
{
execute_stack_op (ctx, addr, addr + len);
}
by R, and return the new value of BUF. Verify that it doesn't extend
past BUF_END. */
-unsigned char *
-read_uleb128 (unsigned char *buf, unsigned char *buf_end, ULONGEST * r)
+gdb_byte *
+read_uleb128 (gdb_byte *buf, gdb_byte *buf_end, ULONGEST * r)
{
unsigned shift = 0;
ULONGEST result = 0;
- unsigned char byte;
+ gdb_byte byte;
while (1)
{
if (buf >= buf_end)
- error ("read_uleb128: Corrupted DWARF expression.");
+ error (_("read_uleb128: Corrupted DWARF expression."));
byte = *buf++;
result |= (byte & 0x7f) << shift;
by R, and return the new value of BUF. Verify that it doesn't extend
past BUF_END. */
-unsigned char *
-read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r)
+gdb_byte *
+read_sleb128 (gdb_byte *buf, gdb_byte *buf_end, LONGEST * r)
{
unsigned shift = 0;
LONGEST result = 0;
- unsigned char byte;
+ gdb_byte byte;
while (1)
{
if (buf >= buf_end)
- error ("read_sleb128: Corrupted DWARF expression.");
+ error (_("read_sleb128: Corrupted DWARF expression."));
byte = *buf++;
result |= (byte & 0x7f) << shift;
BUF_END. The address is returned, and *BYTES_READ is set to the
number of bytes read from BUF. */
-static CORE_ADDR
-read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read)
+CORE_ADDR
+dwarf2_read_address (gdb_byte *buf, gdb_byte *buf_end, int *bytes_read)
{
CORE_ADDR result;
- if (buf_end - buf < TARGET_ADDR_BIT / TARGET_CHAR_BIT)
- error ("read_address: Corrupted DWARF expression.");
+ if (buf_end - buf < gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT)
+ error (_("dwarf2_read_address: Corrupted DWARF expression."));
+
+ *bytes_read = gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT;
+
+ /* For most architectures, calling extract_unsigned_integer() alone
+ is sufficient for extracting an address. However, some
+ architectures (e.g. MIPS) use signed addresses and using
+ extract_unsigned_integer() will not produce a correct
+ result. Turning the unsigned integer into a value and then
+ decomposing that value as an address will cause
+ gdbarch_integer_to_address() to be invoked for those
+ architectures which require it. Thus, using value_as_address()
+ will produce the correct result for both types of architectures.
+
+ One concern regarding the use of values for this purpose is
+ efficiency. Obviously, these extra calls will take more time to
+ execute and creating a value takes more space, space which will
+ have to be garbage collected at a later time. If constructing
+ and then decomposing a value for this purpose proves to be too
+ inefficient, then gdbarch_integer_to_address() can be called
+ directly.
+
+ The use of `unsigned_address_type' in the code below refers to
+ the type of buf and has no bearing on the signedness of the
+ address being returned. */
+
+ result = value_as_address (value_from_longest
+ (unsigned_address_type (),
+ extract_unsigned_integer
+ (buf,
+ gdbarch_addr_bit (current_gdbarch)
+ / TARGET_CHAR_BIT)));
- *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
- result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
return result;
}
static struct type *
unsigned_address_type (void)
{
- switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ switch (gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT)
{
case 2:
return builtin_type_uint16;
return builtin_type_uint64;
default:
internal_error (__FILE__, __LINE__,
- "Unsupported address size.\n");
+ _("Unsupported address size.\n"));
}
}
static struct type *
signed_address_type (void)
{
- switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ switch (gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT)
{
case 2:
return builtin_type_int16;
return builtin_type_int64;
default:
internal_error (__FILE__, __LINE__,
- "Unsupported address size.\n");
+ _("Unsupported address size.\n"));
}
}
\f
evaluate the expression between OP_PTR and OP_END. */
static void
-execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
- unsigned char *op_end)
+execute_stack_op (struct dwarf_expr_context *ctx,
+ gdb_byte *op_ptr, gdb_byte *op_end)
{
+ ctx->in_reg = 0;
+ ctx->initialized = 1; /* Default is initialized. */
+
while (op_ptr < op_end)
{
enum dwarf_location_atom op = *op_ptr++;
- CORE_ADDR result, memaddr;
+ CORE_ADDR result;
ULONGEST uoffset, reg;
LONGEST offset;
int bytes_read;
- enum lval_type expr_lval;
-
- ctx->in_reg = 0;
switch (op)
{
break;
case DW_OP_addr:
- result = read_address (op_ptr, op_end, &bytes_read);
+ result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
op_ptr += bytes_read;
break;
case DW_OP_reg29:
case DW_OP_reg30:
case DW_OP_reg31:
- /* NOTE: in the presence of DW_OP_piece this check is incorrect. */
- if (op_ptr != op_end)
- error ("DWARF-2 expression error: DW_OP_reg operations must be "
- "used alone.");
+ if (op_ptr != op_end
+ && *op_ptr != DW_OP_piece
+ && *op_ptr != DW_OP_GNU_uninit)
+ error (_("DWARF-2 expression error: DW_OP_reg operations must be "
+ "used either alone or in conjuction with DW_OP_piece."));
- /* FIXME drow/2003-02-21: This call to read_reg could be pushed
- into the evaluator's caller by changing the semantics for in_reg.
- Then we wouldn't need to return an lval_type and a memaddr. */
- result = (ctx->read_reg) (ctx->baton, op - DW_OP_reg0, &expr_lval,
- &memaddr);
-
- if (expr_lval == lval_register)
- {
- ctx->regnum = op - DW_OP_reg0;
- ctx->in_reg = 1;
- }
- else
- result = memaddr;
+ result = op - DW_OP_reg0;
+ ctx->in_reg = 1;
break;
case DW_OP_regx:
op_ptr = read_uleb128 (op_ptr, op_end, ®);
- if (op_ptr != op_end)
- error ("DWARF-2 expression error: DW_OP_reg operations must be "
- "used alone.");
-
- result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr);
-
- if (expr_lval == lval_register)
- {
- ctx->regnum = reg;
- ctx->in_reg = 1;
- }
- else
- result = memaddr;
+ if (op_ptr != op_end && *op_ptr != DW_OP_piece)
+ error (_("DWARF-2 expression error: DW_OP_reg operations must be "
+ "used either alone or in conjuction with DW_OP_piece."));
+ result = reg;
+ ctx->in_reg = 1;
break;
case DW_OP_breg0:
case DW_OP_breg31:
{
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
- result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0,
- &expr_lval, &memaddr);
+ result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0);
result += offset;
}
break;
{
op_ptr = read_uleb128 (op_ptr, op_end, ®);
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
- result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr);
+ result = (ctx->read_reg) (ctx->baton, reg);
result += offset;
}
break;
case DW_OP_fbreg:
{
- unsigned char *datastart;
+ gdb_byte *datastart;
size_t datalen;
unsigned int before_stack_len;
afterwards, effectively erasing whatever the recursive
call put there. */
before_stack_len = ctx->stack_len;
+ /* FIXME: cagney/2003-03-26: This code should be using
+ get_frame_base_address(), and then implement a dwarf2
+ specific this_base method. */
(ctx->get_frame_base) (ctx->baton, &datastart, &datalen);
dwarf_expr_eval (ctx, datastart, datalen);
result = dwarf_expr_fetch (ctx, 0);
- if (! ctx->in_reg)
- {
- char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
- int bytes_read;
-
- (ctx->read_mem) (ctx->baton, buf, result,
- TARGET_ADDR_BIT / TARGET_CHAR_BIT);
- result = read_address (buf,
- buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
- &bytes_read);
- }
+ if (ctx->in_reg)
+ result = (ctx->read_reg) (ctx->baton, result);
result = result + offset;
ctx->stack_len = before_stack_len;
ctx->in_reg = 0;
CORE_ADDR t1, t2, t3;
if (ctx->stack_len < 3)
- error ("Not enough elements for DW_OP_rot. Need 3, have %d\n",
+ error (_("Not enough elements for DW_OP_rot. Need 3, have %d."),
ctx->stack_len);
t1 = ctx->stack[ctx->stack_len - 1];
t2 = ctx->stack[ctx->stack_len - 2];
{
case DW_OP_deref:
{
- char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ gdb_byte *buf = alloca (gdbarch_addr_bit (current_gdbarch)
+ / TARGET_CHAR_BIT);
int bytes_read;
(ctx->read_mem) (ctx->baton, buf, result,
- TARGET_ADDR_BIT / TARGET_CHAR_BIT);
- result = read_address (buf,
- buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
- &bytes_read);
+ gdbarch_addr_bit (current_gdbarch)
+ / TARGET_CHAR_BIT);
+ result = dwarf2_read_address (buf,
+ buf + (gdbarch_addr_bit
+ (current_gdbarch)
+ / TARGET_CHAR_BIT),
+ &bytes_read);
}
break;
case DW_OP_deref_size:
{
- char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ gdb_byte *buf
+ = alloca (gdbarch_addr_bit (current_gdbarch)
+ / TARGET_CHAR_BIT);
int bytes_read;
(ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
- result = read_address (buf,
- buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
- &bytes_read);
+ result = dwarf2_read_address (buf,
+ buf + (gdbarch_addr_bit
+ (current_gdbarch)
+ / TARGET_CHAR_BIT),
+ &bytes_read);
}
break;
second = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);
- first = dwarf_expr_fetch (ctx, 1);
+ first = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);
val1 = value_from_longest (unsigned_address_type (), first);
break;
case DW_OP_div:
binop = BINOP_DIV;
+ break;
case DW_OP_minus:
binop = BINOP_SUB;
break;
break;
case DW_OP_shr:
binop = BINOP_RSH;
+ break;
case DW_OP_shra:
binop = BINOP_RSH;
val1 = value_from_longest (signed_address_type (), first);
break;
default:
internal_error (__FILE__, __LINE__,
- "Can't be reached.");
+ _("Can't be reached."));
}
result = value_as_long (value_binop (val1, val2, binop));
}
break;
case DW_OP_GNU_push_tls_address:
+ /* Variable is at a constant offset in the thread-local
+ storage block into the objfile for the current thread and
+ the dynamic linker module containing this expression. Here
+ we return returns the offset from that base. The top of the
+ stack has the offset from the beginning of the thread
+ control block at which the variable is located. Nothing
+ should follow this operator, so the top of stack would be
+ returned. */
result = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);
result = (ctx->get_tls_address) (ctx->baton, result);
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;
+
+ case DW_OP_GNU_uninit:
+ if (op_ptr != op_end)
+ error (_("DWARF-2 expression error: DW_OP_GNU_unint must always "
+ "be the very last op."));
+
+ ctx->initialized = 0;
+ goto no_push;
+
default:
- error ("Unhandled dwarf expression opcode");
+ error (_("Unhandled dwarf expression opcode 0x%x"), op);
}
/* Most things push a result value. */