public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* dwarf_block_to_fb_offset() and 64-bit host
@ 2015-01-25  8:03 Jonathan Larmour
  2015-01-25  8:27 ` Doug Evans
  2015-01-25  8:32 ` Jan Kratochvil
  0 siblings, 2 replies; 6+ messages in thread
From: Jonathan Larmour @ 2015-01-25  8:03 UTC (permalink / raw)
  To: gdb

Hi folks,

I've been looking at a problem on a remote Cortex-M target, which notably
happens to have a somewhat atypical property of using an address space of
0x9xxxxxxx - in other words, addresses will have the top bit set.

When debugging, there is a problem with a GDB built for a 64-bit host,
versus one built for 32-bit, all from exactly the same source base. It
manifests with this sort of issue with a 64-bit hosted GDB:

Breakpoint 2, fileio1_main (id=0, id@entry=<error reading variable: Cannot
access memory at address 0x9001917c>)
    at /.../fatfs1.c:431

The cited address is perfectly valid and readable. Whereas on a 32-bit GDB:
Breakpoint 2, fileio1_main (id=0) at /.../fatfs1.c:431

I have tracked down where the 32-bit and 64-bit builds of GDB diverge in
behaviour and it's in dwarf2expr.c's dwarf_block_to_fb_offset():

int
dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
                          CORE_ADDR *fb_offset_return)
{
  int64_t fb_offset;
[snip]
  buf++;

  buf = gdb_read_sleb128 (buf, buf_end, &fb_offset);
  if (buf == NULL)
    return 0;
  *fb_offset_return = fb_offset;
  if (buf != buf_end || fb_offset != (LONGEST) *fb_offset_return)
    return 0;

  return 1;
}

In the 32-bit (working) build, in one failing example, fb_offset ends up
as -28, whereas *fb_offset_return is 0xffffffe4 - this is because
CORE_ADDR is an *unsigned* 32-bit type (due to bfd_vma). But LONGEST is a
signed long long - 64-bits - so the comparison between fb_offset and
*fb_offset_return ends up comparing -28 and 4294967268. So 0 is returned.

In the 64-bit (buggy) build, fb_offset is still -28 but *fb_offset_return
is 0xffffffffffffffe4 (CORE_ADDR now being an unsigned 64-bit type), which
when cast to LONGEST (which is signed) is still -28. Therefore 1 is
returned. This later results in read_frame_arg()'s call to
ops->read_variable_at_entry incorrectly believing there is a different
value of the variable on entry.

I'm unsure about where the bug really lies. I'm not familiar enough with
Dwarf, but I have to wonder why there's the test for "fb_offset !=
(LONGEST) *fb_offset_return" in the first place.

Any help/advice from anyone with Dwarf experience would be welcome, thanks.

Jifl
-- 
------["Si fractum non sit, noli id reficere"]------       Opinions==mine

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: dwarf_block_to_fb_offset() and 64-bit host
  2015-01-25  8:03 dwarf_block_to_fb_offset() and 64-bit host Jonathan Larmour
