diff options
author | Tom Tromey <tromey@redhat.com> | 2010-06-02 19:37:56 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2010-06-02 19:37:56 +0000 |
commit | 9eae7c5264c14e142dd52988f70d58f62755b2d0 (patch) | |
tree | 526ab8c146436f412c8cb66a4e5b0457714ad482 /gdb/dwarf2loc.c | |
parent | 359cc68c808f70750a020c9bb76de330735a3202 (diff) | |
download | gdb-9eae7c5264c14e142dd52988f70d58f62755b2d0.zip gdb-9eae7c5264c14e142dd52988f70d58f62755b2d0.tar.gz gdb-9eae7c5264c14e142dd52988f70d58f62755b2d0.tar.bz2 |
gdb
* dwarf2loc.h (dwarf2_per_cu_data): Declare.
* dwarf2read.c (dwarf_stack_op_name): No longer static. Return
type is const. Add 'def' argument. Add missing operators, remove
unhandled ones.
(decode_locdesc): Update.
(dwarf2_always_disassemble): New global.
(show_dwarf2_always_disassemble): New function.
(_initialize_dwarf2_read): Add always-disassemble.
(dwarf2_per_cu_offset_size): New function.
* dwarf2loc.c (dwarf2_always_disassemble): Declare.
(piece_end_p): New function.
(locexpr_describe_location_piece): Replace 'size' argument with
'end'. Use piece_end_p. Rewrite recognition of TLS. Recognize
some constants. Remove errors.
(disassemble_dwarf_expression): New function.
(locexpr_describe_location_1): Use disassemble_dwarf_expression.
Add 'offset_size' argument.
(loclist_describe_location): Change output formatting.
* dwarf2expr.h (dwarf_stack_op_name): Declare.
gdb/doc
* gdb.texinfo (Maintenance Commands): Document maint set dwarf2
always-disassemble.
Diffstat (limited to 'gdb/dwarf2loc.c')
-rw-r--r-- | gdb/dwarf2loc.c | 424 |
1 files changed, 370 insertions, 54 deletions
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 79d2277..30464ff 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -42,6 +42,8 @@ #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); @@ -1291,13 +1293,24 @@ locexpr_read_needs_frame (struct symbol *symbol) 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); @@ -1314,7 +1327,7 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, { 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)); @@ -1325,10 +1338,15 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, 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) @@ -1372,19 +1390,18 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, 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"), @@ -1404,13 +1421,14 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream, 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, @@ -1420,9 +1438,275 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *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; } @@ -1434,40 +1718,78 @@ static void 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; + } } } @@ -1486,9 +1808,10 @@ locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr, 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 @@ -1572,6 +1895,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, 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, @@ -1581,7 +1905,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, 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) @@ -1598,7 +1922,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, { 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; @@ -1609,11 +1933,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, /* 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; @@ -1622,20 +1942,16 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, 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; } |