RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece)

Tom Tromey
2010-05-25T19:17:07Z

>>>>> "Stan" == Stan Shebs <stanshebs@earthlink.net> writes:

Stan> Which rewrite is that? I can see switching to opcode disassembly for
Stan> heinously-complicated location expressions, but multiple pieces and
Stan> reg/offset seem reasonable to describe verbally - if nothing else, it
Stan> conveys to the user that a local has a nontrivial liveness range and
Stan> lives in different places at different times, so the user needs to be
Stan> cautious when a register or stack location seems to have a wrong value
Stan> in it.

Here is what I came up with. Let me know what you think.

With this patch, by default GDB still tries to describe a location in a
"human readable" form. This is not always possible, though, and in
those cases it falls back to a disassembly form. Additionally, it adds
a new parameter, "maint show dwarf2 always-disassemble", which can be
set if you prefer to always get disassembly.

Sample still-pretty output:

(gdb) info addr argc
Symbol "argc" is a variable at frame base reg $ebp offset 8+0.

(This is identical to the existing output.)

Here is existing gdb on a complicated expression. Maybe not the ideal
example since it uses something not currently understood (but still ok,
because the new approach is much more complete and will only barf on
expressions that gdb cannot actually evaluate):

(gdb) info addr a
Symbol "a" is multi-location (range 0x8048440-0x8048448, a variable with complex or multiple locations (DWARF2)Corrupted DWARF2 expression for "a".

The new output. This is pretty verbose, but I think this is a feature.

(gdb) info addr a
Symbol "a" is multi-location:
Range 0x8048440-0x8048448: the constant 4 [12-bit piece, offset 0 bits], and an empty 20-bit piece
Range 0x8048448-0x804844b: the constant 4 [12-bit piece, offset 0 bits], and a complex DWARF expression:
1: DW_OP_fbreg 0
3: DW_OP_deref_size 2
5: DW_OP_plus_uconst 6
7: DW_OP_stack_value
[12-bit piece, offset 0 bits], and an empty 1-byte piece
Range 0x804844b-0x804845b: a variable in $edx [12-bit piece, offset 0 bits], and a complex DWARF expression:
1: DW_OP_fbreg 0
3: DW_OP_deref_size 2
5: DW_OP_plus_uconst 7
7: DW_OP_stack_value
[12-bit piece, offset 0 bits], and an empty 1-byte piece
Range 0x804845b-0x804847d: a variable in $esi [12-bit piece, offset 0 bits], and a complex DWARF expression:
1: DW_OP_fbreg 0
3: DW_OP_deref_size 2
5: DW_OP_plus_uconst 7
7: DW_OP_stack_value
[12-bit piece, offset 0 bits], and an empty 1-byte piece
Range 0x804847d-0x8048481: an empty 12-bit piece, and a complex DWARF expression:
1: DW_OP_fbreg 0
3: DW_OP_deref_size 2
5: DW_OP_plus_uconst 7
7: DW_OP_stack_value
[12-bit piece, offset 0 bits], and an empty 1-byte piece
.

Built and regression-tested on x86-64 (compile farm).
This includes a doc update.

Tom

2010-05-24 Tom Tromey <tromey@redhat.com>

* 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.
* 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.
(loclist_describe_location): Change output formatting.
* dwarf2expr.h (dwarf_stack_op_name): Declare.

2010-05-24 Tom Tromey <tromey@redhat.com>

* gdb.texinfo (Maintenance Commands): Document maint set dwarf2
always-disassemble.

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e929481..741f423 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29862,6 +29862,20 @@ that symbol is described. The type chain produced by this command is
a recursive definition of the data type as stored in @value{GDBN}'s
data structures, including its flags and contained types.

+@kindex maint set dwarf2 always-disassemble
+@kindex maint show dwarf2 always-disassemble
+@item maint set dwarf2 always-disassemble
+@item maint show dwarf2 always-disassemble
+Control the behavior of @code{info address} when using DWARF debugging
+information.
+
+The default is @code{off}, which means that @value{GDBN} should try to
+describe a variable's location in an easily readable format. When
+@code{on}, @value{GDBN} will instead display the DWARF location
+expression in an assembly-like format. Note that some locations are
+too complex for @value{GDBN} to describe simply; in this case you will
+always see the disassembly form.
+
@kindex maint set dwarf2 max-cache-age
@kindex maint show dwarf2 max-cache-age
@item maint set dwarf2 max-cache-age
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index a0f4554..8ebbf87 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -208,4 +208,6 @@ const gdb_byte *read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
CORE_ADDR dwarf2_read_address (struct gdbarch *gdbarch, const gdb_byte *buf,
const gdb_byte *buf_end, int addr_size);

+const char *dwarf_stack_op_name (unsigned int, int);
+
#endif /* dwarf2expr.h */
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 481501b..48bb1aa 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);
@@ -1282,13 +1284,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);
@@ -1305,7 +1318,7 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
{
ULONGEST reg;

- data = read_uleb128 (data + 1, data + size, &reg);
+ data = read_uleb128 (data + 1, end, &reg);
regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
fprintf_filtered (stream, _("a variable in $%s"),
gdbarch_register_name (gdbarch, regno));
@@ -1316,10 +1329,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)
@@ -1363,19 +1381,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"),
@@ -1395,13 +1412,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,
@@ -1411,9 +1429,221 @@ 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,
+ 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_regx:
+ data = read_uleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s", pulongest (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", pulongest (ul));
+ break;
+
+ case DW_OP_bregx:
+ {
+ ULONGEST offset;
+
+ data = read_uleb128 (data, end, &ul);
+ data = read_sleb128 (data, end, &offset);
+ fprintf_filtered (stream, " register %s offset %s",
+ pulongest (ul), pulongest (offset));
+ }
+ break;
+
+ case DW_OP_fbreg:
+ data = read_sleb128 (data, end, &ul);
+ fprintf_filtered (stream, " %s", pulongest (ul));
+ break;
+
+ case DW_OP_pick:
+ fprintf_filtered (stream, " %d", *data);
+ ++data;
+ break;
+
+ case DW_OP_deref_size:
+ {
+ int addr_size = *data++;
+
+ fprintf_filtered (stream, " %d", addr_size);
+ }
+ 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_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;
}
@@ -1428,37 +1658,74 @@ locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
struct objfile *objfile, unsigned int addr_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, 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;
+ }
}
}

@@ -1572,7 +1839,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)
@@ -1589,7 +1856,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;
@@ -1600,11 +1867,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;
@@ -1613,21 +1876,17 @@ 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);

+ fprintf_filtered (stream, "\n");
+
loc_ptr += length;
}
}
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 129d6c1..8d74fb4 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1002,8 +1002,6 @@ static char *dwarf_attr_name (unsigned int);

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);
@@ -9848,8 +9846,8 @@ dwarf_form_name (unsigned form)

/* 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)
{
@@ -10152,32 +10150,24 @@ dwarf_stack_op_name (unsigned 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;
}
}

@@ -11018,7 +11008,7 @@ decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu)

default:
complaint (&symfile_complaints, _("unsupported stack op: '%s'"),
- dwarf_stack_op_name (op));
+ dwarf_stack_op_name (op, 1));
return (stack[stacki]);
}
}
@@ -12199,6 +12189,17 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
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
@@ -12231,6 +12232,18 @@ caching, which can slow down startup."),
&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."), _("\