@ 2015-01-25  8:27 ` Doug Evans
  2015-01-25 12:41   ` Jan Kratochvil
  2015-01-25  8:32 ` Jan Kratochvil
  1 sibling, 1 reply; 6+ messages in thread
From: Doug Evans @ 2015-01-25  8:27 UTC (permalink / raw)
  To: Jonathan Larmour; +Cc: gdb

Jonathan Larmour <jifl@eCosCentric.com> writes:
> Hi folks,
>
> I've been looking at a problem on a remote Cortex-M target, which notably
> happens to have a somewhat atypical property of using an address space of
> 0x9xxxxxxx - in other words, addresses will have the top bit set.
>
> When debugging, there is a problem with a GDB built for a 64-bit host,
> versus one built for 32-bit, all from exactly the same source base. It
> manifests with this sort of issue with a 64-bit hosted GDB:
>
> Breakpoint 2, fileio1_main (id=0, id@entry=<error reading variable: Cannot
> access memory at address 0x9001917c>)
>     at /.../fatfs1.c:431
>
> The cited address is perfectly valid and readable. Whereas on a 32-bit GDB:
> Breakpoint 2, fileio1_main (id=0) at /.../fatfs1.c:431
>
> I have tracked down where the 32-bit and 64-bit builds of GDB diverge in
> behaviour and it's in dwarf2expr.c's dwarf_block_to_fb_offset():
>
> int
> dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
>                           CORE_ADDR *fb_offset_return)
> {
>   int64_t fb_offset;
> [snip]
>   buf++;
>
>   buf = gdb_read_sleb128 (buf, buf_end, &fb_offset);
>   if (buf == NULL)
>     return 0;
>   *fb_offset_return = fb_offset;
>   if (buf != buf_end || fb_offset != (LONGEST) *fb_offset_return)
>     return 0;
>
>   return 1;
> }
>
> In the 32-bit (working) build, in one failing example, fb_offset ends up
> as -28, whereas *fb_offset_return is 0xffffffe4 - this is because
> CORE_ADDR is an *unsigned* 32-bit type (due to bfd_vma). But LONGEST is a
> signed long long - 64-bits - so the comparison between fb_offset and
> *fb_offset_return ends up comparing -28 and 4294967268. So 0 is returned.
>
> In the 64-bit (buggy) build, fb_offset is still -28 but *fb_offset_return
> is 0xffffffffffffffe4 (CORE_ADDR now being an unsigned 64-bit type), which
> when cast to LONGEST (which is signed) is still -28. Therefore 1 is
> returned. This later results in read_frame_arg()'s call to
> ops->read_variable_at_entry incorrectly believing there is a different
> value of the variable on entry.
>
> I'm unsure about where the bug really lies. I'm not familiar enough with
> Dwarf, but I have to wonder why there's the test for "fb_offset !=
> (LONGEST) *fb_offset_return" in the first place.
>
> Any help/advice from anyone with Dwarf experience would be welcome, thanks.

Hi.
It would not be unexpected if there are multiple bugs here.

E.g., if the cited address is valid, why is there an error reading it?
[and if gdb could successfully read it would it have noticed that
the two values are the same and thus you'd get the same output as
in the 32-bit case]

Here's where fb_offset originates from:

gdbtypes.h:

	union call_site_parameter_u
	  {
	    /* * DW_TAG_formal_parameter's DW_AT_location's DW_OP_regX
	       as DWARF register number, for register passed
	       parameters.  */

	    int dwarf_reg;

	    /* * Offset from the callee's frame base, for stack passed
	       parameters.  This equals offset from the caller's stack
	       pointer.  */

	    CORE_ADDR fb_offset;

	    /* * Offset relative to the start of this PER_CU to
	       DW_TAG_formal_parameter which is referenced by both
	       caller and the callee.  */

	    cu_offset param_offset;
	  }
	u;

I guess the first question is: Is an fb_offset of -28 valid?
i.e., is a negative value valid?
[Certainly a negative value is valid for DW_OP_fbreg.
But is it valid in this context?  Dunno off hand.]

Also, I can imagine that the "fb_offset != (LONGEST) *fb_offset_return"
test is to verify there's no loss in precision in the saved value.
So while dwarf_block_to_fb_offset is returning 1 in the "buggy"
case it seems to me that that could be the correct result.
[Hence wondering if there's another bug.]

I'm curious what would happen if you changed
"CORE_ADDR fb_offset" to "LONGEST fb_offset"
and updated all the affected pieces,
including changing the signature of dwarf_block_to_fb_offset to

int
dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
			  LONGEST *fb_offset_return)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: dwarf_block_to_fb_offset() and 64-bit host
  2015-01-25  8:03 dwarf_block_to_fb_offset() and 64-bit host Jonathan Larmour
  2015-01-25  8:27 ` Doug Evans
@ 2015-01-25  8:32 ` Jan Kratochvil
  2015-02-03  3:24   ` Jonathan Larmour
  1 sibling, 1 reply; 6+ messages in thread
From: Jan Kratochvil @ 2015-01-25  8:32 UTC (permalink / raw)
  To: Jonathan Larmour; +Cc: gdb

On Sun, 25 Jan 2015 06:52:08 +0100, Jonathan Larmour wrote:
> In the 32-bit (working) build, in one failing example, fb_offset ends up
> as -28, whereas *fb_offset_return is 0xffffffe4 - this is because
> CORE_ADDR is an *unsigned* 32-bit type (due to bfd_vma). But LONGEST is a
> signed long long - 64-bits - so the comparison between fb_offset and
> *fb_offset_return ends up comparing -28 and 4294967268. So 0 is returned.

It is not really working.  It is just a secondary bug which will omit the
'id@entry' value to be read/displayed.  The primary bug is that reading the
value 'id@entry' errors.


> In the 64-bit (buggy) build, fb_offset is still -28 but *fb_offset_return
> is 0xffffffffffffffe4 (CORE_ADDR now being an unsigned 64-bit type), which
> when cast to LONGEST (which is signed) is still -28. Therefore 1 is
> returned. This later results in read_frame_arg()'s call to
> ops->read_variable_at_entry incorrectly believing there is a different
> value of the variable on entry.

