[PATCH] value_optimized_out and value_fetch_lazy

Andrew Burgess
2013-06-10T10:24:50Z

Hi,

I ran into an issue with gdb that appears to be caused by an incorrect
use of value_optimized_out.

Currently, if value_optimized_out returns true, this means we know the
value is optimized out, if value_optimized_out returns false this
means the value might, or might not, be optimized out; if the value
is currently lazy then we don't know it has been optimized out, and
so the answer from value_optimized_out is false.

I believe that currently, not every caller of value_optimized_out
follows these rules, and some cases if value_optimized_out returns
false, they treat the value as though it is NOT optimized out.

The patch below changes value_optimized_out so that if the value
is lazy it will be loaded, this should ensure that by the time
value_optimized_out returns, the value will be correct. I've fixed
the one place I could see where we were obviously taking care to
resolve lazy values and I've also made a few tweaks to some of the
other value code in order to prevent recursion while loading lazy
values, and to try and keep values lazy as much as possible.

Feedback welcome, or ok to commit?

Thanks,
Andrew

gdb/ChangeLog

2013-06-07 Andrew Burgess <aburgess@broadcom.com>

* stack.c (read_frame_arg): No longer need to fetch lazy values,
checking for optimized out will ensure lazy values are loaded.
* valops.c (value_fetch_lazy): Moved to value.c.
* value.c (value_fetch_lazy): Moved from valops.c, also use
optimized out flag rather than calling optimized_out method, to
avoid recursion.
(value_optimized_out): If the value is not already marked
optimized out, and is lazy then fetch it so we can know for sure
if the value is optimized out.
(allocate_optimized_out_value): If we create a value that we know
is optimized out, then mark the value as no longer lazy.
(value_primitive_field): Move optimized out check later to later
in the function after we have loaded any lazy values.

gdb/testsuite/ChangeLog

2013-06-07 Andrew Burgess <aburgess@broadcom.com>

* gdb.dwarf2/dw2-reg-undefined.exp: New file.
* gdb.dwarf2/dw2-reg-undefined.c: Likewise.
* gdb.dwarf2/dw2-reg-undefined.S: Likewise.

diff --git a/gdb/stack.c b/gdb/stack.c
index a4b392e..e844331 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -359,10 +359,6 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame,
{
struct type *type = value_type (val);

- if (!value_optimized_out (val) && value_lazy (val))
- value_fetch_lazy (val);
- if (!value_optimized_out (val) && value_lazy (entryval))
- value_fetch_lazy (entryval);
if (!value_optimized_out (val)
&& value_available_contents_eq (val, 0, entryval, 0,
TYPE_LENGTH (type)))
diff --git a/gdb/valops.c b/gdb/valops.c
index 93c09d8..787b799 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -947,167 +947,6 @@ value_at_lazy (struct type *type, CORE_ADDR addr)
return get_value_at (type, addr, 1);
}

