[4/5] ARM: read_pieced_value do big endian processing only in case of valid gdb_regnum

Message ID 1413853021-4393-5-git-send-email-victor.kamensky@linaro.org
State New
Headers show

Commit Message

vkamensky Oct. 21, 2014, 12:57 a.m.
During armv7b testing gdb.base/store.exp test was failling with
'GDB internal error'. It turns out that compiler generated DWARF
with non-existent register numbers. The compiler issue is present
in both little endian (armv7) and big endian (armv7b) (it is
separate issue). In both case gdbarch_dwarf2_reg_to_regnum returns
-1 which is stored into gdb_regnum. But it cause severe problem
only in big endian case because in read_pieced_value and
write_pieced_value functions BFD_ENDIAN_BIG related processing
happen regardless of gdb_regnum value, and in case of gdb_regnum=-1,
it cause 'GDB internal error' and crash.

Solution is to move BFD_ENDIAN_BIG related processing under
(gdb_regnum != -1) branch of processing.
---
 gdb/ChangeLog   |  6 ++++++
 gdb/dwarf2loc.c | 30 +++++++++++++++---------------
 2 files changed, 21 insertions(+), 15 deletions(-)

Comments

Yao Qi Oct. 22, 2014, 9:27 a.m. | #1
Victor Kamensky <victor.kamensky@linaro.org> writes:

Hi Victor,
Could you please add more details in the commit message? for example....

> During armv7b testing gdb.base/store.exp test was failling with
> 'GDB internal error'. It turns out that compiler generated DWARF

What is the 'GDB internal error'?  Is it like this?

(gdb) PASS: gdb.base/store.exp: continue to wack_double
print l^M
gdb/regcache.c:178: internal-error: register_size: Assertion `regnum >= 0 && regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))' failed.^M
A problem internal to GDB has been detected,

We've seen this internal error on (armv5te big-endian) for a while.

> with non-existent register numbers. The compiler issue is present
> in both little endian (armv7) and big endian (armv7b) (it is
> separate issue). In both case gdbarch_dwarf2_reg_to_regnum returns

Is there any PR opened for the compiler issue?  If there is, please
mention it in the commit message, otherwise, please describe the
mistakes in the compiler generated debug info, the snippet of
'readelf -wi' output, which shows the wrong register number, should be fine.

> -1 which is stored into gdb_regnum. But it cause severe problem
> only in big endian case because in read_pieced_value and
> write_pieced_value functions BFD_ENDIAN_BIG related processing
> happen regardless of gdb_regnum value, and in case of gdb_regnum=-1,
> it cause 'GDB internal error' and crash.
>
> Solution is to move BFD_ENDIAN_BIG related processing under
> (gdb_regnum != -1) branch of processing.

With your patch applied, the internal error is fixed.  How does GDB
behave now?  What is the output for 'print l'?  In my case, it becomes:

print l^M
Unable to access DWARF register number 80^M
(gdb) FAIL: gdb.base/store.exp: upvar float l; print old l, expecting -1

> ---
>  gdb/ChangeLog   |  6 ++++++
>  gdb/dwarf2loc.c | 30 +++++++++++++++---------------
>  2 files changed, 21 insertions(+), 15 deletions(-)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index c32fb3f..6a735b8 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,5 +1,11 @@
>  2014-10-13  Victor Kamensky  <victor.kamensky@linaro.org>
>  
> +	* dwarf2loc.c (read_pieced_value): do BE processing only if
> +	gdb_regnum is not -1.

s/do/Do.  Looks you've fixed it in V2.
s/BE/big endian/ because BE isn't very clear here.

> +	(write_pieced_value): Ditto.
> +
> +2014-10-13  Victor Kamensky  <victor.kamensky@linaro.org>
> +
>  	* arm-tdep.c: (extract_arm_insn): use dbarch_byte_order_for_code
>  	to read arm instruction.
>  
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index e347e59..fbe99bb 100644
> --- a/gdb/dwarf2loc.c
> +++ b/gdb/dwarf2loc.c
> @@ -1686,20 +1686,20 @@ read_pieced_value (struct value *v)
>  	    int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno);
>  	    int reg_offset = source_offset;
>  
> -	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
> -		&& this_size < register_size (arch, gdb_regnum))
> -	      {
> -		/* Big-endian, and we want less than full size.  */
> -		reg_offset = register_size (arch, gdb_regnum) - this_size;
> -		/* We want the lower-order THIS_SIZE_BITS of the bytes
> -		   we extract from the register.  */
> -		source_offset_bits += 8 * this_size - this_size_bits;
> -	      }
> -
>  	    if (gdb_regnum != -1)
>  	      {
>  		int optim, unavail;
>  
> +		if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
> +		    && this_size < register_size (arch, gdb_regnum))
> +		  {
> +		    /* Big-endian, and we want less than full size.  */
> +		    reg_offset = register_size (arch, gdb_regnum) - this_size;
> +		    /* We want the lower-order THIS_SIZE_BITS of the bytes
> +		       we extract from the register.  */
> +		    source_offset_bits += 8 * this_size - this_size_bits;
> +		 }
> +

Nit: after the change, local variable 'reg_offset' is only used in the
"if (gdb_regnum != -1) {}" block, so we can move 'reg_offset' into that
block.
vkamensky Oct. 22, 2014, 3:27 p.m. | #2
Hi Yao,

I've attached my notes I captured while looking at
this issue. Some snippets from them repeated below
inline:

On 22 October 2014 02:27, Yao Qi <yao@codesourcery.com> wrote:
> Victor Kamensky <victor.kamensky@linaro.org> writes:
>
> Hi Victor,
> Could you please add more details in the commit message? for example....
>
>> During armv7b testing gdb.base/store.exp test was failling with
>> 'GDB internal error'. It turns out that compiler generated DWARF
>
> What is the 'GDB internal error'?  Is it like this?
>
> (gdb) PASS: gdb.base/store.exp: continue to wack_double
> print l^M
> gdb/regcache.c:178: internal-error: register_size: Assertion `regnum >= 0 && regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))' failed.^M
> A problem internal to GDB has been detected,

Yes, it is like this. I'll added into commit message.

> We've seen this internal error on (armv5te big-endian) for a while.
>
>> with non-existent register numbers. The compiler issue is present
>> in both little endian (armv7) and big endian (armv7b) (it is
>> separate issue). In both case gdbarch_dwarf2_reg_to_regnum returns
>
> Is there any PR opened for the compiler issue?  If there is, please
> mention it in the commit message, otherwise, please describe the
> mistakes in the compiler generated debug info, the snippet of
> 'readelf -wi' output, which shows the wrong register number, should be fine.

In both little endian and big endian cases compiler generate DW_OP_reg29-
DW_OP_reg31 something like this.

 <2><792>: Abbrev Number: 10 (DW_TAG_formal_parameter)
    <793>   DW_AT_name        : u
    <795>   DW_AT_decl_file   : 1
    <796>   DW_AT_decl_line   : 115
    <797>   DW_AT_type        : <0x57c>
    <79b>   DW_AT_location    : 6 byte block: 6d 93 4 6c 93 4
(DW_OP_reg29 (r29); DW_OP_piece: 4; DW_OP_reg28 (r28); DW_OP_piece: 4)

I strongly suspect that it is compiler error, but more accurately
it is hard to say, because I never saw a document where for given CPU
mapping from registers to DWARF reg numbers is defined. Have you
seen such document for example for ARM V7? In any case for this
test case Gdb believes that those register numbers are wrong. I.e we
can say for sure that gcc and gdb are disagrees.

>> -1 which is stored into gdb_regnum. But it cause severe problem
>> only in big endian case because in read_pieced_value and
>> write_pieced_value functions BFD_ENDIAN_BIG related processing
>> happen regardless of gdb_regnum value, and in case of gdb_regnum=-1,
>> it cause 'GDB internal error' and crash.
>>
>> Solution is to move BFD_ENDIAN_BIG related processing under
>> (gdb_regnum != -1) branch of processing.
>
> With your patch applied, the internal error is fixed.  How does GDB
> behave now?  What is the output for 'print l'?  In my case, it becomes:
>
> print l^M
> Unable to access DWARF register number 80^M
> (gdb) FAIL: gdb.base/store.exp: upvar float l; print old l, expecting -1

Yes it becomes the same as little endian result for the same test case.

The only issue addressed by patch that it makes big endian case behave
consistently with little endian - i.e don't do register_size call for unknown
register number

>> ---
>>  gdb/ChangeLog   |  6 ++++++
>>  gdb/dwarf2loc.c | 30 +++++++++++++++---------------
>>  2 files changed, 21 insertions(+), 15 deletions(-)
>>
>> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
>> index c32fb3f..6a735b8 100644
>> --- a/gdb/ChangeLog
>> +++ b/gdb/ChangeLog
>> @@ -1,5 +1,11 @@
>>  2014-10-13  Victor Kamensky  <victor.kamensky@linaro.org>
>>
>> +     * dwarf2loc.c (read_pieced_value): do BE processing only if
>> +     gdb_regnum is not -1.
>
> s/do/Do.  Looks you've fixed it in V2.
> s/BE/big endian/ because BE isn't very clear here.
>
>> +     (write_pieced_value): Ditto.
>> +
>> +2014-10-13  Victor Kamensky  <victor.kamensky@linaro.org>
>> +
>>       * arm-tdep.c: (extract_arm_insn): use dbarch_byte_order_for_code
>>       to read arm instruction.
>>
>> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
>> index e347e59..fbe99bb 100644
>> --- a/gdb/dwarf2loc.c
>> +++ b/gdb/dwarf2loc.c
>> @@ -1686,20 +1686,20 @@ read_pieced_value (struct value *v)
>>           int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno);
>>           int reg_offset = source_offset;
>>
>> -         if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
>> -             && this_size < register_size (arch, gdb_regnum))
>> -           {
>> -             /* Big-endian, and we want less than full size.  */
>> -             reg_offset = register_size (arch, gdb_regnum) - this_size;
>> -             /* We want the lower-order THIS_SIZE_BITS of the bytes
>> -                we extract from the register.  */
>> -             source_offset_bits += 8 * this_size - this_size_bits;
>> -           }
>> -
>>           if (gdb_regnum != -1)
>>             {
>>               int optim, unavail;
>>
>> +             if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
>> +                 && this_size < register_size (arch, gdb_regnum))
>> +               {
>> +                 /* Big-endian, and we want less than full size.  */
>> +                 reg_offset = register_size (arch, gdb_regnum) - this_size;
>> +                 /* We want the lower-order THIS_SIZE_BITS of the bytes
>> +                    we extract from the register.  */
>> +                 source_offset_bits += 8 * this_size - this_size_bits;
>> +              }
>> +
>
> Nit: after the change, local variable 'reg_offset' is only used in the
> "if (gdb_regnum != -1) {}" block, so we can move 'reg_offset' into that
> block.

Ok, I'll make this change too. I'll update comment note with details
and repost the patch.

Thanks,
Victor

> --
> Yao (齐尧)
(gdb) file /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store
Reading symbols from /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store...done.
(gdb) tbreak wack_double
Temporary breakpoint 1 at 0x1076c: file ../../../binutils-gdb/gdb/testsuite/gdb.base/store.c, line 117.
(gdb) run
Starting program: /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store 

Temporary breakpoint 1, wack_double (u=
../../binutils-gdb/gdb/regcache.c:177: internal-error: register_size: Assertion `regnum >= 0 && regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.


BE Dump
=======


 <1><779>: Abbrev Number: 12 (DW_TAG_subprogram)
    <77a>   DW_AT_external    : 1       
    <77a>   DW_AT_name        : (indirect string, offset: 0x3c9): wack_double   
    <77e>   DW_AT_decl_file   : 1       
    <77f>   DW_AT_decl_line   : 115     
    <780>   DW_AT_prototyped  : 1       
    <780>   DW_AT_type        : <0x57c> 
    <784>   DW_AT_low_pc      : 0x10758 
    <788>   DW_AT_high_pc     : 0x40    
    <78c>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <78e>   DW_AT_GNU_all_tail_call_sites: 1    
    <78e>   DW_AT_sibling     : <0x7d7> 
 <2><792>: Abbrev Number: 10 (DW_TAG_formal_parameter)
    <793>   DW_AT_name        : u       
    <795>   DW_AT_decl_file   : 1       
    <796>   DW_AT_decl_line   : 115     
    <797>   DW_AT_type        : <0x57c> 
    <79b>   DW_AT_location    : 6 byte block: 6d 93 4 6c 93 4   (DW_OP_reg29 (r29); DW_OP_piece: 4; DW_OP_reg28 (r28); DW_OP_piece: 4)
 <2><7a2>: Abbrev Number: 10 (DW_TAG_formal_parameter)
    <7a3>   DW_AT_name        : v       
    <7a5>   DW_AT_decl_file   : 1       
    <7a6>   DW_AT_decl_line   : 115     
    <7a7>   DW_AT_type        : <0x57c> 
    <7ab>   DW_AT_location    : 6 byte block: 6f 93 4 6e 93 4   (DW_OP_reg31 (r31); DW_OP_piece: 4; DW_OP_reg30 (r30); DW_OP_piece: 4)
 <2><7b2>: Abbrev Number: 13 (DW_TAG_variable)
    <7b3>   DW_AT_name        : l       
    <7b5>   DW_AT_decl_file   : 1       
    <7b6>   DW_AT_decl_line   : 117     
    <7b7>   DW_AT_type        : <0x57c> 
    <7bb>   DW_AT_location    : 8 byte block: 90 21 93 4 90 20 93 4     (DW_OP_regx: 33 (r33); DW_OP_piece: 4; DW_OP_regx: 32 (r32); DW_OP_piece: 4)
 <2><7c4>: Abbrev Number: 13 (DW_TAG_variable)
    <7c5>   DW_AT_name        : r       
    <7c7>   DW_AT_decl_file   : 1       
    <7c8>   DW_AT_decl_line   : 117     
    <7c9>   DW_AT_type        : <0x57c> 
    <7cd>   DW_AT_location    : 8 byte block: 90 23 93 4 90 22 93 4     (DW_OP_regx: 35 (r35); DW_OP_piece: 4; DW_OP_regx: 34 (r34); DW_OP_piece: 4)

LE Dump
=======

 <1><777>: Abbrev Number: 12 (DW_TAG_subprogram)
    <778>   DW_AT_external    : 1       
    <778>   DW_AT_name        : (indirect string, offset: 0x3c9): wack_double   
    <77c>   DW_AT_decl_file   : 1       
    <77d>   DW_AT_decl_line   : 115     
    <77e>   DW_AT_prototyped  : 1       
    <77e>   DW_AT_type        : <0x57a> 
    <782>   DW_AT_low_pc      : 0x10758 
    <786>   DW_AT_high_pc     : 0x40    
    <78a>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <78c>   DW_AT_GNU_all_tail_call_sites: 1    
    <78c>   DW_AT_sibling     : <0x7d5> 
 <2><790>: Abbrev Number: 10 (DW_TAG_formal_parameter)
    <791>   DW_AT_name        : u       
    <793>   DW_AT_decl_file   : 1       
    <794>   DW_AT_decl_line   : 115     
    <795>   DW_AT_type        : <0x57a> 
    <799>   DW_AT_location    : 6 byte block: 6c 93 4 6d 93 4   (DW_OP_reg28 (r28); DW_OP_piece: 4; DW_OP_reg29 (r29); DW_OP_piece: 4)
 <2><7a0>: Abbrev Number: 10 (DW_TAG_formal_parameter)
    <7a1>   DW_AT_name        : v       
    <7a3>   DW_AT_decl_file   : 1       
    <7a4>   DW_AT_decl_line   : 115     
    <7a5>   DW_AT_type        : <0x57a> 
    <7a9>   DW_AT_location    : 6 byte block: 6e 93 4 6f 93 4   (DW_OP_reg30 (r30); DW_OP_piece: 4; DW_OP_reg31 (r31); DW_OP_piece: 4)
 <2><7b0>: Abbrev Number: 13 (DW_TAG_variable)
    <7b1>   DW_AT_name        : l       
    <7b3>   DW_AT_decl_file   : 1       
    <7b4>   DW_AT_decl_line   : 117     
    <7b5>   DW_AT_type        : <0x57a> 
    <7b9>   DW_AT_location    : 8 byte block: 90 20 93 4 90 21 93 4     (DW_OP_regx: 32 (r32); DW_OP_piece: 4; DW_OP_regx: 33 (r33); DW_OP_piece: 4)
 <2><7c2>: Abbrev Number: 13 (DW_TAG_variable)
    <7c3>   DW_AT_name        : r       
    <7c5>   DW_AT_decl_file   : 1       
    <7c6>   DW_AT_decl_line   : 117     
    <7c7>   DW_AT_type        : <0x57a> 
    <7cb>   DW_AT_location    : 8 byte block: 90 22 93 4 90 23 93 4     (DW_OP_regx: 34 (r34); DW_OP_piece: 4; DW_OP_regx: 35 (r35); DW_OP_piece: 4)


Backtrace when it failed to get reg number
==========================================

(gdb) n
4207	  if (reg >= 256 && reg <= 287)
(gdb) n
4216	  return -1;
(gdb) bt
#0  arm_dwarf_reg_to_regnum (gdbarch=0x24043a0, reg=29) at ../../binutils-gdb/gdb/arm-tdep.c:4216
#1  0x0020d430 in read_pieced_value (v=0x6c08) at ../../binutils-gdb/gdb/dwarf2loc.c:1686
#2  0x00144d7c in value_fetch_lazy (val=0x2635e08) at ../../binutils-gdb/gdb/value.c:3895
#3  0x001453b0 in value_entirely_covered_by_range_vector (value=0x2635e08, ranges=0x2635e5c)
    at ../../binutils-gdb/gdb/value.c:392
#4  0x00156834 in value_check_printable (val=val@entry=0x2635e08, stream=stream@entry=0x24280c8, options=0xbee8e3ec)
    at ../../binutils-gdb/gdb/valprint.c:810
#5  0x00156bbc in common_val_print (val=0x2635e08, stream=0x24280c8, stream@entry=0x4f505f72, recurse=recurse@entry=2, 
    options=0xbee8e3ec, options@entry=0xbee8e3e4, language=language@entry=0x3b979c <c_language_defn>)
    at ../../binutils-gdb/gdb/valprint.c:849
#6  0x00189cbc in print_frame_arg (arg=0x2044575f) at ../../binutils-gdb/gdb/stack.c:286
#7  0x0018aa04 in print_frame_args (func=<optimized out>, frame=0x0, frame@entry=0x22f74a8, num=36664488, num@entry=-1, 
    stream=0xffffffff) at ../../binutils-gdb/gdb/stack.c:674
#8  0x0018b3f0 in print_frame (frame=frame@entry=0x22f74a8, print_level=print_level@entry=4331400, 
    print_what=print_what@entry=SRC_AND_LOC, print_args=print_args@entry=1, sal=...) at ../../binutils-gdb/gdb/stack.c:1205
#9  0x0018b8bc in print_frame_info (frame=0x22f74a8, frame@entry=0x1, print_level=print_level@entry=4331400, 
    print_what=SRC_AND_LOC, print_what@entry=36664488, print_args=print_args@entry=1, set_current_sal=set_current_sal@entry=1)
    at ../../binutils-gdb/gdb/stack.c:857
#10 0x0018baac in print_stack_frame (frame=0x1, print_level=4331400, print_level@entry=0, print_what=36664488, 
    print_what@entry=SRC_AND_LOC, set_current_sal=0, set_current_sal@entry=1) at ../../binutils-gdb/gdb/stack.c:166
#11 0x0017ffe8 in print_stop_event (ws=ws@entry=0xbee8e6b8) at ../../binutils-gdb/gdb/infrun.c:6280
#12 0x001804c8 in normal_stop () at ../../binutils-gdb/gdb/infrun.c:6426
#13 0x00186304 in fetch_inferior_event (client_data=client_data@entry=0x0) at ../../binutils-gdb/gdb/infrun.c:3149
#14 0x0019bc08 in inferior_event_handler (event_type=INF_REG_EVENT, client_data=0x0) at ../../binutils-gdb/gdb/inf-loop.c:58
#15 0x00199dfc in process_event () at ../../binutils-gdb/gdb/event-loop.c:340
#16 0x0019a204 in gdb_do_one_event () at ../../binutils-gdb/gdb/event-loop.c:392
#17 0x0019a400 in start_event_loop () at ../../binutils-gdb/gdb/event-loop.c:429
#18 0x00193ed4 in captured_command_loop (data=<optimized out>) at ../../binutils-gdb/gdb/main.c:323
#19 0x00190ea4 in catch_errors (func=0x22b01d8, func@entry=0x193ebc <captured_command_loop>, 
    func_args=0x417fe8 <cleanup_chain>, func_args@entry=0x0, errstring=0x0, errstring@entry=0x387fc8 "", mask=37532008, 
    mask@entry=RETURN_MASK_ALL) at ../../binutils-gdb/gdb/exceptions.c:237
#20 0x00195168 in captured_main (data=<optimized out>) at ../../binutils-gdb/gdb/main.c:1151
#21 0x00190ea4 in catch_errors (func=0xb6f02800, func@entry=0x194404 <captured_main>, func_args=0x0, 
    func_args@entry=0xbee8e914, errstring=0xbee8e91c "", errstring@entry=0x387fc8 "", mask=4299140, mask@entry=RETURN_MASK_ALL)
    at ../../binutils-gdb/gdb/exceptions.c:237
#22 0x00195658 in gdb_main (args=args@entry=0xbee8e914) at ../../binutils-gdb/gdb/main.c:1159
#23 0x0005f220 in main (argc=<optimized out>, argv=<optimized out>) at ../../binutils-gdb/gdb/gdb.c:32

Latter it hits assert in register_size

#0  0xb6a9d354 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0xb6aa0eb4 in __GI_abort () at abort.c:89
#2  0x0025b480 in dump_core () at ../../binutils-gdb/gdb/utils.c:578
#3  0x0025d448 in internal_vproblem (problem=0xb6bac0ac <lock>, problem@entry=0x419a78 <internal_error_problem>, 
    file=file@entry=0x37358c "../../binutils-gdb/gdb/regcache.c", line=line@entry=177, fmt=fmt@entry=0x0, ap=...)
    at ../../binutils-gdb/gdb/utils.c:786
#4  0x0025d518 in internal_verror (file=file@entry=0x37358c "../../binutils-gdb/gdb/regcache.c", line=line@entry=177, 
    fmt=fmt@entry=0x0, ap=..., ap@entry=...) at ../../binutils-gdb/gdb/utils.c:812
#5  0x0028f150 in internal_error (file=file@entry=0x37358c "../../binutils-gdb/gdb/regcache.c", line=line@entry=177, 
    fmt=0x331904 "%s: Assertion `%s' failed.") at ../../binutils-gdb/gdb/common/errors.c:55
#6  0x00137558 in register_size (gdbarch=gdbarch@entry=0x24043a0, regnum=-1, regnum@entry=37804872)
    at ../../binutils-gdb/gdb/regcache.c:175
#7  0x0020d590 in read_pieced_value (v=0x6c08) at ../../binutils-gdb/gdb/dwarf2loc.c:1690
#8  0x00144d7c in value_fetch_lazy (val=0x2635e08) at ../../binutils-gdb/gdb/value.c:3895
#9  0x001453b0 in value_entirely_covered_by_range_vector (value=0x2635e08, ranges=0x2635e5c)
    at ../../binutils-gdb/gdb/value.c:392
#10 0x00156834 in value_check_printable (val=val@entry=0x2635e08, stream=stream@entry=0x24280c8, options=0xbee8e3ec)
    at ../../binutils-gdb/gdb/valprint.c:810
#11 0x00156bbc in common_val_print (val=0x2635e08, stream=0x24280c8, stream@entry=0x4f505f72, recurse=recurse@entry=2, 
    options=0xbee8e3ec, options@entry=0xbee8e3e4, language=language@entry=0x3b979c <c_language_defn>)
    at ../../binutils-gdb/gdb/valprint.c:849