To find out whether there is or isn't a different value one has to read it
first.  Which for an unknown reason fails in your case.

If the id entry value was equal GDB would print:
	Breakpoint 2, fileio1_main (id=id@entry=0) at /.../fatfs1.c:431
which happens in neither of your case.

The primary problem is why GDB fails to read the address 0x9001917c.
It usually happens that GDB tries to read address like 0x19001917c or address
0xffffffff9001917c while then the error report
	return xstrprintf (_("Cannot access memory at address %s"),
			   paddress (gdbarch, memaddr));
strips the upper bits in paddress().

corefile.c:memory_error_message():
	s/paddress (gdbarch, memaddr)/core_addr_to_string (memaddr)/
may reveal that.



Jan

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: dwarf_block_to_fb_offset() and 64-bit host
  2015-01-25  8:27 ` Doug Evans
@ 2015-01-25 12:41   ` Jan Kratochvil
  2015-01-26  8:48     ` Mark Kettenis
  0 siblings, 1 reply; 6+ messages in thread
From: Jan Kratochvil @ 2015-01-25 12:41 UTC (permalink / raw)
  To: Doug Evans; +Cc: Jonathan Larmour, gdb

On Sun, 25 Jan 2015 08:58:13 +0100, Doug Evans wrote:
> I guess the first question is: Is an fb_offset of -28 valid?
> i.e., is a negative value valid?

It should not be for decreasing-sp archs (like x86*):

gdb.arch/amd64-entry-value:
 <3><a90>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
    <a91>   DW_AT_location    : 2 byte block: 77 0      (DW_OP_breg7 (rsp): 0)
                                                                            ^
    <a94>   DW_AT_GNU_call_site_value: 1 byte block: 3b         (DW_OP_lit11)
 <3><a96>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
    <a97>   DW_AT_location    : 2 byte block: 77 8      (DW_OP_breg7 (rsp): 8)
                                                                            ^
    <a9a>   DW_AT_GNU_call_site_value: 1 byte block: 3c         (DW_OP_lit12)
 <3><a9c>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
    <a9d>   DW_AT_location    : 2 byte block: 77 10     (DW_OP_breg7 (rsp): 16)
                                                                            ^^
    <aa0>   DW_AT_GNU_call_site_value: 11 byte block: f4 31 8 0 0 0 0 0 0 27 40         (DW_OP_GNU_const_type: <0x31>  8 byte block: 0 0 0 0 0 0 27 40 )
 <3><aac>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
    <aad>   DW_AT_location    : 2 byte block: 77 18     (DW_OP_breg7 (rsp): 24)
                                                                            ^^
    <ab0>   DW_AT_GNU_call_site_value: 11 byte block: f4 31 8 0 0 0 0 0 0 29 40         (DW_OP_GNU_const_type: <0x31>  8 byte block: 0 0 0 0 0 0 29 40 )

Despite its 'fb_offset' name it is an offset from SP so parameters should not
be stored in the to-be-rewritten area under SP.



Jan

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: dwarf_block_to_fb_offset() and 64-bit host
  2015-01-25 12:41   ` Jan Kratochvil
@ 2015-01-26  8:48     ` Mark Kettenis
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Kettenis @ 2015-01-26  8:48 UTC (permalink / raw)
  To: jan.kratochvil; +Cc: xdje42, jifl, gdb

> Date: Sun, 25 Jan 2015 09:32:41 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> 
> On Sun, 25 Jan 2015 08:58:13 +0100, Doug Evans wrote:
> > I guess the first question is: Is an fb_offset of -28 valid?
> > i.e., is a negative value valid?
> 
> It should not be for decreasing-sp archs (like x86*):
> 
> gdb.arch/amd64-entry-value:
>  <3><a90>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
>     <a91>   DW_AT_location    : 2 byte block: 77 0      (DW_OP_breg7 (rsp): 0)
>                                                                             ^
>     <a94>   DW_AT_GNU_call_site_value: 1 byte block: 3b         (DW_OP_lit11)
>  <3><a96>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
>     <a97>   DW_AT_location    : 2 byte block: 77 8      (DW_OP_breg7 (rsp): 8)
>                                                                             ^
>     <a9a>   DW_AT_GNU_call_site_value: 1 byte block: 3c         (DW_OP_lit12)
>  <3><a9c>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
>     <a9d>   DW_AT_location    : 2 byte block: 77 10     (DW_OP_breg7 (rsp): 16)
>                                                                             ^^
>     <aa0>   DW_AT_GNU_call_site_value: 11 byte block: f4 31 8 0 0 0 0 0 0 27 40         (DW_OP_GNU_const_type: <0x31>  8 byte block: 0 0 0 0 0 0 27 40 )
>  <3><aac>: Abbrev Number: 8 (DW_TAG_GNU_call_site_parameter)
>     <aad>   DW_AT_location    : 2 byte block: 77 18     (DW_OP_breg7 (rsp): 24)
>                                                                             ^^
>     <ab0>   DW_AT_GNU_call_site_value: 11 byte block: f4 31 8 0 0 0 0 0 0 29 40         (DW_OP_GNU_const_type: <0x31>  8 byte block: 0 0 0 0 0 0 29 40 )
> 
> Despite its 'fb_offset' name it is an offset from SP so parameters should not
> be stored in the to-be-rewritten area under SP.

Well, some architectures (including amd64) reserve an area "beyond"
the stack pointer that can be used for temporary data (the "red zone"
on amd64).  Now the amd64 "red zone" might not be used for storing
entry values, but for leaf frames it could.  So I'd fb_offset should
be LONGEST instead of CORE_ADDR.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: dwarf_block_to_fb_offset() and 64-bit host
  2015-01-25  8:32 ` Jan Kratochvil
