* vec.h (VEC_cleanup): New macro.
(DEF_VEC_ALLOC_FUNC_I): Update. (DEF_VEC_ALLOC_FUNC_P): Likewise. (DEF_VEC_ALLOC_FUNC_O): Likewise. * dwarf2loc.c (struct axs_var_loc): Remove. (unimplemented): New function. (translate_register): Likewise. (access_memory): Likewise. (compile_dwarf_to_ax): Likewise. (dwarf2_tracepoint_var_loc): Remove. (dwarf2_tracepoint_var_access): Likewise. (dwarf2_tracepoint_var_ref): Likewise. (locexpr_tracepoint_var_ref): Use compile_dwarf_to_ax. (loclist_tracepoint_var_ref): Likewise. * dwarf2expr.h (dwarf_expr_require_composition): Declare. * dwarf2expr.c (dwarf_expr_require_composition): Rename from require_composition. No longer static. (execute_stack_op): Update. * ax-gdb.h (trace_kludge): Declare.
This commit is contained in:
parent
81bb31c0d9
commit
3cf03773b7
6 changed files with 789 additions and 243 deletions
|
@ -1,3 +1,25 @@
|
|||
2010-06-11 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* vec.h (VEC_cleanup): New macro.
|
||||
(DEF_VEC_ALLOC_FUNC_I): Update.
|
||||
(DEF_VEC_ALLOC_FUNC_P): Likewise.
|
||||
(DEF_VEC_ALLOC_FUNC_O): Likewise.
|
||||
* dwarf2loc.c (struct axs_var_loc): Remove.
|
||||
(unimplemented): New function.
|
||||
(translate_register): Likewise.
|
||||
(access_memory): Likewise.
|
||||
(compile_dwarf_to_ax): Likewise.
|
||||
(dwarf2_tracepoint_var_loc): Remove.
|
||||
(dwarf2_tracepoint_var_access): Likewise.
|
||||
(dwarf2_tracepoint_var_ref): Likewise.
|
||||
(locexpr_tracepoint_var_ref): Use compile_dwarf_to_ax.
|
||||
(loclist_tracepoint_var_ref): Likewise.
|
||||
* dwarf2expr.h (dwarf_expr_require_composition): Declare.
|
||||
* dwarf2expr.c (dwarf_expr_require_composition): Rename from
|
||||
require_composition. No longer static.
|
||||
(execute_stack_op): Update.
|
||||
* ax-gdb.h (trace_kludge): Declare.
|
||||
|
||||
2010-06-11 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* breakpoint.c (breakpoint_restore_shadows): New OWNER comment.
|
||||
|
|
|
@ -108,4 +108,6 @@ extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct gdbarch *,
|
|||
|
||||
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
|
||||
|
||||
extern int trace_kludge;
|
||||
|
||||
#endif /* AX_GDB_H */
|
||||
|
|
|
@ -334,8 +334,8 @@ signed_address_type (struct gdbarch *gdbarch, int addr_size)
|
|||
/* Check that the current operator is either at the end of an
|
||||
expression, or that it is followed by a composition operator. */
|
||||
|
||||
static void
|
||||
require_composition (const gdb_byte *op_ptr, const gdb_byte *op_end,
|
||||
void
|
||||
dwarf_expr_require_composition (const gdb_byte *op_ptr, const gdb_byte *op_end,
|
||||
const char *op_name)
|
||||
{
|
||||
/* It seems like DW_OP_GNU_uninit should be handled here. However,
|
||||
|
@ -511,7 +511,7 @@ execute_stack_op (struct dwarf_expr_context *ctx,
|
|||
|
||||
case DW_OP_regx:
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, ®);
|
||||
require_composition (op_ptr, op_end, "DW_OP_regx");
|
||||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
|
||||
|
||||
result = reg;
|
||||
ctx->location = DWARF_VALUE_REGISTER;
|
||||
|
@ -528,13 +528,14 @@ execute_stack_op (struct dwarf_expr_context *ctx,
|
|||
ctx->data = op_ptr;
|
||||
ctx->location = DWARF_VALUE_LITERAL;
|
||||
op_ptr += len;
|
||||
require_composition (op_ptr, op_end, "DW_OP_implicit_value");
|
||||
dwarf_expr_require_composition (op_ptr, op_end,
|
||||
"DW_OP_implicit_value");
|
||||
}
|
||||
goto no_push;
|
||||
|
||||
case DW_OP_stack_value:
|
||||
ctx->location = DWARF_VALUE_STACK;
|
||||
require_composition (op_ptr, op_end, "DW_OP_stack_value");
|
||||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_stack_value");
|
||||
goto no_push;
|
||||
|
||||
case DW_OP_breg0:
|
||||
|
|
|
@ -209,4 +209,7 @@ CORE_ADDR dwarf2_read_address (struct gdbarch *gdbarch, const gdb_byte *buf,
|
|||
|
||||
const char *dwarf_stack_op_name (unsigned int, int);
|
||||
|
||||
void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
|
||||
const char *);
|
||||
|
||||
#endif /* dwarf2expr.h */
|
||||
|
|
888
gdb/dwarf2loc.c
888
gdb/dwarf2loc.c
|
@ -1048,60 +1048,360 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size,
|
|||
return baton.needs_frame || in_reg;
|
||||
}
|
||||
|
||||
/* This struct keeps track of the pieces that make up a multi-location
|
||||
object, for use in agent expression generation. It is
|
||||
superficially similar to struct dwarf_expr_piece, but
|
||||
dwarf_expr_piece is designed for use in immediate evaluation, and
|
||||
does not, for example, have a way to record both base register and
|
||||
offset. */
|
||||
/* A helper function that throws an unimplemented error mentioning a
|
||||
given DWARF operator. */
|
||||
|
||||
struct axs_var_loc
|
||||
static void
|
||||
unimplemented (unsigned int op)
|
||||
{
|
||||
/* Memory vs register, etc */
|
||||
enum axs_lvalue_kind kind;
|
||||
error (_("DWARF operator %s cannot be translated to an agent expression"),
|
||||
dwarf_stack_op_name (op, 1));
|
||||
}
|
||||
|
||||
/* If non-zero, number of bytes in this fragment */
|
||||
unsigned bytes;
|
||||
/* A helper function to convert a DWARF register to an arch register.
|
||||
ARCH is the architecture.
|
||||
DWARF_REG is the register.
|
||||
This will throw an exception if the DWARF register cannot be
|
||||
translated to an architecture register. */
|
||||
|
||||
/* (GDB-numbered) reg, or base reg if >= 0 */
|
||||
int reg;
|
||||
static int
|
||||
translate_register (struct gdbarch *arch, int dwarf_reg)
|
||||
{
|
||||
int reg = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_reg);
|
||||
if (reg == -1)
|
||||
error (_("Unable to access DWARF register number %d"), dwarf_reg);
|
||||
return reg;
|
||||
}
|
||||
|
||||
/* offset from reg */
|
||||
/* A helper function that emits an access to memory. ARCH is the
|
||||
target architecture. EXPR is the expression which we are building.
|
||||
NBITS is the number of bits we want to read. This emits the
|
||||
opcodes needed to read the memory and then extract the desired
|
||||
bits. */
|
||||
|
||||
static void
|
||||
access_memory (struct gdbarch *arch, struct agent_expr *expr, ULONGEST nbits)
|
||||
{
|
||||
ULONGEST nbytes = (nbits + 7) / 8;
|
||||
|
||||
gdb_assert (nbits > 0 && nbits <= sizeof (LONGEST));
|
||||
|
||||
if (trace_kludge)
|
||||
ax_trace_quick (expr, nbytes);
|
||||
|
||||
if (nbits <= 8)
|
||||
ax_simple (expr, aop_ref8);
|
||||
else if (nbits <= 16)
|
||||
ax_simple (expr, aop_ref16);
|
||||
else if (nbits <= 32)
|
||||
ax_simple (expr, aop_ref32);
|
||||
else
|
||||
ax_simple (expr, aop_ref64);
|
||||
|
||||
/* If we read exactly the number of bytes we wanted, we're done. */
|
||||
if (8 * nbytes == nbits)
|
||||
return;
|
||||
|
||||
if (gdbarch_bits_big_endian (arch))
|
||||
{
|
||||
/* On a bits-big-endian machine, we want the high-order
|
||||
NBITS. */
|
||||
ax_const_l (expr, 8 * nbytes - nbits);
|
||||
ax_simple (expr, aop_rsh_unsigned);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* On a bits-little-endian box, we want the low-order NBITS. */
|
||||
ax_zero_ext (expr, nbits);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compile a DWARF location expression to an agent expression.
|
||||
|
||||
EXPR is the agent expression we are building.
|
||||
LOC is the agent value we modify.
|
||||
ARCH is the architecture.
|
||||
ADDR_SIZE is the size of addresses, in bytes.
|
||||
OP_PTR is the start of the location expression.
|
||||
OP_END is one past the last byte of the location expression.
|
||||
|
||||
This will throw an exception for various kinds of errors -- for
|
||||
example, if the expression cannot be compiled, or if the expression
|
||||
is invalid. */
|
||||
|
||||
static void
|
||||
compile_dwarf_to_ax (struct agent_expr *expr, struct axs_value *loc,
|
||||
struct gdbarch *arch, unsigned int addr_size,
|
||||
const gdb_byte *op_ptr, const gdb_byte *op_end,
|
||||
struct dwarf2_per_cu_data *per_cu)
|
||||
{
|
||||
struct cleanup *cleanups;
|
||||
int i, *offsets;
|
||||
VEC(int) *dw_labels = NULL, *patches = NULL;
|
||||
const gdb_byte * const base = op_ptr;
|
||||
const gdb_byte *previous_piece = op_ptr;
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (arch);
|
||||
ULONGEST bits_collected = 0;
|
||||
unsigned int addr_size_bits = 8 * addr_size;
|
||||
int bits_big_endian = gdbarch_bits_big_endian (arch);
|
||||
|
||||
offsets = xmalloc ((op_end - op_ptr) * sizeof (int));
|
||||
cleanups = make_cleanup (xfree, offsets);
|
||||
|
||||
for (i = 0; i < op_end - op_ptr; ++i)
|
||||
offsets[i] = -1;
|
||||
|
||||
make_cleanup (VEC_cleanup (int), &dw_labels);
|
||||
make_cleanup (VEC_cleanup (int), &patches);
|
||||
|
||||
/* By default we are making an address. */
|
||||
loc->kind = axs_lvalue_memory;
|
||||
|
||||
while (op_ptr < op_end)
|
||||
{
|
||||
enum dwarf_location_atom op = *op_ptr;
|
||||
CORE_ADDR result;
|
||||
ULONGEST uoffset, reg;
|
||||
LONGEST offset;
|
||||
};
|
||||
int i;
|
||||
|
||||
static const gdb_byte *
|
||||
dwarf2_tracepoint_var_loc (struct symbol *symbol,
|
||||
struct agent_expr *ax,
|
||||
struct axs_var_loc *loc,
|
||||
struct gdbarch *gdbarch,
|
||||
const gdb_byte *data, const gdb_byte *end)
|
||||
{
|
||||
if (data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31)
|
||||
{
|
||||
loc->kind = axs_lvalue_register;
|
||||
loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_reg0);
|
||||
data += 1;
|
||||
}
|
||||
else if (data[0] == DW_OP_regx)
|
||||
{
|
||||
ULONGEST reg;
|
||||
offsets[op_ptr - base] = expr->len;
|
||||
++op_ptr;
|
||||
|
||||
data = read_uleb128 (data + 1, end, ®);
|
||||
loc->kind = axs_lvalue_register;
|
||||
loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
|
||||
}
|
||||
else if (data[0] == DW_OP_fbreg)
|
||||
/* Our basic approach to code generation is to map DWARF
|
||||
operations directly to AX operations. However, there are
|
||||
some differences.
|
||||
|
||||
First, DWARF works on address-sized units, but AX always uses
|
||||
LONGEST. For most operations we simply ignore this
|
||||
difference; instead we generate sign extensions as needed
|
||||
before division and comparison operations. It would be nice
|
||||
to omit the sign extensions, but there is no way to determine
|
||||
the size of the target's LONGEST. (This code uses the size
|
||||
of the host LONGEST in some cases -- that is a bug but it is
|
||||
difficult to fix.)
|
||||
|
||||
Second, some DWARF operations cannot be translated to AX.
|
||||
For these we simply fail. See
|
||||
http://sourceware.org/bugzilla/show_bug.cgi?id=11662. */
|
||||
switch (op)
|
||||
{
|
||||
case DW_OP_lit0:
|
||||
case DW_OP_lit1:
|
||||
case DW_OP_lit2:
|
||||
case DW_OP_lit3:
|
||||
case DW_OP_lit4:
|
||||
case DW_OP_lit5:
|
||||
case DW_OP_lit6:
|
||||
case DW_OP_lit7:
|
||||
case DW_OP_lit8:
|
||||
case DW_OP_lit9:
|
||||
case DW_OP_lit10:
|
||||
case DW_OP_lit11:
|
||||
case DW_OP_lit12:
|
||||
case DW_OP_lit13:
|
||||
case DW_OP_lit14:
|
||||
case DW_OP_lit15:
|
||||
case DW_OP_lit16:
|
||||
case DW_OP_lit17:
|
||||
case DW_OP_lit18:
|
||||
case DW_OP_lit19:
|
||||
case DW_OP_lit20:
|
||||
case DW_OP_lit21:
|
||||
case DW_OP_lit22:
|
||||
case DW_OP_lit23:
|
||||
case DW_OP_lit24:
|
||||
case DW_OP_lit25:
|
||||
case DW_OP_lit26:
|
||||
case DW_OP_lit27:
|
||||
case DW_OP_lit28:
|
||||
case DW_OP_lit29:
|
||||
case DW_OP_lit30:
|
||||
case DW_OP_lit31:
|
||||
ax_const_l (expr, op - DW_OP_lit0);
|
||||
break;
|
||||
|
||||
case DW_OP_addr:
|
||||
result = dwarf2_read_address (arch, op_ptr, op_end, addr_size);
|
||||
ax_const_l (expr, result);
|
||||
op_ptr += addr_size;
|
||||
break;
|
||||
|
||||
case DW_OP_const1u:
|
||||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 1, byte_order));
|
||||
op_ptr += 1;
|
||||
break;
|
||||
case DW_OP_const1s:
|
||||
ax_const_l (expr, extract_signed_integer (op_ptr, 1, byte_order));
|
||||
op_ptr += 1;
|
||||
break;
|
||||
case DW_OP_const2u:
|
||||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 2, byte_order));
|
||||
op_ptr += 2;
|
||||
break;
|
||||
case DW_OP_const2s:
|
||||
ax_const_l (expr, extract_signed_integer (op_ptr, 2, byte_order));
|
||||
op_ptr += 2;
|
||||
break;
|
||||
case DW_OP_const4u:
|
||||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 4, byte_order));
|
||||
op_ptr += 4;
|
||||
break;
|
||||
case DW_OP_const4s:
|
||||
ax_const_l (expr, extract_signed_integer (op_ptr, 4, byte_order));
|
||||
op_ptr += 4;
|
||||
break;
|
||||
case DW_OP_const8u:
|
||||
ax_const_l (expr, extract_unsigned_integer (op_ptr, 8, byte_order));
|
||||
op_ptr += 8;
|
||||
break;
|
||||
case DW_OP_const8s:
|
||||
ax_const_l (expr, extract_signed_integer (op_ptr, 8, byte_order));
|
||||
op_ptr += 8;
|
||||
break;
|
||||
case DW_OP_constu:
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, &uoffset);
|
||||
ax_const_l (expr, uoffset);
|
||||
break;
|
||||
case DW_OP_consts:
|
||||
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
|
||||
ax_const_l (expr, offset);
|
||||
break;
|
||||
|
||||
case DW_OP_reg0:
|
||||
case DW_OP_reg1:
|
||||
case DW_OP_reg2:
|
||||
case DW_OP_reg3:
|
||||
case DW_OP_reg4:
|
||||
case DW_OP_reg5:
|
||||
case DW_OP_reg6:
|
||||
case DW_OP_reg7:
|
||||
case DW_OP_reg8:
|
||||
case DW_OP_reg9:
|
||||
case DW_OP_reg10:
|
||||
case DW_OP_reg11:
|
||||
case DW_OP_reg12:
|
||||
case DW_OP_reg13:
|
||||
case DW_OP_reg14:
|
||||
case DW_OP_reg15:
|
||||
case DW_OP_reg16:
|
||||
case DW_OP_reg17:
|
||||
case DW_OP_reg18:
|
||||
case DW_OP_reg19:
|
||||
case DW_OP_reg20:
|
||||
case DW_OP_reg21:
|
||||
case DW_OP_reg22:
|
||||
case DW_OP_reg23:
|
||||
case DW_OP_reg24:
|
||||
case DW_OP_reg25:
|
||||
case DW_OP_reg26:
|
||||
case DW_OP_reg27:
|
||||
case DW_OP_reg28:
|
||||
case DW_OP_reg29:
|
||||
case DW_OP_reg30:
|
||||
case DW_OP_reg31:
|
||||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
|
||||
loc->u.reg = translate_register (arch, op - DW_OP_reg0);
|
||||
loc->kind = axs_lvalue_register;
|
||||
break;
|
||||
|
||||
case DW_OP_regx:
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, ®);
|
||||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
|
||||
loc->u.reg = translate_register (arch, reg);
|
||||
loc->kind = axs_lvalue_register;
|
||||
break;
|
||||
|
||||
case DW_OP_implicit_value:
|
||||
{
|
||||
ULONGEST len;
|
||||
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, &len);
|
||||
if (op_ptr + len > op_end)
|
||||
error (_("DW_OP_implicit_value: too few bytes available."));
|
||||
if (len > sizeof (ULONGEST))
|
||||
error (_("Cannot translate DW_OP_implicit_value of %d bytes"),
|
||||
(int) len);
|
||||
|
||||
ax_const_l (expr, extract_unsigned_integer (op_ptr, len,
|
||||
byte_order));
|
||||
op_ptr += len;
|
||||
dwarf_expr_require_composition (op_ptr, op_end,
|
||||
"DW_OP_implicit_value");
|
||||
|
||||
loc->kind = axs_rvalue;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_stack_value:
|
||||
dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_stack_value");
|
||||
loc->kind = axs_rvalue;
|
||||
break;
|
||||
|
||||
case DW_OP_breg0:
|
||||
case DW_OP_breg1:
|
||||
case DW_OP_breg2:
|
||||
case DW_OP_breg3:
|
||||
case DW_OP_breg4:
|
||||
case DW_OP_breg5:
|
||||
case DW_OP_breg6:
|
||||
case DW_OP_breg7:
|
||||
case DW_OP_breg8:
|
||||
case DW_OP_breg9:
|
||||
case DW_OP_breg10:
|
||||
case DW_OP_breg11:
|
||||
case DW_OP_breg12:
|
||||
case DW_OP_breg13:
|
||||
case DW_OP_breg14:
|
||||
case DW_OP_breg15:
|
||||
case DW_OP_breg16:
|
||||
case DW_OP_breg17:
|
||||
case DW_OP_breg18:
|
||||
case DW_OP_breg19:
|
||||
case DW_OP_breg20:
|
||||
case DW_OP_breg21:
|
||||
case DW_OP_breg22:
|
||||
case DW_OP_breg23:
|
||||
case DW_OP_breg24:
|
||||
case DW_OP_breg25:
|
||||
case DW_OP_breg26:
|
||||
case DW_OP_breg27:
|
||||
case DW_OP_breg28:
|
||||
case DW_OP_breg29:
|
||||
case DW_OP_breg30:
|
||||
case DW_OP_breg31:
|
||||
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
|
||||
i = translate_register (arch, op - DW_OP_breg0);
|
||||
ax_reg (expr, i);
|
||||
if (offset != 0)
|
||||
{
|
||||
ax_const_l (expr, offset);
|
||||
ax_simple (expr, aop_add);
|
||||
}
|
||||
break;
|
||||
case DW_OP_bregx:
|
||||
{
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, ®);
|
||||
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
|
||||
i = translate_register (arch, reg);
|
||||
ax_reg (expr, i);
|
||||
if (offset != 0)
|
||||
{
|
||||
ax_const_l (expr, offset);
|
||||
ax_simple (expr, aop_add);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DW_OP_fbreg:
|
||||
{
|
||||
const gdb_byte *datastart;
|
||||
size_t datalen;
|
||||
unsigned int before_stack_len;
|
||||
struct block *b;
|
||||
struct symbol *framefunc;
|
||||
int frame_reg = 0;
|
||||
LONGEST frame_offset;
|
||||
const gdb_byte *base_data;
|
||||
size_t base_size;
|
||||
LONGEST base_offset = 0;
|
||||
|
||||
b = block_for_pc (ax->scope);
|
||||
b = block_for_pc (expr->scope);
|
||||
|
||||
if (!b)
|
||||
error (_("No block found for address"));
|
||||
|
@ -1111,203 +1411,383 @@ dwarf2_tracepoint_var_loc (struct symbol *symbol,
|
|||
if (!framefunc)
|
||||
error (_("No function found for block"));
|
||||
|
||||
dwarf_expr_frame_base_1 (framefunc, ax->scope,
|
||||
&base_data, &base_size);
|
||||
dwarf_expr_frame_base_1 (framefunc, expr->scope,
|
||||
&datastart, &datalen);
|
||||
|
||||
if (base_data[0] >= DW_OP_breg0 && base_data[0] <= DW_OP_breg31)
|
||||
{
|
||||
const gdb_byte *buf_end;
|
||||
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
|
||||
compile_dwarf_to_ax (expr, loc, arch, addr_size, datastart,
|
||||
datastart + datalen, per_cu);
|
||||
|
||||
frame_reg = base_data[0] - DW_OP_breg0;
|
||||
buf_end = read_sleb128 (base_data + 1,
|
||||
base_data + base_size, &base_offset);
|
||||
if (buf_end != base_data + base_size)
|
||||
error (_("Unexpected opcode after DW_OP_breg%u for symbol \"%s\"."),
|
||||
frame_reg, SYMBOL_PRINT_NAME (symbol));
|
||||
}
|
||||
else if (base_data[0] >= DW_OP_reg0 && base_data[0] <= DW_OP_reg31)
|
||||
if (offset != 0)
|
||||
{
|
||||
/* The frame base is just the register, with no offset. */
|
||||
frame_reg = base_data[0] - DW_OP_reg0;
|
||||
base_offset = 0;
|
||||
ax_const_l (expr, offset);
|
||||
ax_simple (expr, aop_add);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't know what to do with the frame base expression,
|
||||
so we can't trace this variable; give up. */
|
||||
error (_("Cannot generate expression to collect symbol \"%s\"; DWARF 2 encoding not handled, first opcode in base data is 0x%x."),
|
||||
SYMBOL_PRINT_NAME (symbol), base_data[0]);
|
||||
}
|
||||
|
||||
data = read_sleb128 (data + 1, end, &frame_offset);
|
||||
|
||||
loc->kind = axs_lvalue_memory;
|
||||
loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, frame_reg);
|
||||
loc->offset = base_offset + frame_offset;
|
||||
}
|
||||
else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31)
|
||||
break;
|
||||
|
||||
case DW_OP_dup:
|
||||
ax_simple (expr, aop_dup);
|
||||
break;
|
||||
|
||||
case DW_OP_drop:
|
||||
ax_simple (expr, aop_pop);
|
||||
break;
|
||||
|
||||
case DW_OP_pick:
|
||||
offset = *op_ptr++;
|
||||
unimplemented (op);
|
||||
break;
|
||||
|
||||
case DW_OP_swap:
|
||||
ax_simple (expr, aop_swap);
|
||||
break;
|
||||
|
||||
case DW_OP_over:
|
||||
/* We can't directly support DW_OP_over, but GCC emits it as
|
||||
part of a sequence to implement signed modulus. As a
|
||||
hack, we recognize this sequence. Note that if GCC ever
|
||||
generates a branch to the middle of this sequence, then
|
||||
we will die somehow. */
|
||||
if (op_end - op_ptr >= 4
|
||||
&& op_ptr[0] == DW_OP_over
|
||||
&& op_ptr[1] == DW_OP_div
|
||||
&& op_ptr[2] == DW_OP_mul
|
||||
&& op_ptr[3] == DW_OP_minus)
|
||||
{
|
||||
unsigned int reg;
|
||||
LONGEST offset;
|
||||
|
||||
reg = data[0] - DW_OP_breg0;
|
||||
data = read_sleb128 (data + 1, end, &offset);
|
||||
|
||||
loc->kind = axs_lvalue_memory;
|
||||
loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
|
||||
loc->offset = offset;
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_simple (expr, aop_rem_signed);
|
||||
op_ptr += 4;
|
||||
}
|
||||
else
|
||||
error (_("Unsupported DWARF opcode 0x%x in the location of \"%s\"."),
|
||||
data[0], SYMBOL_PRINT_NAME (symbol));
|
||||
unimplemented (op);
|
||||
break;
|
||||
|
||||
return data;
|
||||
}
|
||||
case DW_OP_rot:
|
||||
unimplemented (op);
|
||||
break;
|
||||
|
||||
/* Given the location of a piece, issue bytecodes that will access it. */
|
||||
case DW_OP_deref:
|
||||
case DW_OP_deref_size:
|
||||
{
|
||||
int size;
|
||||
|
||||
static void
|
||||
dwarf2_tracepoint_var_access (struct agent_expr *ax,
|
||||
struct axs_value *value,
|
||||
struct axs_var_loc *loc)
|
||||
{
|
||||
value->kind = loc->kind;
|
||||
if (op == DW_OP_deref_size)
|
||||
size = *op_ptr++;
|
||||
else
|
||||
size = addr_size;
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 8:
|
||||
ax_simple (expr, aop_ref8);
|
||||
break;
|
||||
case 16:
|
||||
ax_simple (expr, aop_ref16);
|
||||
break;
|
||||
case 32:
|
||||
ax_simple (expr, aop_ref32);
|
||||
break;
|
||||
case 64:
|
||||
ax_simple (expr, aop_ref64);
|
||||
break;
|
||||
default:
|
||||
error (_("Unsupported size %d in %s"),
|
||||
size, dwarf_stack_op_name (op, 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_abs:
|
||||
/* Sign extend the operand. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_dup);
|
||||
ax_const_l (expr, 0);
|
||||
ax_simple (expr, aop_less_signed);
|
||||
ax_simple (expr, aop_log_not);
|
||||
i = ax_goto (expr, aop_if_goto);
|
||||
/* We have to emit 0 - X. */
|
||||
ax_const_l (expr, 0);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_simple (expr, aop_sub);
|
||||
ax_label (expr, i, expr->len);
|
||||
break;
|
||||
|
||||
case DW_OP_neg:
|
||||
/* No need to sign extend here. */
|
||||
ax_const_l (expr, 0);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_simple (expr, aop_sub);
|
||||
break;
|
||||
|
||||
case DW_OP_not:
|
||||
/* Sign extend the operand. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_bit_not);
|
||||
break;
|
||||
|
||||
case DW_OP_plus_uconst:
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, ®);
|
||||
/* It would be really weird to emit `DW_OP_plus_uconst 0',
|
||||
but we micro-optimize anyhow. */
|
||||
if (reg != 0)
|
||||
{
|
||||
ax_const_l (expr, reg);
|
||||
ax_simple (expr, aop_add);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_and:
|
||||
ax_simple (expr, aop_bit_and);
|
||||
break;
|
||||
|
||||
case DW_OP_div:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_simple (expr, aop_div_signed);
|
||||
break;
|
||||
|
||||
case DW_OP_minus:
|
||||
ax_simple (expr, aop_sub);
|
||||
break;
|
||||
|
||||
case DW_OP_mod:
|
||||
ax_simple (expr, aop_rem_unsigned);
|
||||
break;
|
||||
|
||||
case DW_OP_mul:
|
||||
ax_simple (expr, aop_mul);
|
||||
break;
|
||||
|
||||
case DW_OP_or:
|
||||
ax_simple (expr, aop_bit_or);
|
||||
break;
|
||||
|
||||
case DW_OP_plus:
|
||||
ax_simple (expr, aop_add);
|
||||
break;
|
||||
|
||||
case DW_OP_shl:
|
||||
ax_simple (expr, aop_lsh);
|
||||
break;
|
||||
|
||||
case DW_OP_shr:
|
||||
ax_simple (expr, aop_rsh_unsigned);
|
||||
break;
|
||||
|
||||
case DW_OP_shra:
|
||||
ax_simple (expr, aop_rsh_signed);
|
||||
break;
|
||||
|
||||
case DW_OP_xor:
|
||||
ax_simple (expr, aop_bit_xor);
|
||||
break;
|
||||
|
||||
case DW_OP_le:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
/* Note no swap here: A <= B is !(B < A). */
|
||||
ax_simple (expr, aop_less_signed);
|
||||
ax_simple (expr, aop_log_not);
|
||||
break;
|
||||
|
||||
case DW_OP_ge:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
/* A >= B is !(A < B). */
|
||||
ax_simple (expr, aop_less_signed);
|
||||
ax_simple (expr, aop_log_not);
|
||||
break;
|
||||
|
||||
case DW_OP_eq:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
/* No need for a second swap here. */
|
||||
ax_simple (expr, aop_equal);
|
||||
break;
|
||||
|
||||
case DW_OP_lt:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_simple (expr, aop_less_signed);
|
||||
break;
|
||||
|
||||
case DW_OP_gt:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
/* Note no swap here: A > B is B < A. */
|
||||
ax_simple (expr, aop_less_signed);
|
||||
break;
|
||||
|
||||
case DW_OP_ne:
|
||||
/* Sign extend the operands. */
|
||||
ax_ext (expr, addr_size_bits);
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_ext (expr, addr_size_bits);
|
||||
/* No need for a swap here. */
|
||||
ax_simple (expr, aop_equal);
|
||||
ax_simple (expr, aop_log_not);
|
||||
break;
|
||||
|
||||
case DW_OP_call_frame_cfa:
|
||||
unimplemented (op);
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_push_tls_address:
|
||||
unimplemented (op);
|
||||
break;
|
||||
|
||||
case DW_OP_skip:
|
||||
offset = extract_signed_integer (op_ptr, 2, byte_order);
|
||||
op_ptr += 2;
|
||||
i = ax_goto (expr, aop_goto);
|
||||
VEC_safe_push (int, dw_labels, op_ptr + offset - base);
|
||||
VEC_safe_push (int, patches, i);
|
||||
break;
|
||||
|
||||
case DW_OP_bra:
|
||||
offset = extract_signed_integer (op_ptr, 2, byte_order);
|
||||
op_ptr += 2;
|
||||
/* Zero extend the operand. */
|
||||
ax_zero_ext (expr, addr_size_bits);
|
||||
i = ax_goto (expr, aop_if_goto);
|
||||
VEC_safe_push (int, dw_labels, op_ptr + offset - base);
|
||||
VEC_safe_push (int, patches, i);
|
||||
break;
|
||||
|
||||
case DW_OP_nop:
|
||||
break;
|
||||
|
||||
case DW_OP_piece:
|
||||
case DW_OP_bit_piece:
|
||||
{
|
||||
ULONGEST size, offset;
|
||||
|
||||
if (op_ptr - 1 == previous_piece)
|
||||
error (_("Cannot translate empty pieces to agent expressions"));
|
||||
previous_piece = op_ptr - 1;
|
||||
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, &size);
|
||||
if (op == DW_OP_piece)
|
||||
{
|
||||
size *= 8;
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, &offset);
|
||||
|
||||
if (bits_collected + size > 8 * sizeof (LONGEST))
|
||||
error (_("Expression pieces exceed word size"));
|
||||
|
||||
/* Access the bits. */
|
||||
switch (loc->kind)
|
||||
{
|
||||
case axs_lvalue_register:
|
||||
value->u.reg = loc->reg;
|
||||
ax_reg (expr, loc->u.reg);
|
||||
break;
|
||||
|
||||
case axs_lvalue_memory:
|
||||
ax_reg (ax, loc->reg);
|
||||
if (loc->offset)
|
||||
/* Offset the pointer, if needed. */
|
||||
if (offset > 8)
|
||||
{
|
||||
ax_const_l (ax, loc->offset);
|
||||
ax_simple (ax, aop_add);
|
||||
ax_const_l (expr, offset / 8);
|
||||
ax_simple (expr, aop_add);
|
||||
offset %= 8;
|
||||
}
|
||||
access_memory (arch, expr, size);
|
||||
break;
|
||||
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__, _("Unhandled value kind in dwarf2_tracepoint_var_access"));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dwarf2_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
|
||||
struct agent_expr *ax, struct axs_value *value,
|
||||
const gdb_byte *data, int size)
|
||||
{
|
||||
const gdb_byte *end = data + size;
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
/* In practice, a variable is not going to be spread across
|
||||
dozens of registers or memory locations. If someone comes up
|
||||
with a real-world example, revisit this. */
|
||||
#define MAX_FRAGS 16
|
||||
struct axs_var_loc fragments[MAX_FRAGS];
|
||||
int nfrags = 0, frag;
|
||||
int length = 0;
|
||||
int piece_ok = 0;
|
||||
int bad = 0;
|
||||
int first = 1;
|
||||
|
||||
if (!data || size == 0)
|
||||
{
|
||||
value->optimized_out = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
while (data < end)
|
||||
/* For a bits-big-endian target, shift up what we already
|
||||
have. For a bits-little-endian target, shift up the
|
||||
new data. Note that there is a potential bug here if
|
||||
the DWARF expression leaves multiple values on the
|
||||
stack. */
|
||||
if (bits_collected > 0)
|
||||
{
|
||||
if (!piece_ok)
|
||||
if (bits_big_endian)
|
||||
{
|
||||
if (nfrags == MAX_FRAGS)
|
||||
error (_("Too many pieces in location for \"%s\"."),
|
||||
SYMBOL_PRINT_NAME (symbol));
|
||||
|
||||
fragments[nfrags].bytes = 0;
|
||||
data = dwarf2_tracepoint_var_loc (symbol, ax, &fragments[nfrags],
|
||||
gdbarch, data, end);
|
||||
nfrags++;
|
||||
piece_ok = 1;
|
||||
}
|
||||
else if (data[0] == DW_OP_piece)
|
||||
{
|
||||
ULONGEST bytes;
|
||||
|
||||
data = read_uleb128 (data + 1, end, &bytes);
|
||||
/* Only deal with 4 byte fragments for now. */
|
||||
if (bytes != 4)
|
||||
error (_("DW_OP_piece %s not supported in location for \"%s\"."),
|
||||
pulongest (bytes), SYMBOL_PRINT_NAME (symbol));
|
||||
fragments[nfrags - 1].bytes = bytes;
|
||||
length += bytes;
|
||||
piece_ok = 0;
|
||||
ax_simple (expr, aop_swap);
|
||||
ax_const_l (expr, size);
|
||||
ax_simple (expr, aop_lsh);
|
||||
/* We don't need a second swap here, because
|
||||
aop_bit_or is symmetric. */
|
||||
}
|
||||
else
|
||||
{
|
||||
bad = 1;
|
||||
break;
|
||||
ax_const_l (expr, size);
|
||||
ax_simple (expr, aop_lsh);
|
||||
}
|
||||
ax_simple (expr, aop_bit_or);
|
||||
}
|
||||
|
||||
if (bad || data > end)
|
||||
error (_("Corrupted DWARF expression for \"%s\"."),
|
||||
SYMBOL_PRINT_NAME (symbol));
|
||||
|
||||
/* If single expression, no pieces, convert to external format. */
|
||||
if (length == 0)
|
||||
{
|
||||
dwarf2_tracepoint_var_access (ax, value, &fragments[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length != TYPE_LENGTH (value->type))
|
||||
error (_("Inconsistent piece information for \"%s\"."),
|
||||
SYMBOL_PRINT_NAME (symbol));
|
||||
|
||||
/* Emit bytecodes to assemble the pieces into a single stack entry. */
|
||||
|
||||
for ((frag = (byte_order == BFD_ENDIAN_BIG ? 0 : nfrags - 1));
|
||||
nfrags--;
|
||||
(frag += (byte_order == BFD_ENDIAN_BIG ? 1 : -1)))
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
/* shift the previous fragment up 32 bits */
|
||||
ax_const_l (ax, 32);
|
||||
ax_simple (ax, aop_lsh);
|
||||
}
|
||||
|
||||
dwarf2_tracepoint_var_access (ax, value, &fragments[frag]);
|
||||
|
||||
switch (value->kind)
|
||||
{
|
||||
case axs_lvalue_register:
|
||||
ax_reg (ax, value->u.reg);
|
||||
break;
|
||||
|
||||
case axs_lvalue_memory:
|
||||
{
|
||||
extern int trace_kludge; /* Ugh. */
|
||||
|
||||
gdb_assert (fragments[frag].bytes == 4);
|
||||
if (trace_kludge)
|
||||
ax_trace_quick (ax, 4);
|
||||
ax_simple (ax, aop_ref32);
|
||||
bits_collected += size;
|
||||
loc->kind = axs_rvalue;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_uninit:
|
||||
unimplemented (op);
|
||||
|
||||
case DW_OP_call2:
|
||||
case DW_OP_call4:
|
||||
{
|
||||
struct dwarf2_locexpr_baton block;
|
||||
int size = (op == DW_OP_call2 ? 2 : 4);
|
||||
|
||||
uoffset = extract_unsigned_integer (op_ptr, size, byte_order);
|
||||
op_ptr += size;
|
||||
|
||||
block = dwarf2_fetch_die_location_block (uoffset, per_cu);
|
||||
|
||||
/* DW_OP_call_ref is currently not supported. */
|
||||
gdb_assert (block.per_cu == per_cu);
|
||||
|
||||
compile_dwarf_to_ax (expr, loc, arch, addr_size,
|
||||
block.data, block.data + block.size,
|
||||
per_cu);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_call_ref:
|
||||
unimplemented (op);
|
||||
|
||||
default:
|
||||
error (_("Unhandled dwarf expression opcode 0x%x"), op);
|
||||
}
|
||||
}
|
||||
|
||||
if (!first)
|
||||
/* Patch all the branches we emitted. */
|
||||
for (i = 0; i < VEC_length (int, patches); ++i)
|
||||
{
|
||||
/* or the new fragment into the previous */
|
||||
ax_zero_ext (ax, 32);
|
||||
ax_simple (ax, aop_bit_or);
|
||||
int targ = offsets[VEC_index (int, dw_labels, i)];
|
||||
if (targ == -1)
|
||||
internal_error (__FILE__, __LINE__, _("invalid label"));
|
||||
ax_label (expr, VEC_index (int, patches, i), targ);
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
value->kind = axs_rvalue;
|
||||
|
||||
do_cleanups (cleanups);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1864,9 +2344,11 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
|
|||
struct agent_expr *ax, struct axs_value *value)
|
||||
{
|
||||
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
|
||||
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
|
||||
|
||||
dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value,
|
||||
dlbaton->data, dlbaton->size);
|
||||
compile_dwarf_to_ax (ax, value, gdbarch, addr_size,
|
||||
dlbaton->data, dlbaton->data + dlbaton->size,
|
||||
dlbaton->per_cu);
|
||||
}
|
||||
|
||||
/* The set of location functions used with the DWARF-2 expression
|
||||
|
@ -2008,10 +2490,12 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
|
|||
struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
|
||||
const gdb_byte *data;
|
||||
size_t size;
|
||||
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
|
||||
|
||||
data = find_location_expression (dlbaton, &size, ax->scope);
|
||||
|
||||
dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value, data, size);
|
||||
compile_dwarf_to_ax (ax, value, gdbarch, addr_size, data, data + size,
|
||||
dlbaton->per_cu);
|
||||
}
|
||||
|
||||
/* The set of location functions used with the DWARF-2 expression
|
||||
|
|
34
gdb/vec.h
34
gdb/vec.h
|
@ -184,6 +184,13 @@
|
|||
|
||||
#define VEC_free(T,V) (VEC_OP(T,free)(&V))
|
||||
|
||||
/* A cleanup function for a vector.
|
||||
void VEC_T_cleanup(void *);
|
||||
|
||||
Clean up a vector. */
|
||||
|
||||
#define VEC_cleanup(T) (VEC_OP(T,cleanup))
|
||||
|
||||
/* Use these to determine the required size and initialization of a
|
||||
vector embedded within another structure (as the final member).
|
||||
|
||||
|
@ -461,6 +468,15 @@ static inline void VEC_OP (T,free) \
|
|||
*vec_ = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (T,cleanup) \
|
||||
(void *arg_) \
|
||||
{ \
|
||||
VEC(T) **vec_ = arg_; \
|
||||
if (*vec_) \
|
||||
vec_free_ (*vec_); \
|
||||
*vec_ = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline int VEC_OP (T,reserve) \
|
||||
(VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \
|
||||
{ \
|
||||
|
@ -699,6 +715,15 @@ static inline void VEC_OP (T,free) \
|
|||
*vec_ = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (T,cleanup) \
|
||||
(void *arg_) \
|
||||
{ \
|
||||
VEC(T) **vec_ = arg_; \
|
||||
if (*vec_) \
|
||||
vec_free_ (*vec_); \
|
||||
*vec_ = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \
|
||||
{ \
|
||||
size_t len_ = vec_ ? vec_->num : 0; \
|
||||
|
@ -957,6 +982,15 @@ static inline void VEC_OP (T,free) \
|
|||
*vec_ = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void VEC_OP (T,cleanup) \
|
||||
(void *arg_) \
|
||||
{ \
|
||||
VEC(T) **vec_ = arg_; \
|
||||
if (*vec_) \
|
||||
vec_free_ (*vec_); \
|
||||
*vec_ = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline int VEC_OP (T,reserve) \
|
||||
(VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \
|
||||
{ \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue