Re: RFC: implement DW_OP_stack_value and DW_OP_implicit_value

Tom Tromey
2009-09-04T22:34:09Z

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> This patch implements the new DWARF 4 opcodes DW_OP_stack_value and
Tom> DW_OP_implicit_value. The svn trunk GCC can generate these under some
Tom> conditions.

Here is a version that has been updated for Nathan's recent change.

I added an 'arch' field to piece_closure because we need the objfile's
architecture when decoding a stack value; I think we can't use the
frame's architecture because we might not have a frame.

Let me know what you think.

Tom

ChangeLog:
2009-09-04 Tom Tromey <tromey@redhat.com>

* dwarf2loc.c (struct piece_closure) <arch>: New field.
(dwarf2_evaluate_loc_desc): Update.
(dwarf2_loc_desc_needs_frame): Likewise.
(allocate_piece_closure): Initialize new field.
(read_pieced_value): Update.
(write_pieced_value): Update.
(copy_pieced_value_closure): Update.
* dwarf2expr.h (enum dwarf_value_location): New.
(struct dwarf_expr_context) <in_reg>: Remove.
<location, len, data>: New fields.
(struct dwarf_expr_piece) <in_reg, value>: Remove.
<location, v>: New fields.
* dwarf2expr.c (add_piece): Remove in_reg, value arguments.
Update.
(require_composition): New function.
(execute_stack_op): Update.
<DW_OP_implicit_value, DW_OP_stack_value>: New cases.
<DW_OP_reg0>: Set location, not in_reg.
<DW_OP_regx>: Likewise. Use require_composition.
<DW_OP_fbreg>: Update.
<DW_OP_piece>: Likewise.
* dwarf2-frame.c (execute_stack_op): Update.

testsuite/ChangeLog:
2009-09-04 Tom Tromey <tromey@redhat.com>

* gdb.dwarf2/valop.S: New file.
* gdb.dwarf2/valop.exp: New file.

Index: dwarf2-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2-frame.c,v
retrieving revision 1.97
diff -u -r1.97 dwarf2-frame.c
--- dwarf2-frame.c 2 Sep 2009 14:53:55 -0000 1.97
+++ dwarf2-frame.c 4 Sep 2009 22:31:48 -0000
@@ -379,8 +379,15 @@
dwarf_expr_eval (ctx, exp, len);
result = dwarf_expr_fetch (ctx, 0);

- if (ctx->in_reg)
+ if (ctx->location == DWARF_VALUE_REGISTER)
result = read_reg (this_frame, result);
+ else if (ctx->location != DWARF_VALUE_MEMORY)
+ {
+ /* This is actually invalid DWARF, but if we ever do run across
+ it somehow, we might as well support it. So, instead, report
+ it as unimplemented. */
+ error (_("Not implemented: computing unwound register using explicit value operator"));
+ }

do_cleanups (old_chain);

Index: dwarf2expr.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2expr.c,v
retrieving revision 1.35
diff -u -r1.35 dwarf2expr.c
--- dwarf2expr.c 2 Sep 2009 14:53:55 -0000 1.35
+++ dwarf2expr.c 4 Sep 2009 22:31:48 -0000
@@ -125,8 +125,7 @@

/* Add a new piece to CTX's piece list. */
static void
-add_piece (struct dwarf_expr_context *ctx,
- int in_reg, CORE_ADDR value, ULONGEST size)
+add_piece (struct dwarf_expr_context *ctx, ULONGEST size)
{
struct dwarf_expr_piece *p;

@@ -141,9 +140,15 @@
* sizeof (struct dwarf_expr_piece));

p = &ctx->pieces[ctx->num_pieces - 1];
- p->in_reg = in_reg;
- p->value = value;
+ p->location = ctx->location;
p->size = size;
+ if (p->location == DWARF_VALUE_LITERAL)
+ {
+ p->v.literal.data = ctx->data;
+ p->v.literal.length = ctx->len;
+ }
+ else
+ p->v.value = dwarf_expr_fetch (ctx, 0);
}