#12 0x00189cbc in print_frame_arg (arg=0x2044575f) at ../../binutils-gdb/gdb/stack.c:286
#13 0x0018aa04 in print_frame_args (func=<optimized out>, frame=0x0, frame@entry=0x22f74a8, num=36664488, num@entry=-1, 
    stream=0xffffffff) at ../../binutils-gdb/gdb/stack.c:674
#14 0x0018b3f0 in print_frame (frame=frame@entry=0x22f74a8, print_level=print_level@entry=4331400, 
    print_what=print_what@entry=SRC_AND_LOC, print_args=print_args@entry=1, sal=...) at ../../binutils-gdb/gdb/stack.c:1205
#15 0x0018b8bc in print_frame_info (frame=0x22f74a8, frame@entry=0x1, print_level=print_level@entry=4331400, 
    print_what=SRC_AND_LOC, print_what@entry=36664488, print_args=print_args@entry=1, set_current_sal=set_current_sal@entry=1)
    at ../../binutils-gdb/gdb/stack.c:857
#16 0x0018baac in print_stack_frame (frame=0x1, print_level=4331400, print_level@entry=0, print_what=36664488, 
    print_what@entry=SRC_AND_LOC, set_current_sal=0, set_current_sal@entry=1) at ../../binutils-gdb/gdb/stack.c:166
#17 0x0017ffe8 in print_stop_event (ws=ws@entry=0xbee8e6b8) at ../../binutils-gdb/gdb/infrun.c:6280
#18 0x001804c8 in normal_stop () at ../../binutils-gdb/gdb/infrun.c:6426
#19 0x00186304 in fetch_inferior_event (client_data=client_data@entry=0x0) at ../../binutils-gdb/gdb/infrun.c:3149
#20 0x0019bc08 in inferior_event_handler (event_type=INF_REG_EVENT, client_data=0x0) at ../../binutils-gdb/gdb/inf-loop.c:58
#21 0x00199dfc in process_event () at ../../binutils-gdb/gdb/event-loop.c:340
#22 0x0019a204 in gdb_do_one_event () at ../../binutils-gdb/gdb/event-loop.c:392
#23 0x0019a400 in start_event_loop () at ../../binutils-gdb/gdb/event-loop.c:429
#24 0x00193ed4 in captured_command_loop (data=<optimized out>) at ../../binutils-gdb/gdb/main.c:323
#25 0x00190ea4 in catch_errors (func=0x22b01d8, func@entry=0x193ebc <captured_command_loop>, 
    func_args=0x417fe8 <cleanup_chain>, func_args@entry=0x0, errstring=0x0, errstring@entry=0x387fc8 "", mask=37532008, 
    mask@entry=RETURN_MASK_ALL) at ../../binutils-gdb/gdb/exceptions.c:237
#26 0x00195168 in captured_main (data=<optimized out>) at ../../binutils-gdb/gdb/main.c:1151
#27 0x00190ea4 in catch_errors (func=0xb6f02800, func@entry=0x194404 <captured_main>, func_args=0x0, 
    func_args@entry=0xbee8e914, errstring=0xbee8e91c "", errstring@entry=0x387fc8 "", mask=4299140, mask@entry=RETURN_MASK_ALL)
    at ../../binutils-gdb/gdb/exceptions.c:237

LE code receives gdb_regnum = -1 as well but LE code does not hit 
this because it does not have the following snippet in read_pieced_value


	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
		&& this_size < register_size (arch, gdb_regnum))
	      {
		/* Big-endian, and we want less than full size.  */
		reg_offset = register_size (arch, gdb_regnum) - this_size;
		/* We want the lower-order THIS_SIZE_BITS of the bytes
		   we extract from the register.  */
		source_offset_bits += 8 * this_size - this_size_bits;
	      }

and it proceeds with error:

(gdb) n
1699		    if (gdb_regnum != -1)
(gdb) n
1718			error (_("Unable to access DWARF register number %s"),
(gdb) bt
#0  read_pieced_value (v=0xb6c967c0 <main_arena>) at ../../binutils-gdb/gdb/dwarf2loc.c:1718
#1  0x00144a50 in value_fetch_lazy (val=0x2625020) at ../../binutils-gdb/gdb/value.c:3895
#2  0x00145084 in value_entirely_covered_by_range_vector (value=0x2625020, ranges=0x2625074) at ../../binutils-gdb/gdb/value.c:392
#3  0x00156580 in value_check_printable (val=val@entry=0x2625020, stream=stream@entry=0x2439da8, options=0xbebb85cc) at ../../binutils-gdb/gdb/valprint.c:810
#4  0x00156908 in common_val_print (val=0x2625020, stream=0x2439da8, stream@entry=0x725f504f, recurse=recurse@entry=2, options=0xbebb85cc, options@entry=0xbebb85c4, 
    language=language@entry=0x3b8f60 <c_language_defn>) at ../../binutils-gdb/gdb/valprint.c:849
