#include "gdb_string.h"
#include "gdb_assert.h"
+extern int dwarf2_always_disassemble;
+
static void
dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
const gdb_byte **start, size_t *length);
dlbaton->per_cu);
}
-/* Describe a single piece of a location, returning an updated
- position in the bytecode sequence. */
+/* Return true if DATA points to the end of a piece. END is one past
+ the last byte in the expression. */
+
+static int
+piece_end_p (const gdb_byte *data, const gdb_byte *end)
+{
+ return data == end || data[0] == DW_OP_piece || data[0] == DW_OP_bit_piece;
+}
+
+/* Nicely describe a single piece of a location, returning an updated
+ position in the bytecode sequence. This function cannot recognize
+ all locations; if a location is not recognized, it simply returns
+ DATA. */
static const gdb_byte *
locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
CORE_ADDR addr, struct objfile *objfile,
- const gdb_byte *data, int size,
+ const gdb_byte *data, const gdb_byte *end,
unsigned int addr_size)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
{
ULONGEST reg;
- data = read_uleb128 (data + 1, data + size, ®);
+ data = read_uleb128 (data + 1, end, ®);
regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
fprintf_filtered (stream, _("a variable in $%s"),
gdbarch_register_name (gdbarch, regno));
struct symbol *framefunc;
int frame_reg = 0;
LONGEST frame_offset;
- const gdb_byte *base_data;
+ const gdb_byte *base_data, *new_data;
size_t base_size;
LONGEST base_offset = 0;
+ new_data = read_sleb128 (data + 1, end, &frame_offset);
+ if (!piece_end_p (new_data, end))
+ return data;
+ data = new_data;
+
b = block_for_pc (addr);
if (!b)
regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, frame_reg);
- data = read_sleb128 (data + 1, data + size, &frame_offset);
-
fprintf_filtered (stream, _("a variable at frame base reg $%s offset %s+%s"),
gdbarch_register_name (gdbarch, regno),
plongest (base_offset), plongest (frame_offset));
}
- else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31)
+ else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31
+ && piece_end_p (data, end))
{
LONGEST offset;
regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_breg0);
- data = read_sleb128 (data + 1, data + size, &offset);
+ data = read_sleb128 (data + 1, end, &offset);
fprintf_filtered (stream,
_("a variable at offset %s from base reg $%s"),
The operand represents the offset at which the variable is within
the thread local storage. */
- else if (size > 1
- && data[size - 1] == DW_OP_GNU_push_tls_address
- && data[0] == DW_OP_addr)
+ else if (data + 1 + addr_size < end
+ && data[0] == DW_OP_addr
+ && data[1 + addr_size] == DW_OP_GNU_push_tls_address
+ && piece_end_p (data + 2 + addr_size, end))
{
CORE_ADDR offset = dwarf2_read_address (gdbarch,
data + 1,
- data + size - 1,
+ end,
addr_size);
fprintf_filtered (stream,
data += 1 + addr_size + 1;
}
- else
- fprintf_filtered (stream,
- _("a variable with complex or multiple locations (DWARF2)"));
+ else if (data[0] >= DW_OP_lit0
+ && data[0] <= DW_OP_lit31
+ && data + 1 < end
+ && data[1] == DW_OP_stack_value)
+ {
+ fprintf_filtered (stream, _("the constant %d"), data[0] - DW_OP_lit0);
+ data += 2;
+ }
+
+ return data;
+}
+
+/* Disassemble an expression, stopping at the end of a piece or at the
+ end of the expression. Returns a pointer to the next unread byte
+ in the input expression. If ALL is nonzero, then this function
+ will keep going until it reaches the end of the expression. */
+
+static const gdb_byte *
+disassemble_dwarf_expression (struct ui_file *stream,
+ struct gdbarch *arch, unsigned int addr_size,
+ int offset_size,
+ const gdb_byte *data, const gdb_byte *end,
+ int all)
+{
+ const gdb_byte *start = data;
+
+ fprintf_filtered (stream, _("a complex DWARF expression:\n"));
+
+ while (data < end
+ && (all
+ || (data[0] != DW_OP_piece && data[0] != DW_OP_bit_piece)))
+ {
+ enum dwarf_location_atom op = *data++;
+ CORE_ADDR addr;
+ ULONGEST ul;
+ LONGEST l;
+ const char *name;
+
+ name = dwarf_stack_op_name (op, 0);
+
+ if (!name)
+ error (_("Unrecognized DWARF opcode 0x%02x at %ld"),
+ op, (long) (data - start));
+ fprintf_filtered (stream, " % 4ld: %s", (long) (data - start), name);
+
+ switch (op)
+ {
+ case DW_OP_addr:
+ addr = dwarf2_read_address (arch, data, end, addr_size);
+ data += addr_size;
+ fprintf_filtered (stream, " %s", paddress (arch, addr));
+ break;
+
+ case DW_OP_const1u:
+ ul = extract_unsigned_integer (data, 1, gdbarch_byte_order (arch));
+ data += 1;
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+ case DW_OP_const1s:
+ l = extract_signed_integer (data, 1, gdbarch_byte_order (arch));
+ data += 1;
+ fprintf_filtered (stream, " %s", plongest (l));
+ break;
+ case DW_OP_const2u:
+ ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+ data += 2;
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+ case DW_OP_const2s:
+ l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+ data += 2;
+ fprintf_filtered (stream, " %s", plongest (l));
+ break;
+ case DW_OP_const4u:
+ ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+ data += 4;
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+ case DW_OP_const4s:
+ l = extract_signed_integer (data, 4, gdbarch_byte_order (arch));
+ data += 4;
+ fprintf_filtered (stream, " %s", plongest (l));
+ break;
+ case DW_OP_const8u:
+ ul = extract_unsigned_integer (data, 8, gdbarch_byte_order (arch));
+ data += 8;
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+ case DW_OP_const8s:
+ l = extract_signed_integer (data, 8, gdbarch_byte_order (arch));
+ data += 8;
+ fprintf_filtered (stream, " %s", plongest (l));
+ break;
+ case DW_OP_constu:
+ data = read_uleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+ case DW_OP_consts:
+ data = read_sleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s", plongest (l));
+ 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:
+ fprintf_filtered (stream, " [$%s]",
+ gdbarch_register_name (arch, op - DW_OP_reg0));
+ break;
+
+ case DW_OP_regx:
+ data = read_uleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s [$%s]", pulongest (ul),
+ gdbarch_register_name (arch, (int) ul));
+ break;
+
+ case DW_OP_implicit_value:
+ data = read_uleb128 (data, end, &ul);
+ data += ul;
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ 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:
+ data = read_sleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s [$%s]", pulongest (ul),
+ gdbarch_register_name (arch, op - DW_OP_breg0));
+ break;
+
+ case DW_OP_bregx:
+ {
+ ULONGEST offset;
+
+ data = read_uleb128 (data, end, &ul);
+ data = read_sleb128 (data, end, &offset);
+ fprintf_filtered (stream, " register %s [$%s] offset %s",
+ pulongest (ul),
+ gdbarch_register_name (arch, (int) ul),
+ pulongest (offset));
+ }
+ break;
+
+ case DW_OP_fbreg:
+ data = read_sleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+
+ case DW_OP_xderef_size:
+ case DW_OP_deref_size:
+ case DW_OP_pick:
+ fprintf_filtered (stream, " %d", *data);
+ ++data;
+ break;
+
+ case DW_OP_plus_uconst:
+ data = read_uleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+
+ case DW_OP_skip:
+ l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+ data += 2;
+ fprintf_filtered (stream, " to %ld",
+ (long) (data + l - start));
+ break;
+
+ case DW_OP_bra:
+ l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+ data += 2;
+ fprintf_filtered (stream, " %ld",
+ (long) (data + l - start));
+ break;
+
+ case DW_OP_call2:
+ ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+ data += 2;
+ fprintf_filtered (stream, " offset %s", phex_nz (ul, 2));
+ break;
+
+ case DW_OP_call4:
+ ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+ data += 4;
+ fprintf_filtered (stream, " offset %s", phex_nz (ul, 4));
+ break;
+
+ case DW_OP_call_ref:
+ ul = extract_unsigned_integer (data, offset_size,
+ gdbarch_byte_order (arch));
+ data += offset_size;
+ fprintf_filtered (stream, " offset %s", phex_nz (ul, offset_size));
+ break;
+
+ case DW_OP_piece:
+ data = read_uleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s (bytes)", pulongest (ul));
+ break;
+
+ case DW_OP_bit_piece:
+ {
+ ULONGEST offset;
+
+ data = read_uleb128 (data, end, &ul);
+ data = read_uleb128 (data, end, &offset);
+ fprintf_filtered (stream, " size %s offset %s (bits)",
+ pulongest (ul), pulongest (offset));
+ }
+ break;
+ }
+
+ fprintf_filtered (stream, "\n");
+ }
return data;
}
locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
struct ui_file *stream,
const gdb_byte *data, int size,
- struct objfile *objfile, unsigned int addr_size)
+ struct objfile *objfile, unsigned int addr_size,
+ int offset_size)
{
const gdb_byte *end = data + size;
- int piece_done = 0, first_piece = 1, bad = 0;
+ int first_piece = 1, bad = 0;
- /* A multi-piece description consists of multiple sequences of bytes
- each followed by DW_OP_piece + length of piece. */
while (data < end)
{
- if (!piece_done)
- {
- if (first_piece)
- first_piece = 0;
- else
- fprintf_filtered (stream, _(", and "));
+ const gdb_byte *here = data;
+ int disassemble = 1;
+
+ if (first_piece)
+ first_piece = 0;
+ else
+ fprintf_filtered (stream, _(", and "));
+ if (!dwarf2_always_disassemble)
+ {
data = locexpr_describe_location_piece (symbol, stream, addr, objfile,
- data, size, addr_size);
- piece_done = 1;
+ data, end, addr_size);
+ /* If we printed anything, or if we have an empty piece,
+ then don't disassemble. */
+ if (data != here
+ || data[0] == DW_OP_piece
+ || data[0] == DW_OP_bit_piece)
+ disassemble = 0;
}
- else if (data[0] == DW_OP_piece)
+ if (disassemble)
+ data = disassemble_dwarf_expression (stream, get_objfile_arch (objfile),
+ addr_size, offset_size, data, end,
+ dwarf2_always_disassemble);
+
+ if (data < end)
{
- ULONGEST bytes;
+ int empty = data == here;
- data = read_uleb128 (data + 1, end, &bytes);
+ if (disassemble)
+ fprintf_filtered (stream, " ");
+ if (data[0] == DW_OP_piece)
+ {
+ ULONGEST bytes;
- fprintf_filtered (stream, _(" [%s-byte piece]"), pulongest (bytes));
+ data = read_uleb128 (data + 1, end, &bytes);
- piece_done = 0;
- }
- else
- {
- bad = 1;
- break;
+ if (empty)
+ fprintf_filtered (stream, _("an empty %s-byte piece"),
+ pulongest (bytes));
+ else
+ fprintf_filtered (stream, _(" [%s-byte piece]"),
+ pulongest (bytes));
+ }
+ else if (data[0] == DW_OP_bit_piece)
+ {
+ ULONGEST bits, offset;
+
+ data = read_uleb128 (data + 1, end, &bits);
+ data = read_uleb128 (data, end, &offset);
+
+ if (empty)
+ fprintf_filtered (stream,
+ _("an empty %s-bit piece"),
+ pulongest (bits));
+ else
+ fprintf_filtered (stream,
+ _(" [%s-bit piece, offset %s bits]"),
+ pulongest (bits), pulongest (offset));
+ }
+ else
+ {
+ bad = 1;
+ break;
+ }
}
}
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
struct objfile *objfile = dwarf2_per_cu_objfile (dlbaton->per_cu);
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
+ int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu);
locexpr_describe_location_1 (symbol, addr, stream, dlbaton->data, dlbaton->size,
- objfile, addr_size);
+ objfile, addr_size, offset_size);
}
/* Describe the location of SYMBOL as an agent value in VALUE, generating
struct gdbarch *gdbarch = get_objfile_arch (objfile);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
+ int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu);
CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
/* Adjust base_address for relocatable objects. */
CORE_ADDR base_offset = ANOFFSET (objfile->section_offsets,
loc_ptr = dlbaton->data;
buf_end = dlbaton->data + dlbaton->size;
- fprintf_filtered (stream, _("multi-location ("));
+ fprintf_filtered (stream, _("multi-location:\n"));
/* Iterate through locations until we run out. */
while (1)
{
base_address = dwarf2_read_address (gdbarch,
loc_ptr, buf_end, addr_size);
- fprintf_filtered (stream, _("[base address %s]"),
+ fprintf_filtered (stream, _(" Base address %s"),
paddress (gdbarch, base_address));
loc_ptr += addr_size;
continue;
/* An end-of-list entry. */
if (low == 0 && high == 0)
- {
- /* Indicate the end of the list, for readability. */
- fprintf_filtered (stream, _(")"));
- return;
- }
+ break;
/* Otherwise, a location expression entry. */
low += base_address;
length = extract_unsigned_integer (loc_ptr, 2, byte_order);
loc_ptr += 2;
- /* Separate the different locations with a semicolon. */
- if (first)
- first = 0;
- else
- fprintf_filtered (stream, _("; "));
-
/* (It would improve readability to print only the minimum
necessary digits of the second number of the range.) */
- fprintf_filtered (stream, _("range %s-%s, "),
+ fprintf_filtered (stream, _(" Range %s-%s: "),
paddress (gdbarch, low), paddress (gdbarch, high));
/* Now describe this particular location. */
locexpr_describe_location_1 (symbol, low, stream, loc_ptr, length,
- objfile, addr_size);
+ objfile, addr_size, offset_size);
+
+ fprintf_filtered (stream, "\n");
loc_ptr += length;
}
static char *dwarf_form_name (unsigned int);
-static char *dwarf_stack_op_name (unsigned int);
-
static char *dwarf_bool_name (unsigned int);
static char *dwarf_type_encoding_name (unsigned int);
/* Convert a DWARF stack opcode into its string name. */
-static char *
-dwarf_stack_op_name (unsigned op)
+const char *
+dwarf_stack_op_name (unsigned op, int def)
{
switch (op)
{
return "DW_OP_call4";
case DW_OP_call_ref:
return "DW_OP_call_ref";
- /* GNU extensions. */
case DW_OP_form_tls_address:
return "DW_OP_form_tls_address";
case DW_OP_call_frame_cfa:
return "DW_OP_call_frame_cfa";
case DW_OP_bit_piece:
return "DW_OP_bit_piece";
+ /* DWARF 4 extensions. */
+ case DW_OP_implicit_value:
+ return "DW_OP_implicit_value";
+ case DW_OP_stack_value:
+ return "DW_OP_stack_value";
+ /* GNU extensions. */
case DW_OP_GNU_push_tls_address:
return "DW_OP_GNU_push_tls_address";
case DW_OP_GNU_uninit:
return "DW_OP_GNU_uninit";
- /* HP extensions. */
- case DW_OP_HP_is_value:
- return "DW_OP_HP_is_value";
- case DW_OP_HP_fltconst4:
- return "DW_OP_HP_fltconst4";
- case DW_OP_HP_fltconst8:
- return "DW_OP_HP_fltconst8";
- case DW_OP_HP_mod_range:
- return "DW_OP_HP_mod_range";
- case DW_OP_HP_unmod_range:
- return "DW_OP_HP_unmod_range";
- case DW_OP_HP_tls:
- return "DW_OP_HP_tls";
default:
- return "OP_<unknown>";
+ return def ? "OP_<unknown>" : NULL;
}
}
default:
complaint (&symfile_complaints, _("unsupported stack op: '%s'"),
- dwarf_stack_op_name (op));
+ dwarf_stack_op_name (op, 1));
return (stack[stacki]);
}
}
}
}
+/* Return the offset size given in the compilation unit header for CU. */
+
+int
+dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu)
+{
+ if (per_cu->cu)
+ return per_cu->cu->header.offset_size;
+ else
+ {
+ /* If the CU is not currently read in, we re-read its header. */
+ struct objfile *objfile = per_cu->psymtab->objfile;
+ struct dwarf2_per_objfile *per_objfile
+ = objfile_data (objfile, dwarf2_objfile_data_key);
+ gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset;
+ struct comp_unit_head cu_header;
+
+ memset (&cu_header, 0, sizeof cu_header);
+ read_comp_unit_head (&cu_header, info_ptr, objfile->obfd);
+ return cu_header.offset_size;
+ }
+}
+
/* Locate the .debug_info compilation unit from CU's objfile which contains
the DIE at OFFSET. Raises an error on failure. */
munmap_section_buffer (&data->eh_frame);
}
+int dwarf2_always_disassemble;
+
+static void
+show_dwarf2_always_disassemble (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether to always disassemble DWARF expressions is %s.\n"),
+ value);
+}
+
void _initialize_dwarf2_read (void);
void
&set_dwarf2_cmdlist,
&show_dwarf2_cmdlist);
+ add_setshow_boolean_cmd ("always-disassemble", class_obscure,
+ &dwarf2_always_disassemble, _("\
+Set whether `info address' always disassembles DWARF expressions."), _("\
+Show whether `info address' always disassembles DWARF expressions."), _("\
+When enabled, DWARF expressions are always printed in an assembly-like\n\
+syntax. When disabled, expressions will be printed in a more\n\
+conversational style, when possible."),
+ NULL,
+ show_dwarf2_always_disassemble,
+ &set_dwarf2_cmdlist,
+ &show_dwarf2_cmdlist);
+
add_setshow_zinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\
Set debugging of the dwarf2 DIE reader."), _("\
Show debugging of the dwarf2 DIE reader."), _("\