/* Evaluate the expression at ADDR (LEN bytes long) using the context
@@ -287,6 +292,23 @@
}
}
\f
+
+/* 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 (gdb_byte *op_ptr, gdb_byte *op_end, const char *op_name)
+{
+ /* It seems like DW_OP_GNU_uninit should be handled here. However,
+ it doesn't seem to make sense for DW_OP_*_value, and it was not
+ checked at the other place that this function is called. */
+ if (op_ptr != op_end && *op_ptr != DW_OP_piece && *op_ptr != DW_OP_bit_piece)
+ error (_("DWARF-2 expression error: `%s' operations must be "
+ "used either alone or in conjuction with DW_OP_piece "
+ "or DW_OP_bit_piece."),
+ op_name);
+}
+
/* The engine for the expression evaluator. Using the context in CTX,
evaluate the expression between OP_PTR and OP_END. */

@@ -295,8 +317,7 @@
gdb_byte *op_ptr, gdb_byte *op_end)
{
enum bfd_endian byte_order = gdbarch_byte_order (ctx->gdbarch);
-
- ctx->in_reg = 0;
+ ctx->location = DWARF_VALUE_MEMORY;
ctx->initialized = 1; /* Default is initialized. */

if (ctx->recursion_depth > ctx->max_recursion_depth)
@@ -436,20 +457,36 @@
"used either alone or in conjuction with DW_OP_piece."));

result = op - DW_OP_reg0;
- ctx->in_reg = 1;
-
+ ctx->location = DWARF_VALUE_REGISTER;
break;

case DW_OP_regx:
op_ptr = read_uleb128 (op_ptr, op_end, &reg);
- if (op_ptr != op_end && *op_ptr != DW_OP_piece)
- error (_("DWARF-2 expression error: DW_OP_reg operations must be "
- "used either alone or in conjuction with DW_OP_piece."));
+ require_composition (op_ptr, op_end, "DW_OP_regx");

result = reg;
- ctx->in_reg = 1;
+ ctx->location = DWARF_VALUE_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."));
+ ctx->len = len;
+ ctx->data = op_ptr;
+ ctx->location = DWARF_VALUE_LITERAL;
+ op_ptr += len;
+ 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");
+ goto no_push;
+
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
@@ -513,12 +550,15 @@
specific this_base method. */
(ctx->get_frame_base) (ctx->baton, &datastart, &datalen);
dwarf_expr_eval (ctx, datastart, datalen);
+ if (ctx->location == DWARF_VALUE_LITERAL
+ || ctx->location == DWARF_VALUE_STACK)
+ error (_("Not implemented: computing frame base using explicit value operator"));
result = dwarf_expr_fetch (ctx, 0);
- if (ctx->in_reg)
+ if (ctx->location == DWARF_VALUE_REGISTER)
result = (ctx->read_reg) (ctx->baton, result);
result = result + offset;
ctx->stack_len = before_stack_len;
- ctx->in_reg = 0;
+ ctx->location = DWARF_VALUE_MEMORY;
}
break;
case DW_OP_dup:
@@ -758,12 +798,13 @@

/* Record the piece. */
op_ptr = read_uleb128 (op_ptr, op_end, &size);
- addr_or_regnum = dwarf_expr_fetch (ctx, 0);
- add_piece (ctx, ctx->in_reg, addr_or_regnum, size);
+ add_piece (ctx, size);

- /* Pop off the address/regnum, and clear the in_reg flag. */
- dwarf_expr_pop (ctx);
- ctx->in_reg = 0;
+ /* Pop off the address/regnum, and reset the location
+ type. */
+ if (ctx->location != DWARF_VALUE_LITERAL)
+ dwarf_expr_pop (ctx);
+ ctx->location = DWARF_VALUE_MEMORY;
}
goto no_push;

Index: dwarf2expr.h
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2expr.h,v
retrieving revision 1.17
diff -u -r1.17 dwarf2expr.h
--- dwarf2expr.h 2 Sep 2009 14:53:55 -0000 1.17
+++ dwarf2expr.h 4 Sep 2009 22:31:48 -0000
@@ -23,6 +23,19 @@
#if !defined (DWARF2EXPR_H)
#define DWARF2EXPR_H

+/* The location of a value. */
+enum dwarf_value_location
+{
+ /* The piece is in memory. */
+ DWARF_VALUE_MEMORY,
+ /* The piece is in a register. */
+ DWARF_VALUE_REGISTER,
+ /* The piece is on the stack. */
+ DWARF_VALUE_STACK,
+ /* The piece is a literal. */
+ DWARF_VALUE_LITERAL
+};
+
/* The expression evaluator works with a dwarf_expr_context, describing
its current state and its callbacks. */
struct dwarf_expr_context
@@ -80,9 +93,13 @@
depth we'll tolerate before raising an error. */
int recursion_depth, max_recursion_depth;

- /* Non-zero if the result is in a register. The register number
- will be on the expression stack. */
- int in_reg;
+ /* Location of the value. */
+ enum dwarf_value_location location;
+
+ /* For VALUE_LITERAL, a the current literal value's length and
+ data. */
+ ULONGEST len;
+ gdb_byte *data;

/* Initialization status of variable: Non-zero if variable has been
initialized; zero otherwise. */
@@ -93,9 +110,9 @@

Each time DW_OP_piece is executed, we add a new element to the
end of this array, recording the current top of the stack, the
- current in_reg flag, and the size given as the operand to
- DW_OP_piece. We then pop the top value from the stack, clear the
- in_reg flag, and resume evaluation.
+ current location, and the size given as the operand to
+ DW_OP_piece. We then pop the top value from the stack, rest the
+ location, and resume evaluation.

The Dwarf spec doesn't say whether DW_OP_piece pops the top value
from the stack. We do, ensuring that clients of this interface
@@ -106,12 +123,11 @@

If an expression never uses DW_OP_piece, num_pieces will be zero.
(It would be nice to present these cases as expressions yielding
- a single piece, with in_reg clear, so that callers need not
- distinguish between the no-DW_OP_piece and one-DW_OP_piece cases.
- But expressions with no DW_OP_piece operations have no value to
- place in a piece's 'size' field; the size comes from the
- surrounding data. So the two cases need to be handled
- separately.) */
+ a single piece, so that callers need not distinguish between the
+ no-DW_OP_piece and one-DW_OP_piece cases. But expressions with
+ no DW_OP_piece operations have no value to place in a piece's
+ 'size' field; the size comes from the surrounding data. So the
+ two cases need to be handled separately.) */
int num_pieces;
struct dwarf_expr_piece *pieces;
};
@@ -120,13 +136,22 @@
/* A piece of an object, as recorded by DW_OP_piece. */
struct dwarf_expr_piece
{
- /* If IN_REG is zero, then the piece is in memory, and VALUE is its address.
- If IN_REG is non-zero, then the piece is in a register, and VALUE
- is the register number. */
- int in_reg;
+ enum dwarf_value_location location;

- /* This piece's address or register number. */
- CORE_ADDR value;
+ union
+ {
+ /* This piece's address or register number. */
+ CORE_ADDR value;
+
+ struct
+ {
+ /* A pointer to the data making up this piece, for literal
+ pieces. */
+ gdb_byte *data;
+ /* The length of the available data. */
+ ULONGEST length;
+ } literal;
+ } v;

/* The length of the piece, in bytes. */
ULONGEST size;
Index: dwarf2loc.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.c,v
retrieving revision 1.66
diff -u -r1.66 dwarf2loc.c
--- dwarf2loc.c 4 Sep 2009 20:05:25 -0000 1.66
+++ dwarf2loc.c 4 Sep 2009 22:31:48 -0000
@@ -220,6 +220,9 @@
/* The number of pieces used to describe this variable. */
int n_pieces;

+ /* The architecture, used only for DWARF_VALUE_STACK. */
+ struct gdbarch *arch;
+
/* The pieces themselves. */
struct dwarf_expr_piece *pieces;
};
@@ -228,11 +231,13 @@
PIECES. */

