Re: [2/3] [PATCH] value_optimized_out and value_fetch_lazy

Andrew Burgess
2013-07-01T18:06:44Z

On 19/06/2013 4:50 PM, Pedro Alves wrote:
> On 06/10/2013 11:24 AM, Andrew Burgess wrote:
>>
>> 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.
>
> Can you explain a little better the value_primitive_field
> changes? Is that code motion mainly an optimization that could
> be done separately, or is it necessary for correctness? IOW, is
> that something that could be split out too?

The changes in value_primitive_field are functional. I add some nested
blocks so the churn looks worse than it really is.

In the old world value_primitive_field the code looks roughly like this:

if (value_optimized_out (arg1))
v = allocate_optimized_out_value (type); /* CASE 1 */
else if (TYPE_FIELD_BITSIZE (arg_type, fieldno))
/* CASE 2 */
else if (fieldno < TYPE_N_BASECLASSES (arg_type))
/* CASE 3 */
else
/* CASE 4 */

Now, consider ARG1 to value_primitive_field has the following
properties, (a) optimised out but not yet marked optimized out,
(b) lval_memory, an (c) lazy. We'll not hit "CASE 1", but, if
we hit "CASE 2" then we will return another lazy value, same for
"CASE 3", and the same for "CASE 4". However, with my change we
decide at the first call to value_optimized_out that the value
is gone, and so land in "CASE 1".

Also note, in the old world we initially case value_optimized_out,
which might return false, but really mean true once we've done a
value_fetch_lazy, later, in "CASE 3" and "CASE 4" we called
value_fetch_lazy, but then failed to take any special action if
the value has now become optimized out.

When I initially wrote my patch I did not change
value_primitive_field, and some tests did regress, and the new
output was less helpful then the current behaviour.

My patch then does 2 things, first, I add in the extra checks
for has this value become optimized out after we call
value_fetch_lazy, this is needed for correctness, as a result of
this first change, only "CASE 2" does not handle optimized out
value, so I add code into "CASE 2" to handle optimized out values.
Now, I no longer need the initial check for optimized out values, I
can leave the values as lazy for as long as possible, only fetching
them if they are lazy and lval_register, this restores the original
behaviour, but, I believe is more correct.

>
> Please add copyright headers to the tests. I also noticed
> the patch adds spurious trailing whitespace:

These issues should be fixed now.

Here's the improved patch, ok to apply?

Thanks,
Andrew

gdb/ChangeLog

2013-07-01 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.
* value.c (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.
(value_primitive_field): Move optimized out check later to later in
the function after we have loaded any lazy values.
(value_fetch_lazy): Use optimized out flag directly rather than
calling optimized_out method to avoid triggering recursion.

diff --git a/gdb/stack.c b/gdb/stack.c
index 08431bb..2462931 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/value.c b/gdb/value.c
index 61fd4a1..e3a60dd 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1054,6 +1054,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;
}

@@ -2630,9 +2633,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.

@@ -2646,19 +2647,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))
{
@@ -2671,29 +2677,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
{
@@ -2704,7 +2715,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
{
@@ -3528,7 +3541,7 @@ value_fetch_lazy (struct value *val)
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))
+ else if (val->optimized_out)
/* Keep it optimized out. */;
else
internal_error (__FILE__, __LINE__, _("Unexpected lazy value type."));

gdb/testsuite/ChangeLog

2013-07-01 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/testsuite/gdb.dwarf2/dw2-reg-undefined.S b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.S
new file mode 100644
index 0000000..ae071d9
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.S
@@ -0,0 +1,522 @@
+/*
+ Copyright 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/>. */
+
+ /* 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 19 0
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ .loc 1 22 0
+ popq %rbp
+.LCFI2:
+ ret
+.LFE0:
+ .size stop_frame, .-stop_frame
+ .globl first_frame
+ .type first_frame, @function
+first_frame:
+.LFB1:
+ .loc 1 26 0
+ pushq %rbp
+.LCFI3:
+ movq %rsp, %rbp
+.LCFI4:
+ .loc 1 27 0
+ movl $0, %eax
+ call stop_frame
+ .loc 1 28 0
+ popq %rbp
+.LCFI5:
+ ret
+.LFE1:
+ .size first_frame, .-first_frame
+ .globl main
+ .type main, @function
+main:
+.LFB2:
+ .loc 1 32 0
+ pushq %rbp
+.LCFI6:
+ movq %rsp, %rbp
+.LCFI7:
+ .loc 1 33 0
+ movl $0, %eax
+ call first_frame
+ .loc 1 35 0
+ movl $0, %eax
+ .loc 1 36 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
+.LASFDE0:
+ .long .Lframe0
+ .quad .LFB0
+ .quad .LFE0-.LFB0
+
+ /* START OF NEW CONTENT. */
+ .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 */
+ /* END OF NEW CONTENT. */
+
+ .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
+.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 0x12
+ .quad .LFB0
+ .quad .LFE0
+ .long .LLST0
+ .byte 0x1
+ .uleb128 0x3
+ .byte 0x1
+ .long .LASF1
+ .byte 0x1
+ .byte 0x19
+ .quad .LFB1
+ .quad .LFE1
+ .long .LLST1
+ .byte 0x1
+ .uleb128 0x4
+ .byte 0x1
+ .long .LASF5
+ .byte 0x1
+ .byte 0x1f
+ .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"
+.LASF1:
+ .string "first_frame"
+.LASF5:
+ .string "main"
+.LASF4:
+ .string "/home/username/src/gdb/testsuite/gdb.dwarf2"
+ .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..6a177c5
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 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/>. */
+
+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..7b7b4d1
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
@@ -0,0 +1,59 @@
+# Copyright 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}"
+}