This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: PATCH: error reading variable: value has been optimized out
- From: "Andrew Burgess" <aburgess at broadcom dot com>
- To: "gdb-patches at sourceware dot org" <gdb-patches at sourceware dot org>
- Cc: "Tom Tromey" <tromey at redhat dot com>, "Jan Kratochvil" <jan dot kratochvil at redhat dot com>
- Date: Thu, 13 Sep 2012 13:33:43 +0100
- Subject: Re: PATCH: error reading variable: value has been optimized out
- References: <50376F3B.1080407@broadcom.com> <20120826171840.GA21205@host2.jankratochvil.net> <504092C0.2000602@broadcom.com> <87wqzz5eug.fsf@fleche.redhat.com>
On 12/09/2012 6:29 PM, Tom Tromey wrote:
>>>>>> "Andrew" == Andrew Burgess <aburgess@broadcom.com> writes:
>
> Andrew> (3) Structures the size of two registers split over two
> Andrew> registers using dwarf piece information.
>
> Andrew> (4) Values the size of a single register split over two
> Andrew> registers using dwarf piece information to describe the
> Andrew> location.
>
> Andrew> Cases (3) and (4) are not fixed by my original patch, and fail
> Andrew> for a different reason. I could remove these from the test, but
> Andrew> I believe the tests are reasonable, or at least not totally
> Andrew> crazy, so I'm reluctant to just delete them. I could just
> Andrew> commit the test with these two examples marked as known failing
> Andrew> .... or I could fix them :)
>
> Andrew> The problem is this,
>
> Andrew> - In dwarf2loc.c:dwarf_evaluate_loc_desc_full we create the
> Andrew> computed value from the pieced location information.
>
> Andrew> - In dwarf2loc.c:read_pieced_value we spot that some of the
> Andrew> registers are missing and mark the computed value as optimized
> Andrew> out.
>
> This scenario seems odd to me. I think what it means is that the
> compiler declares an object as being split between two registers -- but
> then also knows that one of the registers is not in fact available.
>
> Does any compiler actually do this?
I have never seen such debug, I was just thinking up similar cases to the original test #1, that I have seen. I agree that in all these cases, if they did occur, it would be incorrect (though not invalid) debug information.
> If it is just a theoretical problem I think we can just declare it
> unsupported; and, if we do see it, try reporting it as a compiler bug
> first. After all, the compiler could just emit an empty piece instead.
I'm happy to mark these tests as unsupported. As the tests (#2 -> #4) are pretty much zero cost given that I'm adding test #1 anyway I'd like to leave them in. I've created a new patch, the only change is that test #3 and #4 now report unsupported (with comment), and test #2 reports pass, with a comment to explain the reasoning.
Full patch below, would everyone be happy with this?
Thanks,
Andrew
gdb/ChangeLog
2012-08-24 Andrew Burgess <aburgess@broadcom.com>
* findvar.c (read_frame_register_value): Mark the result value as
optimized out if any of the input registers have been optimized out.
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 66bcebe..ec9dde7 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -677,7 +677,10 @@ default_value_from_register (struct type *type, int regnum,
/* VALUE must be an lval_register value. If regnum is the value's
associated register number, and len the length of the values type,
read one or more registers in FRAME, starting with register REGNUM,
- until we've read LEN bytes. */
+ until we've read LEN bytes.
+
+ If any of the registers we try to read are optimized out, then mark the
+ complete resulting value as optimized out. */
void
read_frame_register_value (struct value *value, struct frame_info *frame)
@@ -703,6 +706,12 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
struct value *regval = get_frame_register_value (frame, regnum);
int reg_len = TYPE_LENGTH (value_type (regval)) - reg_offset;
+ if (value_optimized_out (regval))
+ {
+ set_value_optimized_out (value, 1);
+ break;
+ }
+
/* If the register length is larger than the number of bytes
remaining to copy, then only copy the appropriate bytes. */
if (reg_len > len)
gdb/testsuite/ChangeLog
2012-08-31 Andrew Burgess <aburgess@broadcom.com>
* gdb.dwarf2/dw2-op-out-param.S: New file.
* gdb.dwarf2/dw2-op-out-param.exp: New file.
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.S b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.S
new file mode 100644
index 0000000..48fa136
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.S
@@ -0,0 +1,678 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 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 the behaviour of gdb in the following situation, the dwarf debug
+ information describes a parameter as being in a register but a more
+ recent (inner) frame marks the register as being undefined.
+
+ This can arrise if the dwarf producer has the location of a parameter in
+ a callee clobbered register at the time of a call. Older versions of
+ gcc used to do this, newer versions seem to avoid this issue.
+
+ Though it could be argued that such dwarf is incorrect, we would still
+ like gdb to behave in a user friendly, and helpful way when presented
+ with such dwarf. */
+
+/* There are 4 test cases in this assembler file. In each case funcion
+ main calls each test function in turn, each test case then calls the
+ breakpt function.
+
+ We don't actually pass any parameters around, we don't need to, instead
+ the dwarf for each test function declares that the function has some
+ parameters, and tells us which registers these parameters are in. The
+ breakpt function marks some of these registers as undefined. The main
+ function helpfully places some marker values into all the registers that
+ are used as parameters so we can see if they ever get printed.
+
+ We use gdb to break in the breakpt function for each of the 4 test
+ cases, and then backtrace through the test function back to main. In
+ each case some or all of the parameters to the test function should be
+ marked as optimized out, due to the breakpt function effectively
+ clobbering them.
+
+ The dwarf register numbering is different to the gdb register number.
+ In some of the tests we rely on gdb behaviour of being able to specify a
+ struct using a single register location, the structure will then "flow"
+ into the next gdb register. The initial register is specified using a
+ dwarf register number, but the "next" register will depend on gdb
+ register ordering.
+
+ Exposing this internal gdb register numbering is really a gdb bug, the
+ functionality for selecting the "next" register should be moved into
+ target dependent code (such as AVR). Right now we work around this
+ bug in this test; if the bug is ever fixed this test is going to need
+ some tweaking.
+
+ The breakpt function always marks rcx, rsi, and rdi as undefined.
+
+ register | dwarf | gdb | |
+ name | reg # | reg # | breakpt |
+ ----------|-------|-------|---------|
+ rdx | 1 | 3 | |
+ rcx | 2 | 2 | undef |
+ rbx | 3 | 1 | |
+ rsi | 4 | 4 | undef |
+ rdi | 5 | 5 | undef |
+
+ We declare the test parameters to be in the register rdx, rcx, rbx, rsi,
+ and rdi. Of these, rdx and rbx are not traditionally used for parameter
+ passing, but that really doesn't matter for this test.
+
+ int_param_single_reg_loc: Passes 8-byte integer parameters in 8-byte
+ registers using DW_OP_regn style location
+ information. The parameters are placed as
+ follows, operand0 (rcx), operand1 (rbx),
+ operand2 (rsi). We expect operand0 and
+ operand2 to be marked as optimised out, but
+ operand1 to be valid.
+
+ struct_param_single_reg_loc: Passes 16-byte structures in two 8-byte
+ registers using dwarf DW_OP_regn location
+ information to describe a single register,
+ gdb will assume that the structure flows
+ into the next sequential register. The
+ parameters are placed as follows, operand0
+ (rbx/rcx), operand1 (rcx/rdx), and operand2
+ (rsi/rdi). The reuse of rcx between
+ operand0 and operand1 is intentional.
+
+ struct_param_two_reg_pieces: Passes 16-byte structure in two 8-byte
+ registers using dwarf DW_OP_piece based
+ location information to describe both
+ registers. The parameters are placed as
+ follows, operand0 (rdx/rcx), operand1
+ (rcx/rbx), and operand2 (rsi/rdi). The
+ reuse of rcx between operand0 and operand1
+ is intentional.
+
+ int_param_two_reg_pieces: Passes 8-byte integer values in two 8-byte
+ registers with 4-bytes being placed in each
+ register, using dwarf DW_OP_piece based
+ location information to describe how the
+ parameters are split up.The parameters are
+ placed as follows, operand0 (rdx/rcx),
+ operand1 (rcx/rbx), and operand2 (rsi/rdi).
+ The reuse of rcx between operand0 and operand1
+ is intentional.
+*/
+
+ .text
+
+.Ltext0:
+
+ /* main */
+.globl main
+ .type main, @function
+main:
+.Ltext1:
+ sub $0x8,%rsp
+.Ltext2:
+ movq $0xdeadbe00deadbe01, %rbx
+ movq $0xdeadbe02deadbe03, %rcx
+ movq $0xdeadbe04deadbe05, %rdx
+ movq $0xdeadbe06deadbe07, %rsi
+ movq $0xdeadbe08deadbe09, %rdi
+
+ callq int_param_single_reg_loc
+ nop
+
+ callq struct_param_single_reg_loc
+ nop
+
+ callq struct_param_two_reg_pieces
+ nop
+
+ callq int_param_two_reg_pieces
+ nop
+
+ add $0x8,%rsp
+ retq
+.Ltext3:
+ .size main, .-main
+
+ /* breakpt */
+.globl breakpt
+ .type breakpt, @function
+breakpt:
+.Ltext4:
+ sub $0x8,%rsp
+ add $0x8, %rsp
+ retq
+.Ltext5:
+ .size breakpt, .-breakpt
+
+ /* int_param_single_reg_loc */
+.globl int_param_single_reg_loc
+ .type int_param_single_reg_loc, @function
+int_param_single_reg_loc:
+.Ltext5:
+ sub $0x8,%rsp
+.Ltext6:
+ nop
+ callq breakpt
+ nop
+ add $0x8,%rsp
+ retq
+.Ltext7:
+ .size int_param_single_reg_loc, .-int_param_single_reg_loc
+
+ /* struct_param_single_reg_loc */
+.globl struct_param_single_reg_loc
+ .type struct_param_single_reg_loc, @function
+struct_param_single_reg_loc:
+.Ltext8:
+ sub $0x8,%rsp
+.Ltext9:
+ nop
+ callq breakpt
+ nop
+ add $0x8,%rsp
+ retq
+.Ltext10:
+ .size struct_param_single_reg_loc, .-struct_param_single_reg_loc
+
+ /* struct_param_two_reg_pieces */
+.globl struct_param_two_reg_pieces
+ .type struct_param_two_reg_pieces, @function
+struct_param_two_reg_pieces:
+.Ltext11:
+ sub $0x8,%rsp
+.Ltext12:
+ nop
+ callq breakpt
+ nop
+ add $0x8,%rsp
+ retq
+.Ltext13:
+ .size struct_param_two_reg_pieces, .-struct_param_two_reg_pieces
+
+ /* int_param_two_reg_pieces */
+.globl int_param_two_reg_pieces
+ .type int_param_two_reg_pieces, @function
+int_param_two_reg_pieces:
+.Ltext14:
+ sub $0x8,%rsp
+.Ltext15:
+ nop
+ callq breakpt
+ nop
+ add $0x8,%rsp
+ retq
+.Ltext16:
+ .size int_param_two_reg_pieces, .-int_param_two_reg_pieces
+
+
+.Letext0:
+
+ /*******************************************************/
+
+ .section .debug_frame,"",@progbits
+
+ /* CIE */
+.Lframe0:
+ .long .LECIE0-.LSCIE0 /* length */
+.LSCIE0:
+ .long 0xffffffff /* CIE_id */
+ .byte 0x1 /* version */
+ .string "" /* augmentation */
+ .uleb128 0x1 /* code alignment */
+ .sleb128 -8 /* data alignment */
+ .byte 0x10 /* R/A column */
+ /* Initial instructions */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .uleb128 0x7 /* reg# */
+ .uleb128 0x8 /* offset */
+ .byte 0x90 /* DW_CFA_offset (r16) */
+ .uleb128 0x1 /* offset */
+ .align 8
+.LECIE0:
+
+ /* FDE : breakpt */
+.LSFDE0:
+ .long .LEFDE0-.LASFDE0 /* length */
+.LASFDE0:
+ .long .Lframe0 /* CIE reference */
+ .quad .Ltext4 /* start */
+ .quad .Ltext5-.Ltext4 /* length */
+ /* Instructions */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x2 /* reg# */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x4 /* reg# */
+ .byte 0x7 /* DW_CFA_undefined */
+ .uleb128 0x5 /* reg# */
+ .align 8
+.LEFDE0:
+
+ /* FDE : int_param_single_reg_loc */
+.LSFDE2:
+ .long .LEFDE2-.LASFDE2 /* length */
+.LASFDE2:
+ .long .Lframe0 /* CIE reference */
+ .quad .Ltext5 /* start */
+ .quad .Ltext7-.Ltext5 /* length */
+ /* Instructions */
+ .byte 0x4
+ .long .Ltext6-.Ltext5
+ .byte 0xe
+ .uleb128 0x10
+ .align 8
+.LEFDE2:
+
+ /* FDE : struct_param_single_reg_loc */
+.LSFDE3:
+ .long .LEFDE3-.LASFDE3 /* length */
+.LASFDE3:
+ .long .Lframe0 /* CIE reference */
+ .quad .Ltext8 /* start */
+ .quad .Ltext10-.Ltext8 /* length */
+ /* Instructions */
+ .byte 0x4
+ .long .Ltext9-.Ltext8
+ .byte 0xe
+ .uleb128 0x10
+ .align 8
+.LEFDE3:
+
+ /* FDE : struct_param_two_reg_pieces */
+.LSFDE4:
+ .long .LEFDE4-.LASFDE4 /* length */
+.LASFDE4:
+ .long .Lframe0 /* CIE reference */
+ .quad .Ltext11 /* start */
+ .quad .Ltext13-.Ltext11 /* length */
+ /* Instructions */
+ .byte 0x4
+ .long .Ltext12-.Ltext11
+ .byte 0xe
+ .uleb128 0x10
+ .align 8
+.LEFDE4:
+
+ /* FDE : int_param_two_reg_pieces */
+.LSFDE5:
+ .long .LEFDE5-.LASFDE5 /* length */
+.LASFDE5:
+ .long .Lframe0 /* CIE reference */
+ .quad .Ltext14 /* start */
+ .quad .Ltext16-.Ltext14 /* length */
+ /* Instructions */
+ .byte 0x4
+ .long .Ltext15-.Ltext14
+ .byte 0xe
+ .uleb128 0x10
+ .align 8
+.LEFDE5:
+
+ /* FDE : main */
+.LSFDE9:
+ .long .LEFDE9-.LASFDE9 /* length */
+.LASFDE9:
+ .long .Lframe0 /* CIE reference */
+ .quad .Ltext1 /* start */
+ .quad .Ltext3-.Ltext1 /* length */
+ /* Instructions */
+ .byte 0x4
+ .long .Ltext2-.Ltext1
+ .byte 0xe
+ .uleb128 0x10
+ .align 8
+.LEFDE9:
+
+ /*******************************************************/
+
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .long .Ldebug_info_end - .Ldebug_info_start /* Length */
+.Ldebug_info_start:
+ .value 0x2 /* DWARF version number. */
+ .long .Ldebug_abbrev0 /* Offset into .debug_abbrev */
+ .byte 0x8 /* Pointer size */
+
+.LDI0:
+ .uleb128 0x1 /* DW_TAG_compile_unit */
+ .string "GNU C 4.2.1" /* DW_AT_producer */
+ .byte 0x1 /* DW_AT_language */
+ .quad .Ltext0 /* DW_AT_low_pc */
+ .quad .Letext0 /* DW_AT_high_pc */
+
+.LDI1:
+ .uleb128 0x2 /* DW_TAG_subprogram */
+ .byte 0x1 /* DW_AT_external */
+ .string "breakpt" /* DW_AT_name */
+ .byte 0x1 /* DW_AT_prototyped */
+ .quad .Ltext4 /* DW_AT_low_pc */
+ .quad .Ltext5 /* DW_AT_high_pc */
+
+.LDI2:
+ .uleb128 0x5 /* DW_TAG_base_type */
+ .byte 0x8 /* DW_AT_byte_size */
+ .byte 0x5 /* DW_AT_encoding (DW_ATE_signed) */
+ .string "long int" /* DW_AT_name */
+
+.LDI3:
+ .uleb128 0x7 /* DW_TAG_structure_type */
+ .string "big" /* DW_AT_name */
+ .byte 0x10 /* DW_AT_byte_size */
+ .long .LDI6 /* DW_AT_sibling */
+
+.LDI4:
+ .uleb128 0x8 /* DW_TAG_member */
+ .string "a" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 0x2 /* DW_AT_data_member_location : length */
+ .byte 0x23 /* DW_OP_plus_uconst */
+ .uleb128 0x0 /* + 0 */
+
+.LDI5:
+ .uleb128 0x8 /* DW_TAG_structure_type */
+ .string "b" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 0x2 /* DW_AT_data_member_location : length */
+ .byte 0x23 /* DW_OP_plus_uconst */
+ .uleb128 0x8 /* + 8 */
+ .byte 0x0
+
+.LDI6:
+ .uleb128 0x6 /* DW_TAG_subprogram */
+ .byte 0x1 /* DW_AT_external */
+ .string "main" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .quad .Ltext1 /* DW_AT_low_pc */
+ .quad .Ltext3 /* DW_AT_high_pc */
+
+.LDI7:
+ .uleb128 0x3 /* DW_TAG_subprogram */
+ .byte 0x1 /* DW_AT_external */
+ .string "int_param_single_reg_loc" /* DW_AT_name */
+ .byte 0x1 /* DW_AT_prototyped */
+ .quad .Ltext5 /* DW_AT_low_pc */
+ .quad .Ltext7 /* DW_AT_high_pc */
+ .long .LDI11 /* DW_AT_sibling */
+
+.LDI8:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand0" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 1 /* DW_AT_location : length */
+ .byte 0x52 /* DW_OP_reg2 */
+
+.LDI9:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand1" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 1 /* DW_AT_location : length */
+ .byte 0x53 /* DW_OP_reg3 */
+
+.LDI10:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand2" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 1 /* DW_AT_location : length */
+ .byte 0x54 /* DW_OP_reg4 */
+
+ .byte 0x0
+
+.LDI11:
+ .uleb128 0x3 /* DW_TAG_subprogram */
+ .byte 0x1 /* DW_AT_external */
+ .string "struct_param_single_reg_loc" /* DW_AT_name */
+ .byte 0x1 /* DW_AT_prototyped */
+ .quad .Ltext8 /* DW_AT_low_pc */
+ .quad .Ltext10 /* DW_AT_high_pc */
+ .long .LDI15 /* DW_AT_sibling */
+
+.LDI12:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand0" /* DW_AT_name */
+ .long .LDI3 /* DW_AT_type */
+ .byte 1 /* DW_AT_location : length */
+ .byte 0x53 /* DW_OP_reg3 */
+
+.LDI13:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand1" /* DW_AT_name */
+ .long .LDI3 /* DW_AT_type */
+ .byte 1 /* DW_AT_location : length */
+ .byte 0x52 /* DW_OP_reg2 */
+
+.LDI14:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand2" /* DW_AT_name */
+ .long .LDI3 /* DW_AT_type */
+ .byte 1 /* DW_AT_location : length */
+ .byte 0x54 /* DW_OP_reg4 */
+
+ .byte 0x0
+
+.LDI15:
+ .uleb128 0x3 /* DW_TAG_subprogram */
+ .byte 0x1 /* DW_AT_external */
+ .string "struct_param_two_reg_pieces" /* DW_AT_name */
+ .byte 0x1 /* DW_AT_prototyped */
+ .quad .Ltext11 /* DW_AT_low_pc */
+ .quad .Ltext13 /* DW_AT_high_pc */
+ .long .LDI19 /* DW_AT_sibling */
+
+.LDI16:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand0" /* DW_AT_name */
+ .long .LDI3 /* DW_AT_type */
+ .byte 6 /* DW_AT_location : length */
+ .byte 0x51 /* DW_OP_reg1 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x8 /* 8 bytes */
+ .byte 0x52 /* DW_OP_reg2 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x8 /* 8 bytes */
+
+.LDI17:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand1" /* DW_AT_name */
+ .long .LDI3 /* DW_AT_type */
+ .byte 6 /* DW_AT_location : length */
+ .byte 0x52 /* DW_OP_reg2 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x8 /* 8 bytes */
+ .byte 0x53 /* DW_OP_reg3 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x8 /* 8 bytes */
+
+.LDI18:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand2" /* DW_AT_name */
+ .long .LDI3 /* DW_AT_type */
+ .byte 6 /* DW_AT_location : length */
+ .byte 0x54 /* DW_OP_reg4 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x8 /* 8 bytes */
+ .byte 0x55 /* DW_OP_reg5 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x8 /* 8 bytes */
+
+ .byte 0x0
+
+.LDI19:
+ .uleb128 0x3 /* DW_TAG_subprogram */
+ .byte 0x1 /* DW_AT_external */
+ .string "int_param_two_reg_pieces" /* DW_AT_name */
+ .byte 0x1 /* DW_AT_prototyped */
+ .quad .Ltext14 /* DW_AT_low_pc */
+ .quad .Ltext16 /* DW_AT_high_pc */
+ .long .LDIE0 /* DW_AT_sibling */
+
+.LDI20:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand0" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 6 /* DW_AT_location : length */
+ .byte 0x51 /* DW_OP_reg1 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x4 /* 4 bytes */
+ .byte 0x52 /* DW_OP_reg2 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x4 /* 4 bytes */
+
+.LDI21:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand1" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 6 /* DW_AT_location : length */
+ .byte 0x52 /* DW_OP_reg2 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x4 /* 4 bytes */
+ .byte 0x53 /* DW_OP_reg3 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x4 /* 4 bytes */
+
+.LDI22:
+ .uleb128 0x4 /* DW_TAG_formal_parameter */
+ .string "operand2" /* DW_AT_name */
+ .long .LDI2 /* DW_AT_type */
+ .byte 6 /* DW_AT_location : length */
+ .byte 0x54 /* DW_OP_reg4 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x4 /* 4 bytes */
+ .byte 0x55 /* DW_OP_reg5 */
+ .byte 0x93 /* DW_OP_piece */
+ .uleb128 0x4 /* 4 bytes */
+
+ .byte 0x0
+
+.LDIE0:
+ .byte 0x0
+.Ldebug_info_end:
+
+ /*******************************************************/
+
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .uleb128 0x1 /* abbrev code */
+ .uleb128 0x11 /* TAG: DW_TAG_compile_unit */
+ .byte 0x1 /* DW_CHILDREN_yes */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x2 /* abbrev code */
+ .uleb128 0x2e /* TAG: DW_TAG_subprogram */
+ .byte 0x0 /* DW_CHILDREN_no */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x27 /* DW_AT_prototyped */
+ .uleb128 0xc /* DW_FORM_flag*/
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x3 /* abbrev code */
+ .uleb128 0x2e /* TAG: DW_TAG_subprogram */
+ .byte 0x1 /* DW_CHILDREN_yes */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x27 /* DW_AT_prototyped */
+ .uleb128 0xc /* DW_FORM_flag*/
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x1 /* DW_AT_sibling */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x4 /* abbrev code */
+ .uleb128 0x5 /* TAG: DW_TAG_formal_parameter */
+ .byte 0x0 /* DW_CHILDREN_no */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2 /* DW_AT_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x5 /* abbrev code */
+ .uleb128 0x24 /* TAG: DW_TAG_base_type */
+ .byte 0x0 /* DW_CHILDREN_no */
+ .uleb128 0xb /* DW_AT_byte_size */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3e /* DW_AT_encoding */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x6 /* abbrev code */
+ .uleb128 0x2e /* TAG: DW_TAG_subprogram */
+ .byte 0x0 /* DW_CHILDREN_no */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x7 /* abbrev code */
+ .uleb128 0x13 /* DW_TAG_structure_type */
+ .byte 0x1 /* DW_CHILDREN_yes */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0xb /* DW_AT_byte_size */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x1 /* DW_AT_sibling */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0
+ .byte 0x0
+
+ .uleb128 0x8 /* abbrev code */
+ .uleb128 0xd /* DW_TAG_member */
+ .byte 0x0 /* DW_children_no */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x38 /* DW_AT_data_member_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0
+ .byte 0x0
+
+ .byte 0x0
+
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
new file mode 100644
index 0000000..ec98a3a
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
@@ -0,0 +1,108 @@
+# Copyright 2012 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
+
+set test "dw2-op-out-param"
+
+# 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
+}
+
+if { [prepare_for_testing "${test}.exp" "${test}" ${test}.S {nodebug}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint "breakpt"
+
+# Change the radix, making it easier to spot 0xdeadbeef in output.
+gdb_test "set output-radix 16" \
+ "Output radix now set to decimal 16, hex 10, octal 20."
+
+# So we get to see the structure arguments.
+gdb_test_no_output "set print frame-arguments all"
+
+# (1) int_param_single_reg_loc
+gdb_continue_to_breakpoint "Stop in breakpt for test int_param_single_reg_loc"
+gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_single_reg_loc \\(operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)" "Backtrace for test int_param_single_reg_loc"
+
+# (2) struct_param_single_reg_loc
+gdb_continue_to_breakpoint "Stop in breakpt for struct_param_single_reg_loc"
+set test "Backtrace for test struct_param_single_reg_loc"
+gdb_test_multiple "bt" "$test" {
+ -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe04deadbe05}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" {
+ # If we ever fix gdb so that we start to hit this case then we
+ # should delete the passing case below as this is a better state to
+ # be in, and we don't want to regress back to the case below.
+ xpass $test
+ }
+ -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" {
+ # Having DWARF debug information placing things into registers that
+ # are then clobbered is really bad debug information. If this is
+ # ever seen we'd prefer to fix the producer of the debug
+ # information. Right now there are no plans to improve this case
+ # in gdb so we're happy with the output given above.
+ pass $test
+ }
+}
+
+# (3) struct_param_two_reg_pieces
+gdb_continue_to_breakpoint "Stop in breakpt for struct_param_two_reg_pieces"
+set test "Backtrace for test struct_param_two_reg_pieces"
+gdb_test_multiple "bt" "$test" {
+ -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" {
+ # If we ever fix gdb so this passes we should delete the
+ # unsupported case below.
+ xpass $test
+ }
+ -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0=.*, operand1=.*, operand2=.*\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" {
+ # Having DWARF debug information placing things into registers that
+ # are then clobbered is really bad debug information. If this is
+ # ever seen we'd prefer to fix the producer of the debug
+ # information. Right now there are no plans to fix this case in
+ # gdb.
+ unsupported $test
+ }
+}
+
+# (4) int_param_two_reg_pieces
+gdb_continue_to_breakpoint "Stop in breakpt for int_param_two_reg_pieces"
+set test "Backtrace for test int_param_two_reg_pieces"
+gdb_test_multiple "bt" "$test" {
+ -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" {
+ # If we ever fix gdb so this passes we should delete the
+ # unsupported case below.
+ xpass $test
+ }
+ -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=.*, operand1=.*, operand2=.*\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" {
+ # Having DWARF debug information placing things into registers that
+ # are then clobbered is really bad debug information. If this is
+ # ever seen we'd prefer to fix the producer of the debug
+ # information. Right now there are no plans to fix this case in
+ # gdb.
+ unsupported $test
+ }
+}
+