static struct piece_closure *
-allocate_piece_closure (int n_pieces, struct dwarf_expr_piece *pieces)
+allocate_piece_closure (int n_pieces, struct dwarf_expr_piece *pieces,
+ struct gdbarch *arch)
{
struct piece_closure *c = XZALLOC (struct piece_closure);

c->n_pieces = n_pieces;
+ c->arch = arch;
c->pieces = XCALLOC (n_pieces, struct dwarf_expr_piece);

memcpy (c->pieces, pieces, n_pieces * sizeof (struct dwarf_expr_piece));
@@ -253,24 +258,49 @@
for (i = 0; i < c->n_pieces; i++)
{
struct dwarf_expr_piece *p = &c->pieces[i];
-
- if (frame == NULL)
- {
- memset (contents + offset, 0, p->size);
- set_value_optimized_out (v, 1);
- }
- else if (p->in_reg)
+ switch (p->location)
{
- struct gdbarch *arch = get_frame_arch (frame);
- gdb_byte regval[MAX_REGISTER_SIZE];
- int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->value);
+ case DWARF_VALUE_REGISTER:
+ {
+ struct gdbarch *arch = get_frame_arch (frame);
+ bfd_byte regval[MAX_REGISTER_SIZE];
+ int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch,
+ p->v.value);
+ get_frame_register (frame, gdb_regnum, regval);
+ memcpy (contents + offset, regval, p->size);
+ }
+ break;
+
+ case DWARF_VALUE_MEMORY:
+ read_memory (p->v.value, contents + offset, p->size);
+ break;
+
+ case DWARF_VALUE_STACK:
+ {
+ gdb_byte bytes[sizeof (ULONGEST)];
+ size_t n;
+ int addr_size = gdbarch_addr_bit (c->arch) / 8;
+ store_unsigned_integer (bytes, addr_size,
+ gdbarch_byte_order (c->arch),
+ p->v.value);
+ n = p->size;
+ if (n > addr_size)
+ n = addr_size;
+ memcpy (contents + offset, bytes, n);
+ }
+ break;
+
+ case DWARF_VALUE_LITERAL:
+ {
+ size_t n = p->size;
+ if (n > p->v.literal.length)
+ n = p->v.literal.length;
+ memcpy (contents + offset, p->v.literal.data, n);
+ }
+ break;

- get_frame_register (frame, gdb_regnum, regval);
- memcpy (contents + offset, regval, p->size);
- }
- else
- {
- read_memory (p->value, contents + offset, p->size);
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid location type"));
}
offset += p->size;
}
@@ -295,15 +325,21 @@
for (i = 0; i < c->n_pieces; i++)
{
struct dwarf_expr_piece *p = &c->pieces[i];
- if (p->in_reg)
+ switch (p->location)
{
- struct gdbarch *arch = get_frame_arch (frame);
- int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->value);
- put_frame_register (frame, gdb_regnum, contents + offset);
- }
- else
- {
- write_memory (p->value, contents + offset, p->size);
+ case DWARF_VALUE_REGISTER:
+ {
+ struct gdbarch *arch = get_frame_arch (frame);
+ int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.value);
+ put_frame_register (frame, gdb_regnum, contents + offset);
+ }
+ break;
+ case DWARF_VALUE_MEMORY:
+ write_memory (p->v.value, contents + offset, p->size);
+ break;
+ default:
+ set_value_optimized_out (to, 1);
+ return;
}
offset += p->size;
}
@@ -314,7 +350,7 @@
{
struct piece_closure *c = (struct piece_closure *) value_computed_closure (v);

- return allocate_piece_closure (c->n_pieces, c->pieces);
+ return allocate_piece_closure (c->n_pieces, c->pieces, c->arch);
}

