* RFC: implement DW_OP_stack_value and DW_OP_implicit_value
@ 2009-09-02 22:13 Tom Tromey
2009-09-04 22:34 ` Tom Tromey
0 siblings, 1 reply; 5+ messages in thread
From: Tom Tromey @ 2009-09-02 22:13 UTC (permalink / raw)
To: gdb-patches
This patch implements the new DWARF 4 opcodes DW_OP_stack_value and
DW_OP_implicit_value. The svn trunk GCC can generate these under some
conditions.
Built and regtested on x86-64 (compile farm). There's an x86 test case
included, made with some random VTA branch snapshot -- I verified by
hand that it uses both operators in question.
Tom
2009-09-02 Tom Tromey <tromey@redhat.com>
* dwarf2loc.c (dwarf2_evaluate_loc_desc): Update.
(dwarf2_loc_desc_needs_frame): Likewise.
* 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.
2009-09-02 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 2 Sep 2009 21:56:50 -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 2 Sep 2009 21:56:50 -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, ®);
- 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 2 Sep 2009 21:56:50 -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.65
diff -u -r1.65 dwarf2loc.c
--- dwarf2loc.c 2 Sep 2009 14:53:55 -0000 1.65
+++ dwarf2loc.c 2 Sep 2009 21:56:50 -0000
@@ -263,37 +263,111 @@
for (i = 0; i < ctx->num_pieces; i++)
{
struct dwarf_expr_piece *p = &ctx->pieces[i];
- if (p->in_reg)
+ switch (p->location)
{
- struct gdbarch *arch = get_frame_arch (frame);
- bfd_byte regval[MAX_REGISTER_SIZE];
- int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->value);
- get_frame_register (frame, gdb_regnum, regval);
- memcpy (contents + offset, regval, p->size);
- }
- else /* In memory? */
- {
- read_memory (p->value, contents + offset, p->size);
+ 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;
+ store_unsigned_integer (bytes, ctx->addr_size,
+ gdbarch_byte_order (ctx->gdbarch),
+ p->v.value);
+ n = p->size;
+ if (n > ctx->addr_size)
+ n = ctx->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;
+
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid location type"));
}
offset += p->size;
}
}
- 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);
@@ -390,7 +464,7 @@
dwarf_expr_eval (ctx, data, size);
- in_reg = ctx->in_reg;
+ in_reg = ctx->location == DWARF_VALUE_REGISTER;
if (ctx->num_pieces > 0)
{
@@ -399,7 +473,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 2 Sep 2009 21:56:51 -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 2 Sep 2009 21:56:51 -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"
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: RFC: implement DW_OP_stack_value and DW_OP_implicit_value 2009-09-02 22:13 RFC: implement DW_OP_stack_value and DW_OP_implicit_value Tom Tromey @ 2009-09-04 22:34 ` Tom Tromey 2009-09-04 23:01 ` Pedro Alves 2009-09-11 18:33 ` Tom Tromey 0 siblings, 2 replies; 5+ messages in thread From: Tom Tromey @ 2009-09-04 22:34 UTC (permalink / raw) To: gdb-patches >>>>> "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, ®); - 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" ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RFC: implement DW_OP_stack_value and DW_OP_implicit_value 2009-09-04 22:34 ` Tom Tromey @ 2009-09-04 23:01 ` Pedro Alves 2009-09-04 23:56 ` Tom Tromey 2009-09-11 18:33 ` Tom Tromey 1 sibling, 1 reply; 5+ messages in thread From: Pedro Alves @ 2009-09-04 23:01 UTC (permalink / raw) To: gdb-patches, Tom Tromey On Friday 04 September 2009 23:33:54, Tom Tromey wrote: > 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. That sounds strange to me. When would we be reading things off the stack and not have a frame? -- Pedro Alves ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RFC: implement DW_OP_stack_value and DW_OP_implicit_value 2009-09-04 23:01 ` Pedro Alves @ 2009-09-04 23:56 ` Tom Tromey 0 siblings, 0 replies; 5+ messages in thread From: Tom Tromey @ 2009-09-04 23:56 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches >>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes: Pedro> On Friday 04 September 2009 23:33:54, Tom Tromey wrote: >> 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. Pedro> That sounds strange to me. When would we be reading things Pedro> off the stack and not have a frame? Sorry, I wasn't clear. I was referring to the dwarf expression stack. The value in question comes from DW_OP_stack_value. Tom ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: RFC: implement DW_OP_stack_value and DW_OP_implicit_value 2009-09-04 22:34 ` Tom Tromey 2009-09-04 23:01 ` Pedro Alves @ 2009-09-11 18:33 ` Tom Tromey 1 sibling, 0 replies; 5+ messages in thread From: Tom Tromey @ 2009-09-11 18:33 UTC (permalink / raw) To: gdb-patches >>>>> "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. [...] Tom> Let me know what you think. Doug said on irc that it looked ok to him. I am going to commit this shortly. Tom ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-09-11 18:33 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-09-02 22:13 RFC: implement DW_OP_stack_value and DW_OP_implicit_value Tom Tromey 2009-09-04 22:34 ` Tom Tromey 2009-09-04 23:01 ` Pedro Alves 2009-09-04 23:56 ` Tom Tromey 2009-09-11 18:33 ` Tom Tromey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox