This is the mail archive of the mailing list for the GDB project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA/RFC] Restore old handling of multi-register variables

I came across a situation on AVR where pretty much none of the
local variable could be printed. Consider for instance the following

    procedure Foo is
       My_Variable : Integer := 16#12cd#;
       Do_Nothing (My_Variable'Address);
    end Foo;

After having run the program up until the call to `Do_Nothing',
the debugger is unable to print the value of the variable:

    (gdb) p my_variable
    $1 = 0

The problem is that the address of my_variable is improperly computed.
The debug info says:

        .uleb128 0x4     ;  (DIE (0x48) DW_TAG_variable)
        .long   .LASF5   ;  DW_AT_name: "my_variable"
        .long   0x57     ;  DW_AT_type
        .byte   0x2      ;  DW_AT_location
        .byte   0x8c     ;  DW_OP_breg28
        .sleb128 1

This says that the address of my_variable is to be computed
by adding 1 to the value of register r28.  But this is not
actually correct. Registers on AVR are 1-byte long, whereas
addresses are 2-byte long.  In reality, we should be reading
an address spanning over r28 and r29, and then add 1.

Although the debugging information is at fault in this case,
this used to work.  I also think that we might be hitting
the same problem on platforms that are still using stabs.
It's just very visible on the AVR because registers on this
microcontroller are only 1 byte long (whereas addresses are
2 bytes long).

I've opened a ticket internally for looking at the debugging
info generated by the compiler.  But in the meantime, I propose
to restore the old way of handling multi-register entities:
When trying to fetch the value of an entity from a register, and
the size of that entity is larger than the register value, assume
that the value is to be fetched by reading multiple consecutive

Not ideal, but I see a better way to preserve support for all
these imprecise compilers out there...


        * findvar.c (value_from_register): Handle the case where
        the size of the entity to be read is larger than the size
        of the register where the entity is supposed to be read from.

Tested on x86_64-linux. No regression.


 gdb/findvar.c |   30 ++++++++++++++++++++++++++++--
 1 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/gdb/findvar.c b/gdb/findvar.c
index 8e986f1..c7e4c63 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -668,9 +668,35 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
       v = gdbarch_value_from_register (gdbarch, type, regnum, frame);
       /* Get the data.  */
-      v2 = get_frame_register_value (frame, regnum);
+      if (len > register_size (gdbarch, regnum))
+	{
+	  /* This is probably a situation where the data is stored over
+	     multiple registers.  We normally expect the debugging info
+	     to describe this multi-register layout explicitly, but this
+	     is not always the case - either because the debugging info
+	     format does not support that level of detail (stabs) or
+	     because the compiler is generating incorrect debugging info.
+	     Try to be as helpful as possible, by assuming that the data
+	     is stored over consecutive registers.  */
+	  int optim, unavail, ok;
+	  ok = get_frame_register_bytes (frame, regnum, value_offset (v),
+					 len, value_contents_raw (v),
+					 &optim, &unavail);
+	  if (!ok)
+	    {
+	      if (optim)
+		set_value_optimized_out (v, 1);
+	      if (unavail)
+		mark_value_bytes_unavailable (v, 0, TYPE_LENGTH (type));
+	    }
+	}
+      else
+	{
+	  v2 = get_frame_register_value (frame, regnum);
-      value_contents_copy (v, 0, v2, value_offset (v), len);
+	  value_contents_copy (v, 0, v2, value_offset (v), len);
+	}
   return v;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]