static void
@@ -376,28 +412,71 @@
struct piece_closure *c;
struct frame_id frame_id = get_frame_id (frame);

- c = allocate_piece_closure (ctx->num_pieces, ctx->pieces);
+ c = allocate_piece_closure (ctx->num_pieces, ctx->pieces, ctx->gdbarch);
retval = allocate_computed_value (SYMBOL_TYPE (var),
&pieced_value_funcs,
c);
VALUE_FRAME_ID (retval) = frame_id;
}
- else if (ctx->in_reg)
- {
- struct gdbarch *arch = get_frame_arch (frame);
- CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0);
- int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum);
- retval = value_from_register (SYMBOL_TYPE (var), gdb_regnum, frame);
- }
else
{
- CORE_ADDR address = dwarf_expr_fetch (ctx, 0);
+ switch (ctx->location)
+ {
+ case DWARF_VALUE_REGISTER:
+ {
+ struct gdbarch *arch = get_frame_arch (frame);
+ CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0);
+ int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum);
+ retval = value_from_register (SYMBOL_TYPE (var), gdb_regnum, frame);
+ }
+ break;
+
+ case DWARF_VALUE_MEMORY:
+ {
+ CORE_ADDR address = dwarf_expr_fetch (ctx, 0);
+
+ retval = allocate_value (SYMBOL_TYPE (var));
+ VALUE_LVAL (retval) = lval_memory;
+ set_value_lazy (retval, 1);
+ set_value_stack (retval, 1);
+ set_value_address (retval, address);
+ }
+ break;
+
+ case DWARF_VALUE_STACK:
+ {
+ gdb_byte bytes[sizeof (ULONGEST)];
+ ULONGEST value = (ULONGEST) dwarf_expr_fetch (ctx, 0);
+ bfd_byte *contents;
+ size_t n = ctx->addr_size;
+
+ store_unsigned_integer (bytes, ctx->addr_size,
+ gdbarch_byte_order (ctx->gdbarch),
+ value);
+ retval = allocate_value (SYMBOL_TYPE (var));
+ contents = value_contents_raw (retval);
+ if (n > TYPE_LENGTH (SYMBOL_TYPE (var)))
+ n = TYPE_LENGTH (SYMBOL_TYPE (var));
+ memcpy (contents, bytes, n);
+ }
+ break;
+
+ case DWARF_VALUE_LITERAL:
+ {
+ bfd_byte *contents;
+ size_t n = ctx->len;
+
+ retval = allocate_value (SYMBOL_TYPE (var));
+ contents = value_contents_raw (retval);
+ if (n > TYPE_LENGTH (SYMBOL_TYPE (var)))
+ n = TYPE_LENGTH (SYMBOL_TYPE (var));
+ memcpy (contents, ctx->data, n);
+ }
+ break;

- retval = allocate_value (SYMBOL_TYPE (var));
- VALUE_LVAL (retval) = lval_memory;
- set_value_lazy (retval, 1);
- set_value_stack (retval, 1);
- set_value_address (retval, address);
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid location type"));
+ }
}

set_value_initialized (retval, ctx->initialized);
@@ -494,7 +573,7 @@

dwarf_expr_eval (ctx, data, size);

- in_reg = ctx->in_reg;
+ in_reg = ctx->location == DWARF_VALUE_REGISTER;

if (ctx->num_pieces > 0)
{
@@ -503,7 +582,7 @@
/* If the location has several pieces, and any of them are in
registers, then we will need a frame to fetch them from. */
for (i = 0; i < ctx->num_pieces; i++)
- if (ctx->pieces[i].in_reg)
+ if (ctx->pieces[i].location == DWARF_VALUE_REGISTER)
in_reg = 1;
}

Index: testsuite/gdb.dwarf2/valop.S
===================================================================
RCS file: testsuite/gdb.dwarf2/valop.S
diff -N testsuite/gdb.dwarf2/valop.S
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.dwarf2/valop.S 4 Sep 2009 22:31:50 -0000
@@ -0,0 +1,505 @@
+/*
+ Copyright 2009 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This was compiled from a trivial program just to test the
+ DW_OP_stack_value and DW_OP_implicit_value operators:
+
+ unsigned int func (unsigned int arg) __attribute__ ((__noinline__));
+
+ unsigned int func (unsigned int arg)
+ {
+ unsigned int uses_stack_op = 23;
+ unsigned int uses_lit_op = 0x7fffffff;
+ unsigned int result = arg;
+
+ if (arg % 2)
+ result += uses_lit_op + uses_stack_op;
+ else
+ {
+ ++uses_stack_op;
+ ++uses_lit_op;
+
+ result -= uses_stack_op + uses_lit_op;
+ }
+
+ return result * uses_stack_op; // line 19, see the .exp file
+ }
+
+ int main (int argc, char *argv[])
+ {
+ return func (1024);
+ }
+
+ Then it was compiled with:
+
+ gcc -fvar-tracking{,-assignments} -gdwarf-3
+ -fno-inline{,-functions,-small-functions,-functions-called-once}
+ -O2
+
+*/
+
+ .file "valop.c"
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .text
+.Ltext0:
+ .p2align 4,,15
+.globl func
+ .type func, @function
+func:
+.LFB0:
+ .file 1 "valop.c"
+ .loc 1 4 0
+ .cfi_startproc
+.LVL0:
+ pushl %ebp
+ .cfi_def_cfa_offset 8
+ movl %esp, %ebp
+ .cfi_offset 5, -8
+ .cfi_def_cfa_register 5
+ .loc 1 4 0
+ movl 8(%ebp), %eax
+.LVL1:
+ .loc 1 9 0
+ testb $1, %al
+ jne .L5
+.LVL2:
+ .loc 1 16 0
+ addl $2147483624, %eax
+.LVL3:
+ .loc 1 13 0
+ movl $24, %edx
+.LVL4:
+ .loc 1 16 0
+ imull %edx, %eax
+.LVL5:
+ .loc 1 20 0
+ popl %ebp
+ .cfi_remember_state
+ .cfi_restore 5
+ .cfi_def_cfa 4, 4
+ ret
+.LVL6:
+ .p2align 4,,7
+ .p2align 3
+.L5:
+ .cfi_restore_state
+ .loc 1 10 0
+ subl $2147483626, %eax
+.LVL7:
+ .loc 1 5 0
+ movl $23, %edx
+.LVL8:
+ .loc 1 16 0
+ imull %edx, %eax
+.LVL9:
+ .loc 1 20 0
+ popl %ebp
+ .cfi_def_cfa 4, 4
+ .cfi_restore 5
+ ret
+ .cfi_endproc
+.LFE0:
+ .size func, .-func
+ .p2align 4,,15
+.globl _start
+ .type _start, @function
+_start:
+.LFB1:
+ .loc 1 23 0
+ .cfi_startproc
+.LVL10:
+ pushl %ebp
+ .cfi_def_cfa_offset 8
+ movl %esp, %ebp
+ .cfi_offset 5, -8
+ .cfi_def_cfa_register 5
+ subl $4, %esp
+ .loc 1 24 0
+ movl $1024, (%esp)
+ call func
+.LVL11:
+ .loc 1 25 0
+ leave
+ .cfi_restore 5
+ .cfi_def_cfa 4, 4
+ ret
+ .cfi_endproc
+.LFE1:
+ .size _start, .-_start
+.Letext0:
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+ .long .LVL0-.Ltext0
+ .long .LVL2-.Ltext0
+ .value 0x4
+ .byte 0x47
+ .byte 0x9f
+ .byte 0x93
+ .uleb128 0x4
+ .long .LVL2-.Ltext0
+ .long .LVL4-.Ltext0
+ .value 0x4
+ .byte 0x48
+ .byte 0x9f
+ .byte 0x93
+ .uleb128 0x4
+ .long .LVL4-.Ltext0
+ .long .LVL6-.Ltext0
+ .value 0x1
+ .byte 0x52
+ .long .LVL6-.Ltext0
+ .long .LVL8-.Ltext0
+ .value 0x4
+ .byte 0x47
+ .byte 0x9f
+ .byte 0x93
+ .uleb128 0x4
+ .long .LVL8-.Ltext0
+ .long .LFE0-.Ltext0
+ .value 0x1
+ .byte 0x52
+ .long 0x0
+ .long 0x0
+.LLST1:
+ .long .LVL0-.Ltext0
+ .long .LVL2-.Ltext0
+ .value 0x6
+ .byte 0x9e
+ .uleb128 0x4
+ .long 0x7fffffff
+ .long .LVL2-.Ltext0
+ .long .LVL6-.Ltext0
+ .value 0x6
+ .byte 0x9e
+ .uleb128 0x4
+ .long 0x80000000
+ .long .LVL6-.Ltext0
+ .long .LFE0-.Ltext0
+ .value 0x6
+ .byte 0x9e
+ .uleb128 0x4
+ .long 0x7fffffff
+ .long 0x0
+ .long 0x0
+.LLST2:
+ .long .LVL1-.Ltext0
+ .long .LVL3-.Ltext0
+ .value 0x1
+ .byte 0x50
+ .long .LVL3-.Ltext0
+ .long .LVL5-.Ltext0
+ .value 0x1
+ .byte 0x50
+ .long .LVL6-.Ltext0
+ .long .LVL7-.Ltext0
+ .value 0x1
+ .byte 0x50
+ .long .LVL7-.Ltext0
+ .long .LVL9-.Ltext0
+ .value 0x1
+ .byte 0x50
+ .long 0x0
+ .long 0x0
+.LLST3:
+ .long .LVL10-.Ltext0
+ .long .LVL11-1-.Ltext0
+ .value 0x2
+ .byte 0x91
+ .sleb128 0
+ .long 0x0
+ .long 0x0
+.LLST4:
+ .long .LVL10-.Ltext0
+ .long .LVL11-1-.Ltext0
+ .value 0x2
+ .byte 0x91
+ .sleb128 4
+ .long 0x0
+ .long 0x0
+ .section .debug_info
+ .long 0xd4
+ .value 0x3
+ .long .Ldebug_abbrev0
+ .byte 0x4
+ .uleb128 0x1
+ .long .LASF9
+ .byte 0x1
+ .long .LASF10
+ .long .LASF11
+ .long .Ltext0
+ .long .Letext0
+ .long .Ldebug_line0
+ .uleb128 0x2
+ .byte 0x1
+ .long .LASF3
+ .byte 0x1
+ .byte 0x3
+ .byte 0x1
+ .long 0x7c
+ .long .LFB0
+ .long .LFE0
+ .byte 0x1
+ .byte 0x9c
+ .long 0x7c
+ .uleb128 0x3
+ .string "arg"
+ .byte 0x1
+ .byte 0x3
+ .long 0x7c
+ .byte 0x2
+ .byte 0x91
+ .sleb128 0
+ .uleb128 0x4
+ .long .LASF0
+ .byte 0x1
+ .byte 0x5
+ .long 0x7c
+ .long .LLST0
+ .uleb128 0x4
+ .long .LASF1
+ .byte 0x1
+ .byte 0x6
+ .long 0x7c
+ .long .LLST1
+ .uleb128 0x4
+ .long .LASF2
+ .byte 0x1
+ .byte 0x7
+ .long 0x7c
+ .long .LLST2
+ .byte 0x0
+ .uleb128 0x5
+ .byte 0x4
+ .byte 0x7
+ .long .LASF7
+ .uleb128 0x2
+ .byte 0x1
+ .long .LASF4
+ .byte 0x1
+ .byte 0x16
+ .byte 0x1
+ .long 0xbd
+ .long .LFB1
+ .long .LFE1
+ .byte 0x1
+ .byte 0x9c
+ .long 0xbd
+ .uleb128 0x6
+ .long .LASF5
+ .byte 0x1
+ .byte 0x16
+ .long 0xbd
+ .long .LLST3
+ .uleb128 0x6
+ .long .LASF6
+ .byte 0x1
+ .byte 0x16
+ .long 0xc4
+ .long .LLST4
+ .byte 0x0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .uleb128 0x8
+ .byte 0x4
+ .long 0xca
+ .uleb128 0x8
+ .byte 0x4
+ .long 0xd0
+ .uleb128 0x5
+ .byte 0x1
+ .byte 0x6
+ .long .LASF8
+ .byte 0x0
+ .section .debug_abbrev
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0xe
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x1b
+ .uleb128 0xe
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x27
+ .uleb128 0xc
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0xa
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x5
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x4
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x5
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x6
+ .uleb128 0x5
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x8
+ .uleb128 0xf
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .byte 0x0
+ .section .debug_pubnames,"",@progbits
+ .long 0x20
+ .value 0x2
+ .long .Ldebug_info0
+ .long 0xd8
+ .long 0x25
+ .string "func"
+ .long 0x83
+ .string "main"
+ .long 0x0
+ .section .debug_aranges,"",@progbits
+ .long 0x1c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x4
+ .byte 0x0
+ .value 0x0
+ .value 0x0
+ .long .Ltext0
+ .long .Letext0-.Ltext0
+ .long 0x0
+ .long 0x0
+ .section .debug_str,"MS",@progbits,1
+.LASF7:
+ .string "unsigned int"
+.LASF3:
+ .string "func"
+.LASF0:
+ .string "uses_stack_op"
+.LASF5:
+ .string "argc"
+.LASF10:
+ .string "valop.c"
+.LASF2:
+ .string "result"
+.LASF8:
+ .string "char"
+.LASF9:
+ .string "GNU C 4.5.0 20090818 (experimental) [var-tracking-assignments-branch revision 150964]"
+.LASF4:
+ .string "main"
+.LASF11:
+ .string "/tmp"
+.LASF1:
+ .string "uses_lit_op"
+.LASF6:
+ .string "argv"
+ .ident "GCC: (GNU) 4.5.0 20090818 (experimental) [var-tracking-assignments-branch revision 150964]"
+ .section .note.GNU-stack,"",@progbits
Index: testsuite/gdb.dwarf2/valop.exp
===================================================================
RCS file: testsuite/gdb.dwarf2/valop.exp
diff -N testsuite/gdb.dwarf2/valop.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.dwarf2/valop.exp 4 Sep 2009 22:31:50 -0000
@@ -0,0 +1,55 @@
+# Copyright 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test DW_OP_stack_value and DW_OP_implicit_value.
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+# This test can only be run on x86 targets.
+if {![istarget i?86-*]} {
+ return 0
+}
+
+set testfile "valop"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}.x
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+ [list {additional_flags=-nostdlib}]] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_test "break valop.c:19" "Breakpoint 2.*" "set breakpoint for valop"
+gdb_continue_to_breakpoint "continue to breakpoint for valop"
+
+gdb_test "print uses_stack_op" " = 24" "print uses_stack_op"
+gdb_test "print uses_lit_op" " = 2147483648" "print uses_lit_op"