@ 2015-02-03  3:24   ` Jonathan Larmour
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Larmour @ 2015-02-03  3:24 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb

Thanks for all the replies, sorry for the delay in getting back but I
haven't been able to work full time on this...

On 25/01/15 08:27, Jan Kratochvil wrote:
> On Sun, 25 Jan 2015 06:52:08 +0100, Jonathan Larmour wrote:
>> In the 32-bit (working) build, in one failing example, fb_offset ends up
>> as -28, whereas *fb_offset_return is 0xffffffe4 - this is because
>> CORE_ADDR is an *unsigned* 32-bit type (due to bfd_vma). But LONGEST is a
>> signed long long - 64-bits - so the comparison between fb_offset and
>> *fb_offset_return ends up comparing -28 and 4294967268. So 0 is returned.
> 
> It is not really working.  It is just a secondary bug which will omit the
> 'id@entry' value to be read/displayed.  The primary bug is that reading the
> value 'id@entry' errors.

After investigation, the reason the read of id@entry failed was because
the remote target has provided a memory region map, and the requested
stack address to read was 0xffffffff90019160, instead of 0x90019160,
therefore lying outside of the permitted memory map, so GDB never even
attempted to read from the target. The read of the value came from a call
to dwarf2_frame_cache() which calls dwarf2-frame.c:read_reg() which uses
unpack_long() which returns a LONGEST which, despite being converted to
CORE_ADDR on return, has been sign extended.

BUT...

what I intended to say in my previous mail but accidentally missed was
that this is from GDB 7.6.2. I see that the code in 7.8.2 has changed
substantially, now using read_addr_from_reg() which behaves more
appropriately for addresses.

Indeed, now I've switched to 7.8.2 everything _appears_ to outwardly work
okay. However, it now works in the same way that the 32-bit version works,
and from the comments in this thread, could there still be a lurking but
hidden problem here, because there is still a negative fb_offset of -28?
I've tried a variety of different functions and programs, on different ARM
targets, and every time fb_offset is negative when reading the frame args.
So I have to query whether a negative fb_offset really is a problem.

Just in case I was missing something, I thought I would follow Doug Evans'
suggestion of changing fb_offset_return to use LONGEST, but not very
surprisingly that didn't help the negative fb_offset (Doug's suggestion
really being about the discrepancy between 32- and 64-bit host behaviour).

Jifl
-- 

Besuchen Sie uns vom 24-26 Feb auf der Embedded World 2015, Stand 4-161
Visit us at Embedded World 2015, Nürnberg-Germany, Stand 4-161, 24-26 Feb

eCosCentric Limited      http://www.eCosCentric.com/     The eCos experts
Barnwell House, Barnwell Drive, Cambridge, UK.       Tel: +44 1223 245571
Registered in England and Wales: Reg No 4422071.
------["Si fractum non sit, noli id reficere"]------       Opinions==mine

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-02-03  3:24 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-25  8:03 dwarf_block_to_fb_offset() and 64-bit host Jonathan Larmour
2015-01-25  8:27 ` Doug Evans
2015-01-25 12:41   ` Jan Kratochvil
2015-01-26  8:48     ` Mark Kettenis
2015-01-25  8:32 ` Jan Kratochvil
2015-02-03  3:24   ` Jonathan Larmour

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).