-/* Called only from the value_contents and value_contents_all()
- macros, if the current data for a variable needs to be loaded into
- value_contents(VAL). Fetches the data from the user's process, and
- clears the lazy flag to indicate that the data in the buffer is
- valid.
-
- If the value is zero-length, we avoid calling read_memory, which
- would abort. We mark the value as fetched anyway -- all 0 bytes of
- it.
-
- This function returns a value because it is used in the
- value_contents macro as part of an expression, where a void would
- not work. The value is ignored. */
-
-int
-value_fetch_lazy (struct value *val)
-{
- gdb_assert (value_lazy (val));
- allocate_value_contents (val);
- if (value_bitsize (val))
- {
- /* To read a lazy bitfield, read the entire enclosing value. This
- prevents reading the same block of (possibly volatile) memory once
- per bitfield. It would be even better to read only the containing
- word, but we have no way to record that just specific bits of a
- value have been fetched. */
- struct type *type = check_typedef (value_type (val));
- enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
- struct value *parent = value_parent (val);
- LONGEST offset = value_offset (val);
- LONGEST num;
-
- if (!value_bits_valid (val,
- TARGET_CHAR_BIT * offset + value_bitpos (val),
- value_bitsize (val)))
- error (_("value has been optimized out"));
-
- if (!unpack_value_bits_as_long (value_type (val),
- value_contents_for_printing (parent),
- offset,
- value_bitpos (val),
- value_bitsize (val), parent, &num))
- mark_value_bytes_unavailable (val,
- value_embedded_offset (val),
- TYPE_LENGTH (type));
- else
- store_signed_integer (value_contents_raw (val), TYPE_LENGTH (type),
- byte_order, num);
- }
- else if (VALUE_LVAL (val) == lval_memory)
- {
- CORE_ADDR addr = value_address (val);
- struct type *type = check_typedef (value_enclosing_type (val));
-
- if (TYPE_LENGTH (type))
- read_value_memory (val, 0, value_stack (val),
- addr, value_contents_all_raw (val),
- TYPE_LENGTH (type));
- }
- else if (VALUE_LVAL (val) == lval_register)
- {
- struct frame_info *frame;
- int regnum;
- struct type *type = check_typedef (value_type (val));
- struct value *new_val = val, *mark = value_mark ();
-
- /* Offsets are not supported here; lazy register values must
- refer to the entire register. */
- gdb_assert (value_offset (val) == 0);
-
- while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
- {
- frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
- regnum = VALUE_REGNUM (new_val);
-
- gdb_assert (frame != NULL);
-
- /* Convertible register routines are used for multi-register
- values and for interpretation in different types
- (e.g. float or int from a double register). Lazy
- register values should have the register's natural type,
- so they do not apply. */
- gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame),
- regnum, type));
-
- new_val = get_frame_register_value (frame, regnum);
- }
-
- /* If it's still lazy (for instance, a saved register on the
- stack), fetch it. */
- if (value_lazy (new_val))
- value_fetch_lazy (new_val);
-
- /* If the register was not saved, mark it optimized out. */
- if (value_optimized_out (new_val))
- set_value_optimized_out (val, 1);
- else
- {
- set_value_lazy (val, 0);
- value_contents_copy (val, value_embedded_offset (val),
- new_val, value_embedded_offset (new_val),
- TYPE_LENGTH (type));
- }
-
- if (frame_debug)
- {
- struct gdbarch *gdbarch;
- frame = frame_find_by_id (VALUE_FRAME_ID (val));
- regnum = VALUE_REGNUM (val);
- gdbarch = get_frame_arch (frame);
-
- fprintf_unfiltered (gdb_stdlog,
- "{ value_fetch_lazy "
- "(frame=%d,regnum=%d(%s),...) ",
- frame_relative_level (frame), regnum,
- user_reg_map_regnum_to_name (gdbarch, regnum));
-
- fprintf_unfiltered (gdb_stdlog, "->");
- if (value_optimized_out (new_val))
- fprintf_unfiltered (gdb_stdlog, " optimized out");
- else
- {
- int i;
- const gdb_byte *buf = value_contents (new_val);
-
- if (VALUE_LVAL (new_val) == lval_register)
- fprintf_unfiltered (gdb_stdlog, " register=%d",
- VALUE_REGNUM (new_val));
- else if (VALUE_LVAL (new_val) == lval_memory)
- fprintf_unfiltered (gdb_stdlog, " address=%s",
- paddress (gdbarch,
- value_address (new_val)));
- else
- fprintf_unfiltered (gdb_stdlog, " computed");
-
- fprintf_unfiltered (gdb_stdlog, " bytes=");
- fprintf_unfiltered (gdb_stdlog, "[");
- for (i = 0; i < register_size (gdbarch, regnum); i++)
- fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
- fprintf_unfiltered (gdb_stdlog, "]");
- }
-
- fprintf_unfiltered (gdb_stdlog, " }\n");
- }
-
- /* Dispose of the intermediate values. This prevents
- watchpoints from trying to watch the saved frame pointer. */
- value_free_to_mark (mark);
- }
- else if (VALUE_LVAL (val) == lval_computed
- && value_computed_funcs (val)->read != NULL)
- value_computed_funcs (val)->read (val);
- else if (value_optimized_out (val))
- /* Keep it optimized out. */;
- else
- internal_error (__FILE__, __LINE__, _("Unexpected lazy value type."));
-
- set_value_lazy (val, 0);
- return 0;
-}
-
void
read_value_memory (struct value *val, int embedded_offset,
int stack, CORE_ADDR memaddr,
diff --git a/gdb/value.c b/gdb/value.c
index ee3c998..fae21d6 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -42,6 +42,7 @@
#include <ctype.h>
#include "tracepoint.h"
#include "cp-abi.h"
+#include "user-regs.h"

/* Prototypes for exported functions. */

@@ -743,6 +744,8 @@ allocate_optimized_out_value (struct type *type)
{
struct value *retval = allocate_value_lazy (type);

+ /* It's no longer lazy if we know it's optimized out. */
+ set_value_lazy (retval, 0);
set_value_optimized_out (retval, 1);

return retval;
@@ -1055,6 +1058,9 @@ value_contents_equal (struct value *val1, struct value *val2)
int
value_optimized_out (struct value *value)
{
+ if (!value->optimized_out && value->lazy)
+ value_fetch_lazy (value);
+
return value->optimized_out;
}

@@ -2629,9 +2635,7 @@ value_primitive_field (struct value *arg1, int offset,
description correctly. */
check_typedef (type);

- if (value_optimized_out (arg1))
- v = allocate_optimized_out_value (type);
- else if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
+ if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
{
/* Handle packed fields.

@@ -2645,19 +2649,24 @@ value_primitive_field (struct value *arg1, int offset,
int bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno);
int container_bitsize = TYPE_LENGTH (type) * 8;

- v = allocate_value_lazy (type);
- v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno);
- if ((bitpos % container_bitsize) + v->bitsize <= container_bitsize
- && TYPE_LENGTH (type) <= (int) sizeof (LONGEST))
- v->bitpos = bitpos % container_bitsize;
+ if (arg1->optimized_out)
+ v = allocate_optimized_out_value (type);
else
- v->bitpos = bitpos % 8;
- v->offset = (value_embedded_offset (arg1)
- + offset
- + (bitpos - v->bitpos) / 8);
- set_value_parent (v, arg1);
- if (!value_lazy (arg1))
- value_fetch_lazy (v);
+ {
+ v = allocate_value_lazy (type);
+ v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno);
+ if ((bitpos % container_bitsize) + v->bitsize <= container_bitsize
+ && TYPE_LENGTH (type) <= (int) sizeof (LONGEST))
+ v->bitpos = bitpos % container_bitsize;
+ else
+ v->bitpos = bitpos % 8;
+ v->offset = (value_embedded_offset (arg1)
+ + offset
+ + (bitpos - v->bitpos) / 8);
+ set_value_parent (v, arg1);
+ if (!value_lazy (arg1))
+ value_fetch_lazy (v);
+ }
}
else if (fieldno < TYPE_N_BASECLASSES (arg_type))
{
@@ -2670,29 +2679,34 @@ value_primitive_field (struct value *arg1, int offset,
if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1))
value_fetch_lazy (arg1);

- /* We special case virtual inheritance here because this
- requires access to the contents, which we would rather avoid
- for references to ordinary fields of unavailable values. */
- if (BASETYPE_VIA_VIRTUAL (arg_type, fieldno))
- boffset = baseclass_offset (arg_type, fieldno,
- value_contents (arg1),
- value_embedded_offset (arg1),
- value_address (arg1),
- arg1);
- else
- boffset = TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
-
- if (value_lazy (arg1))
- v = allocate_value_lazy (value_enclosing_type (arg1));
+ if (arg1->optimized_out)
+ v = allocate_optimized_out_value (type);
else
{
- v = allocate_value (value_enclosing_type (arg1));
- value_contents_copy_raw (v, 0, arg1, 0,
- TYPE_LENGTH (value_enclosing_type (arg1)));
+ /* We special case virtual inheritance here because this
+ requires access to the contents, which we would rather avoid
+ for references to ordinary fields of unavailable values. */
+ if (BASETYPE_VIA_VIRTUAL (arg_type, fieldno))
+ boffset = baseclass_offset (arg_type, fieldno,
+ value_contents (arg1),
+ value_embedded_offset (arg1),
+ value_address (arg1),
+ arg1);
+ else
+ boffset = TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
+
+ if (value_lazy (arg1))
+ v = allocate_value_lazy (value_enclosing_type (arg1));
+ else
+ {
+ v = allocate_value (value_enclosing_type (arg1));
+ value_contents_copy_raw (v, 0, arg1, 0,
+ TYPE_LENGTH (value_enclosing_type (arg1)));
+ }
+ v->type = type;
+ v->offset = value_offset (arg1);
+ v->embedded_offset = offset + value_embedded_offset (arg1) + boffset;
}
- v->type = type;
- v->offset = value_offset (arg1);
- v->embedded_offset = offset + value_embedded_offset (arg1) + boffset;
}
else
{
@@ -2703,7 +2717,9 @@ value_primitive_field (struct value *arg1, int offset,
if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1))
value_fetch_lazy (arg1);

- if (value_lazy (arg1))
+ if (arg1->optimized_out)
+ v = allocate_optimized_out_value (type);
+ else if (value_lazy (arg1))
v = allocate_value_lazy (type);
else
{
@@ -3375,6 +3391,168 @@ value_initialized (struct value *val)
return val->initialized;
}

+
+/* Called only from the value_contents and value_contents_all()
+ macros, if the current data for a variable needs to be loaded into
+ value_contents(VAL). Fetches the data from the user's process, and
+ clears the lazy flag to indicate that the data in the buffer is
+ valid.
+
+ If the value is zero-length, we avoid calling read_memory, which
+ would abort. We mark the value as fetched anyway -- all 0 bytes of
+ it.
+
+ This function returns a value because it is used in the
+ value_contents macro as part of an expression, where a void would
+ not work. The value is ignored. */
+
+int
+value_fetch_lazy (struct value *val)
+{
+ gdb_assert (value_lazy (val));
+ allocate_value_contents (val);
+ if (value_bitsize (val))
+ {
+ /* To read a lazy bitfield, read the entire enclosing value. This
+ prevents reading the same block of (possibly volatile) memory once
+ per bitfield. It would be even better to read only the containing
+ word, but we have no way to record that just specific bits of a
+ value have been fetched. */
+ struct type *type = check_typedef (value_type (val));
+ enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+ struct value *parent = value_parent (val);
+ LONGEST offset = value_offset (val);
+ LONGEST num;
+
+ if (!value_bits_valid (val,
+ TARGET_CHAR_BIT * offset + value_bitpos (val),
+ value_bitsize (val)))
+ error (_("value has been optimized out"));
+
+ if (!unpack_value_bits_as_long (value_type (val),
+ value_contents_for_printing (parent),
+ offset,
+ value_bitpos (val),
+ value_bitsize (val), parent, &num))
+ mark_value_bytes_unavailable (val,
+ value_embedded_offset (val),
+ TYPE_LENGTH (type));
+ else
+ store_signed_integer (value_contents_raw (val), TYPE_LENGTH (type),
+ byte_order, num);
+ }
+ else if (VALUE_LVAL (val) == lval_memory)
+ {
+ CORE_ADDR addr = value_address (val);
+ struct type *type = check_typedef (value_enclosing_type (val));
+
+ if (TYPE_LENGTH (type))
+ read_value_memory (val, 0, value_stack (val),
+ addr, value_contents_all_raw (val),
+ TYPE_LENGTH (type));
+ }
+ else if (VALUE_LVAL (val) == lval_register)
+ {
+ struct frame_info *frame;
+ int regnum;
+ struct type *type = check_typedef (value_type (val));
+ struct value *new_val = val, *mark = value_mark ();
+
+ /* Offsets are not supported here; lazy register values must
+ refer to the entire register. */
+ gdb_assert (value_offset (val) == 0);
+
+ while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
+ {
+ frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
+ regnum = VALUE_REGNUM (new_val);
+
+ gdb_assert (frame != NULL);
+
+ /* Convertible register routines are used for multi-register
+ values and for interpretation in different types
+ (e.g. float or int from a double register). Lazy
+ register values should have the register's natural type,
+ so they do not apply. */
+ gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame),
+ regnum, type));
+
+ new_val = get_frame_register_value (frame, regnum);
+ }
+
+ /* If it's still lazy (for instance, a saved register on the
+ stack), fetch it. */
+ if (value_lazy (new_val))
+ value_fetch_lazy (new_val);
+
+ /* If the register was not saved, mark it optimized out. */
+ if (value_optimized_out (new_val))
+ set_value_optimized_out (val, 1);
+ else
+ {
+ set_value_lazy (val, 0);
+ value_contents_copy (val, value_embedded_offset (val),
+ new_val, value_embedded_offset (new_val),
+ TYPE_LENGTH (type));
+ }
+
+ if (frame_debug)
+ {
+ struct gdbarch *gdbarch;
+ frame = frame_find_by_id (VALUE_FRAME_ID (val));
+ regnum = VALUE_REGNUM (val);
+ gdbarch = get_frame_arch (frame);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "{ value_fetch_lazy "
+ "(frame=%d,regnum=%d(%s),...) ",
+ frame_relative_level (frame), regnum,
+ user_reg_map_regnum_to_name (gdbarch, regnum));
+
+ fprintf_unfiltered (gdb_stdlog, "->");
+ if (value_optimized_out (new_val))
+ fprintf_unfiltered (gdb_stdlog, " optimized out");
+ else
+ {
+ int i;
+ const gdb_byte *buf = value_contents (new_val);
+
+ if (VALUE_LVAL (new_val) == lval_register)
+ fprintf_unfiltered (gdb_stdlog, " register=%d",
+ VALUE_REGNUM (new_val));
+ else if (VALUE_LVAL (new_val) == lval_memory)
+ fprintf_unfiltered (gdb_stdlog, " address=%s",
+ paddress (gdbarch,
+ value_address (new_val)));
+ else
+ fprintf_unfiltered (gdb_stdlog, " computed");
+
+ fprintf_unfiltered (gdb_stdlog, " bytes=");
+ fprintf_unfiltered (gdb_stdlog, "[");
+ for (i = 0; i < register_size (gdbarch, regnum); i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "]");
+ }
+
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
+ /* Dispose of the intermediate values. This prevents
+ watchpoints from trying to watch the saved frame pointer. */
+ value_free_to_mark (mark);
+ }
+ else if (VALUE_LVAL (val) == lval_computed
+ && value_computed_funcs (val)->read != NULL)
+ value_computed_funcs (val)->read (val);
+ else if (val->optimized_out)
+ /* Keep it optimized out. */;
+ else
+ internal_error (__FILE__, __LINE__, _("Unexpected lazy value type."));
+
+ set_value_lazy (val, 0);
+ return 0;
+}
+
void
_initialize_values (void)
{
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.S b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.S
new file mode 100644
index 0000000..54b5af1
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.S
@@ -0,0 +1,505 @@
+ /* The FDE entry for "stop_frame" in the .debug_frame section has
+ been hand modified to mark a set of registers as undefined.
+ Otherwise this file is as generated by gcc 4.7.2 for x86_64. */
+ .file "dw2-reg-undefined.c"
+ .text
+.Ltext0:
+ .globl stop_frame
+ .type stop_frame, @function
+stop_frame:
+.LFB0:
+ .file 1 "dw2-reg-undefined.c"
+ .loc 1 3 0
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ .loc 1 6 0
+ popq %rbp
+.LCFI2:
+ ret
+.LFE0:
+ .size stop_frame, .-stop_frame
+ .globl first_frame
+ .type first_frame, @function
+first_frame:
+.LFB1:
+ .loc 1 10 0
+ pushq %rbp
+.LCFI3:
+ movq %rsp, %rbp
+.LCFI4:
+ .loc 1 11 0
+ movl $0, %eax
+ call stop_frame
+ .loc 1 12 0
+ popq %rbp
+.LCFI5:
+ ret
+.LFE1:
+ .size first_frame, .-first_frame
+ .globl main
+ .type main, @function
+main:
+.LFB2:
+ .loc 1 16 0
+ pushq %rbp
+.LCFI6:
+ movq %rsp, %rbp
+.LCFI7:
+ .loc 1 17 0
+ movl $0, %eax
+ call first_frame
+ .loc 1 19 0
+ movl $0, %eax
+ .loc 1 20 0
+ popq %rbp
+.LCFI8:
+ ret
+.LFE2:
+ .size main, .-main
+ .section .debug_frame,"",@progbits
+.Lframe0:
+ .long .LECIE0-.LSCIE0
+.LSCIE0:
+ .long 0xffffffff
+ .byte 0x1
+ .string ""
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE0:
+ /* This FDE entry, for stop_frame was modified to mark
+ registers 0 -> 6 as being undefined. */
+.LSFDE0:
+ .long .LEFDE0-.LASFDE0 /* FDE length (uword) */
+.LASFDE0:
+ .long .Lframe0 /* CIE Pointer (uword) */
+ .quad .LFB0 /* Initial location (addr) */
+ .quad .LFE0-.LFB0 /* Address range (addr) */
+ /* Instructions... */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x0 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x1 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x2 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x3 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x4 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x5 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x6 /* ULEB128 register */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x7 /* ULEB128 register */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI0-.LFB0 /* 4-byte offset */
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 0x10 /* ULEB128 offset */
+ .byte 0x86 /* DW_CFA_offset (reg = 6) */
+ .uleb128 0x2 /* ULEB128 offset */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI1-.LCFI0 /* 4-byte offset */
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0x6 /* ULEB128 register */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .long .LCFI2-.LCFI1 /* 4-byte offset */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .uleb128 0x7 /* ULEB128 register */
+ .uleb128 0x8 /* ULEB128 offset */
+
+ .align 8
+ /* End of modified frame. */
+.LEFDE0:
+.LSFDE2:
+ .long .LEFDE2-.LASFDE2
+.LASFDE2:
+ .long .Lframe0
+ .quad .LFB1
+ .quad .LFE1-.LFB1
+ .byte 0x4
+ .long .LCFI3-.LFB1
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI4-.LCFI3
+ .byte 0xd
+ .uleb128 0x6
+ .byte 0x4
+ .long .LCFI5-.LCFI4
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .align 8
+.LEFDE2:
+.LSFDE4:
+ .long .LEFDE4-.LASFDE4
+.LASFDE4:
+ .long .Lframe0
+ .quad .LFB2
+ .quad .LFE2-.LFB2
+ .byte 0x4
+ .long .LCFI6-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI7-.LCFI6
+ .byte 0xd
+ .uleb128 0x6
+ .byte 0x4
+ .long .LCFI8-.LCFI7
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .align 8
+.LEFDE4:
+ .section .eh_frame,"a",@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1
+.LSCIE1:
+ .long 0
+ .byte 0x1
+ .string "zR"
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .uleb128 0x1
+ .byte 0x3
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE7:
+ .long .LEFDE7-.LASFDE7
+.LASFDE7:
+ .long .LASFDE7-.Lframe1
+ .long .LFB0
+ .long .LFE0-.LFB0
+ .uleb128 0
+ .byte 0x4
+ .long .LCFI0-.LFB0
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .byte 0x4
+ .long .LCFI2-.LCFI1
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .align 8
+.LEFDE7:
+.LSFDE9:
+ .long .LEFDE9-.LASFDE9
+.LASFDE9:
+ .long .LASFDE9-.Lframe1
+ .long .LFB1
+ .long .LFE1-.LFB1
+ .uleb128 0
+ .byte 0x4
+ .long .LCFI3-.LFB1
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI4-.LCFI3
+ .byte 0xd
+ .uleb128 0x6
+ .byte 0x4
+ .long .LCFI5-.LCFI4
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .align 8
+.LEFDE9:
+.LSFDE11:
+ .long .LEFDE11-.LASFDE11
+.LASFDE11:
+ .long .LASFDE11-.Lframe1
+ .long .LFB2
+ .long .LFE2-.LFB2
+ .uleb128 0
+ .byte 0x4
+ .long .LCFI6-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI7-.LCFI6
+ .byte 0xd
+ .uleb128 0x6
+ .byte 0x4
+ .long .LCFI8-.LCFI7
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .align 8
+.LEFDE11:
+ .text
+.Letext0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .long 0x8c
+ .value 0x2
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .LASF2
+ .byte 0x1
+ .long .LASF3
+ .long .LASF4
+ .quad .Ltext0
+ .quad .Letext0
+ .long .Ldebug_line0
+ .uleb128 0x2
+ .byte 0x1
+ .long .LASF0
+ .byte 0x1
+ .byte 0x2
+ .quad .LFB0
+ .quad .LFE0
+ .long .LLST0
+ .byte 0x1
+ .uleb128 0x3
+ .byte 0x1
+ .long .LASF1
+ .byte 0x1
+ .byte 0x9
+ .quad .LFB1
+ .quad .LFE1
+ .long .LLST1
+ .byte 0x1
+ .uleb128 0x4
+ .byte 0x1
+ .long .LASF5
+ .byte 0x1
+ .byte 0xf
+ .long 0x88
+ .quad .LFB2
+ .quad .LFE2
+ .long .LLST2
+ .byte 0x1
+ .uleb128 0x5
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .byte 0
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .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 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x2117
+ .uleb128 0xc
+ .byte 0
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x2116
+ .uleb128 0xc
+ .byte 0
+ .byte 0
+ .uleb128 0x4
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x2116
+ .uleb128 0xc
+ .byte 0
+ .byte 0
+ .uleb128 0x5
+ .uleb128 0x24
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+ .quad .LFB0-.Ltext0
+ .quad .LCFI0-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI0-.Ltext0
+ .quad .LCFI1-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI1-.Ltext0
+ .quad .LCFI2-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad .LCFI2-.Ltext0
+ .quad .LFE0-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad 0
+ .quad 0
+.LLST1:
+ .quad .LFB1-.Ltext0
+ .quad .LCFI3-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI3-.Ltext0
+ .quad .LCFI4-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI4-.Ltext0
+ .quad .LCFI5-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad .LCFI5-.Ltext0
+ .quad .LFE1-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad 0
+ .quad 0
+.LLST2:
+ .quad .LFB2-.Ltext0
+ .quad .LCFI6-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI6-.Ltext0
+ .quad .LCFI7-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI7-.Ltext0
+ .quad .LCFI8-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad .LCFI8-.Ltext0
+ .quad .LFE2-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad 0
+ .quad 0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x8
+ .byte 0
+ .value 0
+ .value 0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0
+ .quad 0
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .section .debug_str,"MS",@progbits,1
+.LASF0:
+ .string "stop_frame"
+.LASF3:
+ .string "dw2-reg-undefined.c"
+.LASF2:
+ .string "GNU C 4.7.2"
+.LASF4:
+ .string "/projects/firepath_work/aburgess/tmp"
+.LASF1:
+ .string "first_frame"
+.LASF5:
+ .string "main"
+ .ident "GCC: (GNU) 4.7.2"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.c b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.c
new file mode 100644
index 0000000..2101ff9
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.c
@@ -0,0 +1,20 @@
+void
+stop_frame ()
+{
+ /* The debug information for this frame is modified in the accompanying
+ .S file, to mark a set of registers as being undefined. */
+}
+
+void
+first_frame ()
+{
+ stop_frame ();
+}
+
+int
+main ()
+{
+ first_frame ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
new file mode 100644
index 0000000..468cd21
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
@@ -0,0 +1,60 @@
+# Copyright 2008-2013 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/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+ return 0
+}
+
+# This test can only be run on x86_64 targets.
+if {![istarget "x86_64-*-*"] || ![is_lp64_target]} {
+ return 0
+}
+
+standard_testfile .S
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile {nodebug}] } {
+ return -1
+}
+
+if ![runto stop_frame] {
+ perror "Failed to stop in stop_frame"
+ return -1
+}
+
+gdb_test "bt" "#0 (0x\[0-9a-f\]+ in )?stop_frame \[^\r\n\]*\r\n#1 \[^\r\n\]*first_frame \[^\r\n\]*\r\n#2 \[^\r\n\]*main\[^\r\n\]*" \
+ "backtrace from stop_frame"
+
+set value_pattern "0x\[0-9a-f\]+\\s+\[0-9\]+"
+set opt_out_pattern "\\*value not available\\*"
+
+for {set f 0} {$f < 3} {incr f} {
+ if {${f} == 0} {
+ set pattern_rax_rbx_rcx ${value_pattern}
+ set pattern_r8_r9 ${value_pattern}
+ } else {
+ set pattern_rax_rbx_rcx ${opt_out_pattern}
+ set pattern_r8_r9 ${value_pattern}
+ }
+
+ # Select frame.
+ gdb_test "frame ${f}" "#${f}.*" "Switch to frame ${f}"
+
+ # Display register values.
+ gdb_test "info registers rax rbx rcx r8 r9" "rax\\s+${pattern_rax_rbx_rcx}\\s*\r\nrbx\\s+${pattern_rax_rbx_rcx}\\s*\r\nrcx\\s+${pattern_rax_rbx_rcx}\\s*\r\nr8\\s+${pattern_r8_r9}\\s*\r\nr9\\s+${pattern_r8_r9}\\s*" \
+ "Check values of rax, rbx, rcx, r8, r9 in frame ${f}"
+}
+