#5  0x001899c8 in print_frame_arg (arg=0x5f574420) at ../../binutils-gdb/gdb/stack.c:286
#6  0x0018a710 in print_frame_args (func=<optimized out>, frame=0x0, frame@entry=0x2260438, num=36045880, num@entry=-1, stream=0xffffffff) at ../../binutils-gdb/gdb/stack.c:674
#7  0x0018b0fc in print_frame (frame=frame@entry=0x2260438, print_level=print_level@entry=4331144, print_what=print_what@entry=SRC_AND_LOC, print_args=print_args@entry=1, sal=...)
    at ../../binutils-gdb/gdb/stack.c:1205
#8  0x0018b5c8 in print_frame_info (frame=0x2260438, frame@entry=0x1, print_level=print_level@entry=4331144, print_what=SRC_AND_LOC, print_what@entry=36045880, print_args=print_args@entry=1, 
    set_current_sal=set_current_sal@entry=1) at ../../binutils-gdb/gdb/stack.c:857
#9  0x0018b7b8 in print_stack_frame (frame=0x1, print_level=4331144, print_level@entry=0, print_what=36045880, print_what@entry=SRC_AND_LOC, set_current_sal=0, set_current_sal@entry=1)
    at ../../binutils-gdb/gdb/stack.c:166
#10 0x0017fd00 in print_stop_event (ws=ws@entry=0xbebb8898) at ../../binutils-gdb/gdb/infrun.c:6280
#11 0x001801e0 in normal_stop () at ../../binutils-gdb/gdb/infrun.c:6426
#12 0x00186010 in fetch_inferior_event (client_data=client_data@entry=0x0) at ../../binutils-gdb/gdb/infrun.c:3149
#13 0x0019b8fc in inferior_event_handler (event_type=INF_REG_EVENT, client_data=0x0) at ../../binutils-gdb/gdb/inf-loop.c:58
#14 0x00199af0 in process_event () at ../../binutils-gdb/gdb/event-loop.c:340
#15 0x00199ef8 in gdb_do_one_event () at ../../binutils-gdb/gdb/event-loop.c:392
#16 0x0019a0f4 in start_event_loop () at ../../binutils-gdb/gdb/event-loop.c:429
#17 0x00193bcc in captured_command_loop (data=<optimized out>) at ../../binutils-gdb/gdb/main.c:323
#18 0x00190bac in catch_errors (func=0x22191d8, func@entry=0x193bb4 <captured_command_loop>, func_args=0x417ee8 <cleanup_chain>, func_args@entry=0x0, errstring=0x0, 
    errstring@entry=0x3877e0 "", mask=37746520, mask@entry=RETURN_MASK_ALL) at ../../binutils-gdb/gdb/exceptions.c:237
#19 0x00194e60 in captured_main (data=<optimized out>) at ../../binutils-gdb/gdb/main.c:1151
#20 0x00190bac in catch_errors (func=0xb6fec2a0, func@entry=0x1940fc <captured_main>, func_args=0x0, func_args@entry=0xbebb8af4, errstring=0xbebb8afc "\005", errstring@entry=0x3877e0 "", 
    mask=4298884, mask@entry=RETURN_MASK_ALL) at ../../binutils-gdb/gdb/exceptions.c:237
#21 0x00195350 in gdb_main (args=args@entry=0xbebb8af4) at ../../binutils-gdb/gdb/main.c:1159
#22 0x0005f218 in main (argc=<optimized out>, argv=<optimized out>) at ../../binutils-gdb/gdb/gdb.c:32
Yao Qi Oct. 23, 2014, 3:18 a.m. | #3
Victor Kamensky <victor.kamensky@linaro.org> writes:

> In both little endian and big endian cases compiler generate DW_OP_reg29-
> DW_OP_reg31 something like this.
>
>  <2><792>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>     <793>   DW_AT_name        : u
>     <795>   DW_AT_decl_file   : 1
>     <796>   DW_AT_decl_line   : 115
>     <797>   DW_AT_type        : <0x57c>
>     <79b>   DW_AT_location    : 6 byte block: 6d 93 4 6c 93 4
> (DW_OP_reg29 (r29); DW_OP_piece: 4; DW_OP_reg28 (r28); DW_OP_piece: 4)
>

This is quite illustrative.

> I strongly suspect that it is compiler error, but more accurately
> it is hard to say, because I never saw a document where for given CPU
> mapping from registers to DWARF reg numbers is defined. Have you
> seen such document for example for ARM V7? In any case for this
> test case Gdb believes that those register numbers are wrong. I.e we
> can say for sure that gcc and gdb are disagrees.

You need doc "DWARF for the ARM Architecture", which has a table about
the mapping between dwarf reg numbers and processor registers. For the
table, we can see that dwarf register 16 to 63 doesn't map to any
processor registers.

>
>
> (gdb) file /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store
> Reading symbols from /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store...done.
> (gdb) tbreak wack_double
> Temporary breakpoint 1 at 0x1076c: file ../../../binutils-gdb/gdb/testsuite/gdb.base/store.c, line 117.
> (gdb) run
> Starting program: /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store 
>
> Temporary breakpoint 1, wack_double (u=
> ../../binutils-gdb/gdb/regcache.c:177: internal-error: register_size: Assertion `regnum >= 0 && regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))' failed.
> A problem internal to GDB has been detected,
> further debugging may prove unreliable.
>

This is quite useful too.

>
> BE Dump
> =======
>
>
>  <1><779>: Abbrev Number: 12 (DW_TAG_subprogram)
>     <77a>   DW_AT_external    : 1       
>     <77a>   DW_AT_name        : (indirect string, offset: 0x3c9): wack_double   
>     <77e>   DW_AT_decl_file   : 1       
>     <77f>   DW_AT_decl_line   : 115     
>     <780>   DW_AT_prototyped  : 1       
>     <780>   DW_AT_type        : <0x57c> 
>     <784>   DW_AT_low_pc      : 0x10758 
>     <788>   DW_AT_high_pc     : 0x40    
>     <78c>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
>     <78e>   DW_AT_GNU_all_tail_call_sites: 1    
>     <78e>   DW_AT_sibling     : <0x7d7> 
>  <2><792>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>     <793>   DW_AT_name        : u       
>     <795>   DW_AT_decl_file   : 1       
>     <796>   DW_AT_decl_line   : 115     
>     <797>   DW_AT_type        : <0x57c> 
>     <79b>   DW_AT_location    : 6 byte block: 6d 93 4 6c 93 4   (DW_OP_reg29 (r29); DW_OP_piece: 4; DW_OP_reg28 (r28); DW_OP_piece: 4)
>  <2><7a2>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>     <7a3>   DW_AT_name        : v       
>     <7a5>   DW_AT_decl_file   : 1       
>     <7a6>   DW_AT_decl_line   : 115     
>     <7a7>   DW_AT_type        : <0x57c> 
>     <7ab>   DW_AT_location    : 6 byte block: 6f 93 4 6e 93 4   (DW_OP_reg31 (r31); DW_OP_piece: 4; DW_OP_reg30 (r30); DW_OP_piece: 4)
>  <2><7b2>: Abbrev Number: 13 (DW_TAG_variable)
>     <7b3>   DW_AT_name        : l       
>     <7b5>   DW_AT_decl_file   : 1       
>     <7b6>   DW_AT_decl_line   : 117     
>     <7b7>   DW_AT_type        : <0x57c> 
>     <7bb>   DW_AT_location    : 8 byte block: 90 21 93 4 90 20 93 4     (DW_OP_regx: 33 (r33); DW_OP_piece: 4; DW_OP_regx: 32 (r32); DW_OP_piece: 4)
>  <2><7c4>: Abbrev Number: 13 (DW_TAG_variable)
>     <7c5>   DW_AT_name        : r       
>     <7c7>   DW_AT_decl_file   : 1       
>     <7c8>   DW_AT_decl_line   : 117     
>     <7c9>   DW_AT_type        : <0x57c> 
>     <7cd>   DW_AT_location    : 8 byte block: 90 23 93 4 90 22 93 4     (DW_OP_regx: 35 (r35); DW_OP_piece: 4; DW_OP_regx: 34 (r34); DW_OP_piece: 4)
>

However, we don't need to copy the whole DIE here, instead, we can only
copy one DW_TAG_formal_parameter, which is should be illustrative enough
for the problem.

> Backtrace when it failed to get reg number
> ==========================================

We don't need to copy the full stack back trace here.
vkamensky Oct. 23, 2014, 5:43 a.m. | #4
Hi Yao,

I've posted updated V3 version only for this patch. I've modified
commit message to include more details as you suggested.
And I moved reg_offset var to more specific blocks as you noted.
Please take a look.

Would you like me to repost the whole series again (all 4
patches) or it would be OK just like this?

Also it came up on binutils@ patch discussion with Alan -
I do not have git commit permission. Is it my correct
expectation once folks are OK with the patches, you or
some other gdb maintainer will commit those?

Thanks,
Victor


On 22 October 2014 20:18, Yao Qi <yao@codesourcery.com> wrote:
> Victor Kamensky <victor.kamensky@linaro.org> writes:
>
>> In both little endian and big endian cases compiler generate DW_OP_reg29-
>> DW_OP_reg31 something like this.
>>
>>  <2><792>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>>     <793>   DW_AT_name        : u
>>     <795>   DW_AT_decl_file   : 1
>>     <796>   DW_AT_decl_line   : 115
>>     <797>   DW_AT_type        : <0x57c>
>>     <79b>   DW_AT_location    : 6 byte block: 6d 93 4 6c 93 4
>> (DW_OP_reg29 (r29); DW_OP_piece: 4; DW_OP_reg28 (r28); DW_OP_piece: 4)
>>
>
> This is quite illustrative.
>
>> I strongly suspect that it is compiler error, but more accurately
>> it is hard to say, because I never saw a document where for given CPU
>> mapping from registers to DWARF reg numbers is defined. Have you
>> seen such document for example for ARM V7? In any case for this
>> test case Gdb believes that those register numbers are wrong. I.e we
>> can say for sure that gcc and gdb are disagrees.
>
> You need doc "DWARF for the ARM Architecture", which has a table about
> the mapping between dwarf reg numbers and processor registers. For the
> table, we can see that dwarf register 16 to 63 doesn't map to any
> processor registers.
>
>>
>>
>> (gdb) file /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store
>> Reading symbols from /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store...done.
>> (gdb) tbreak wack_double
>> Temporary breakpoint 1 at 0x1076c: file ../../../binutils-gdb/gdb/testsuite/gdb.base/store.c, line 117.
>> (gdb) run
>> Starting program: /wd1/gdb/20140930/build-v7le/gdb/testsuite/gdb.base/store
>>
>> Temporary breakpoint 1, wack_double (u=
>> ../../binutils-gdb/gdb/regcache.c:177: internal-error: register_size: Assertion `regnum >= 0 && regnum < (gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch))' failed.
>> A problem internal to GDB has been detected,
>> further debugging may prove unreliable.
>>
>
> This is quite useful too.
>
>>
>> BE Dump
>> =======
>>
>>
>>  <1><779>: Abbrev Number: 12 (DW_TAG_subprogram)
>>     <77a>   DW_AT_external    : 1
>>     <77a>   DW_AT_name        : (indirect string, offset: 0x3c9): wack_double
>>     <77e>   DW_AT_decl_file   : 1
>>     <77f>   DW_AT_decl_line   : 115
>>     <780>   DW_AT_prototyped  : 1
>>     <780>   DW_AT_type        : <0x57c>
>>     <784>   DW_AT_low_pc      : 0x10758
>>     <788>   DW_AT_high_pc     : 0x40
>>     <78c>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
>>     <78e>   DW_AT_GNU_all_tail_call_sites: 1
>>     <78e>   DW_AT_sibling     : <0x7d7>
>>  <2><792>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>>     <793>   DW_AT_name        : u
>>     <795>   DW_AT_decl_file   : 1
>>     <796>   DW_AT_decl_line   : 115
>>     <797>   DW_AT_type        : <0x57c>
>>     <79b>   DW_AT_location    : 6 byte block: 6d 93 4 6c 93 4   (DW_OP_reg29 (r29); DW_OP_piece: 4; DW_OP_reg28 (r28); DW_OP_piece: 4)
>>  <2><7a2>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>>     <7a3>   DW_AT_name        : v
>>     <7a5>   DW_AT_decl_file   : 1
>>     <7a6>   DW_AT_decl_line   : 115
>>     <7a7>   DW_AT_type        : <0x57c>
>>     <7ab>   DW_AT_location    : 6 byte block: 6f 93 4 6e 93 4   (DW_OP_reg31 (r31); DW_OP_piece: 4; DW_OP_reg30 (r30); DW_OP_piece: 4)
>>  <2><7b2>: Abbrev Number: 13 (DW_TAG_variable)
>>     <7b3>   DW_AT_name        : l
>>     <7b5>   DW_AT_decl_file   : 1
>>     <7b6>   DW_AT_decl_line   : 117
>>     <7b7>   DW_AT_type        : <0x57c>
>>     <7bb>   DW_AT_location    : 8 byte block: 90 21 93 4 90 20 93 4     (DW_OP_regx: 33 (r33); DW_OP_piece: 4; DW_OP_regx: 32 (r32); DW_OP_piece: 4)
>>  <2><7c4>: Abbrev Number: 13 (DW_TAG_variable)
>>     <7c5>   DW_AT_name        : r
>>     <7c7>   DW_AT_decl_file   : 1
>>     <7c8>   DW_AT_decl_line   : 117
>>     <7c9>   DW_AT_type        : <0x57c>
>>     <7cd>   DW_AT_location    : 8 byte block: 90 23 93 4 90 22 93 4     (DW_OP_regx: 35 (r35); DW_OP_piece: 4; DW_OP_regx: 34 (r34); DW_OP_piece: 4)
>>
>
> However, we don't need to copy the whole DIE here, instead, we can only
> copy one DW_TAG_formal_parameter, which is should be illustrative enough
> for the problem.
>
>> Backtrace when it failed to get reg number
>> ==========================================
>
> We don't need to copy the full stack back trace here.
>
> --
> Yao (齐尧)
Yao Qi Oct. 23, 2014, 6:20 a.m. | #5
Victor Kamensky <victor.kamensky@linaro.org> writes:

> I've posted updated V3 version only for this patch. I've modified
> commit message to include more details as you suggested.
> And I moved reg_offset var to more specific blocks as you noted.
> Please take a look.

Thanks, I'll take a look.

> Would you like me to repost the whole series again (all 4
> patches) or it would be OK just like this?

Well, we have two options usually, supposing you post a patch series,

 - if you only update one or two patches after review, you can
   just reply to reviewer's mail and post the updated patches in the same
   mail thread as your original post.  It'll be convenient to search in
   archive, because all of them are in the same thread.

 - if you update all the patches, for example, change the design, better
   to post the updated series, like what you did for V2.

In this case, you don't have to post them again.
>
> Also it came up on binutils@ patch discussion with Alan -
> I do not have git commit permission. Is it my correct
> expectation once folks are OK with the patches, you or
> some other gdb maintainer will commit those?

It is better for you to create your own account, and commit your patches
after approval in the future.

Please fill in the form here https://sourceware.org/cgi-bin/pdw/ps_form.cgi
I think I can approve your request, so please fill in my mail address in
box "email address of person who approved request".

Once your account is ready, you can commit approved patches first.  I am
still thinking about patch 4/4, it may take some time.

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c32fb3f..6a735b8 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@ 
 2014-10-13  Victor Kamensky  <victor.kamensky@linaro.org>
 
+	* dwarf2loc.c (read_pieced_value): do BE processing only if
+	gdb_regnum is not -1.
+	(write_pieced_value): Ditto.
+
+2014-10-13  Victor Kamensky  <victor.kamensky@linaro.org>
+
 	* arm-tdep.c: (extract_arm_insn): use dbarch_byte_order_for_code
 	to read arm instruction.
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index e347e59..fbe99bb 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -1686,20 +1686,20 @@  read_pieced_value (struct value *v)
 	    int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno);
 	    int reg_offset = source_offset;
 
-	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
-		&& this_size < register_size (arch, gdb_regnum))
-	      {
-		/* Big-endian, and we want less than full size.  */
-		reg_offset = register_size (arch, gdb_regnum) - this_size;
-		/* We want the lower-order THIS_SIZE_BITS of the bytes
-		   we extract from the register.  */
-		source_offset_bits += 8 * this_size - this_size_bits;
-	      }
-
 	    if (gdb_regnum != -1)
 	      {
 		int optim, unavail;
 
+		if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
+		    && this_size < register_size (arch, gdb_regnum))
+		  {
+		    /* Big-endian, and we want less than full size.  */
+		    reg_offset = register_size (arch, gdb_regnum) - this_size;
+		    /* We want the lower-order THIS_SIZE_BITS of the bytes
+		       we extract from the register.  */
+		    source_offset_bits += 8 * this_size - this_size_bits;
+		 }
+
 		if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
 					       this_size, buffer,
 					       &optim, &unavail))
@@ -1878,13 +1878,13 @@  write_pieced_value (struct value *to, struct value *from)
 	    int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno);
 	    int reg_offset = dest_offset;
 
-	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
-		&& this_size <= register_size (arch, gdb_regnum))
-	      /* Big-endian, and we want less than full size.  */
-	      reg_offset = register_size (arch, gdb_regnum) - this_size;
-
 	    if (gdb_regnum != -1)
 	      {
+		if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
+		    && this_size <= register_size (arch, gdb_regnum))
+		  /* Big-endian, and we want less than full size.  */
+		  reg_offset = register_size (arch, gdb_regnum) - this_size;
+
 		if (need_bitwise)
 		  {
 		    int optim, unavail;