Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Simon Marchi <simon.marchi@ericsson.com>
To: Yao Qi <qiyaoltc@gmail.com>, Simon Marchi <simon.marchi@polymtl.ca>
Cc: <gdb-patches@sourceware.org>
Subject: Re: [PATCH] Make arm_record_test work on big-endian machines
Date: Mon, 12 Mar 2018 15:42:00 -0000	[thread overview]
Message-ID: <fb6d077c-d731-03b9-c9cd-b03a8f1ab161@ericsson.com> (raw)
In-Reply-To: <86tvtle5wo.fsf@gmail.com>

On 2018-03-12 10:15, Yao Qi wrote:
> Simon Marchi <simon.marchi@polymtl.ca> writes:
>
>> While running selftests on a big-endian PPC, I noticed arm_record_test
>> failed a test.  The reason is that the gdbarch_find_by_info call is done
>> with BFD_ENDIAN_UNKNOWN byte order in the info structure.  In that case,
>> it uses the byte order of the current default BFD, which happened to be
>> big-endian on that GDB build, and the gdbarch returned is a big-endian
>> one.  The instruction used for the 32-bits part of the test is written
>> in little-endian form, so GDB fails to decode the instruction
>> properly.
>
> The test instructions are endianess-neutral, because they are written as
> uint16_t, and that is why you didn't have to adjust 16-bit thumb
> instructions in the tests.

Ok, and I think there was something confusing me with the order of the Thumb2 instructions
(maybe it's the order the bytes are written in the comment).  From what I understand now
after playing with objdump, the two 16-bit parts of a Thumb2 instructions are not swapped
on little endian, they are considered as two separate instructions (I guess it makes sense,
otherwise it would be impossible to determine whether the next instruction is 16-bit or
32-bit long).  So only the two bytes of each 16-bit chunk are swapped when switching
between big and little endian.  In memory, the bytes for that instruction should look like
this:

  little endian: 0x1d, 0xee, 0x70, 0x7f
  big endian:    0xee, 0x1d, 0x7f, 0x70

And in both cases, we want the value in arm_record->arm_insn to end up containing 0xee1d7f70.  Is that right?

>>
>> Since ARM supports both endiannesses, and it should be possible to debug
>> using an host of both endiannesses, I changed the test to check with
>> gdbarches of both endiannesses.
>
> Although ARM supports both endianesses, the big endian has two variants,
> BE-32 and BE-8.  Before ARMv6, it was BE-32.  In ARMv6, BE-8 must be
> supported, but support of BE-32 is implementation defined.  ARMv7 drops
> the BE-32 support.  With BE-8, data is big endian and code is little
> endian.  Thumb-2 instruction was introduced in armv6t2, so it is still
> likely to have both big endian and little endian thumb-2 instructions
> code.

Ok, thanks for the info.

> As I said, the test case is written in an endianess-neutral way,
>
>     static const uint16_t insns[] = {
>       /* 1d ee 70 7f	 mrc	15, 0, r7, cr13, cr0, {3} */
>       0xee1d, 0x7f70,
>     };

If my assumption above is right, everything looks right until extract_arm_insn.
The 4-byte instruction is extracted with

  insn_record->arm_insn = (uint32_t) extract_unsigned_integer (&buf[0],
                           insn_size,
			   gdbarch_byte_order_for_code (insn_record->gdbarch));

Since the instruction is extracted as a single 4-byte value, on little endian,
extract_arm_insn leaves insn_record->arm_insn equal to 0x7f70ee1d.  On big
endian, it leaves it equal to 0xee1d7f70.  Hence the need for the word swapping
you show below.

In my opinion, it should be extract_arm_insn's responsibility to leave
insn_record->arm_insn with a consistent value regardless of the target/host
endiannesses.  The easiest way would be to read the instruction as two 16-bit
integers instead of one 32-bit one.  Or we can still do the word swap shown below
(only if the code is little endian), but at least I think it would make more sense
to do it in extract_arm_insn.

>
> but the arm process recording processes thumb-2 instruction as one
> 32-bit instruction, so that it has this,
>
> 	  /* Swap first half of 32bit thumb instruction with second half.  */
> 	  arm_record->arm_insn
> 	    = (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);

> I wonder this is the cause of the test fail, that is, we don't need to
> swap them in big endian.  Since I've never run GDB tests on arm big
> endian target, I am not very confident on my fix below.  It fixes the
> test fail on ppc64, and also the fail with your patch to change the test
> with two different endianess.

What do you think about the patch below?  Functionally, it should be identical
to what you suggested, but I think it's clear to fix extract_arm_insn instead.


From 925b2f54e53f39b8713dccc7788b3f10fccc374c Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@ericsson.com>
Date: Mon, 12 Mar 2018 11:28:29 -0400
Subject: [PATCH] extract_arm_insn: Read 32-bit instruction as two 16-bit words

---
 gdb/arm-tdep.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index ef7e66b..e92ac13 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -13089,14 +13089,25 @@ extract_arm_insn (abstract_memory_reader& reader,
 		  insn_decode_record *insn_record, uint32_t insn_size)
 {
   gdb_byte buf[insn_size];
-
   memset (&buf[0], 0, insn_size);

+  gdb_assert (insn_size == 2 || insn_size == 4);
+
   if (!reader.read (insn_record->this_addr, buf, insn_size))
     return 1;
-  insn_record->arm_insn = (uint32_t) extract_unsigned_integer (&buf[0],
-                           insn_size,
-			   gdbarch_byte_order_for_code (insn_record->gdbarch));
+
+  bfd_endian endian = gdbarch_byte_order_for_code (insn_record->gdbarch);
+
+  insn_record->arm_insn
+    = (uint32_t) extract_unsigned_integer (&buf[0], 2, endian);
+
+  if (insn_size == 4)
+    {
+      insn_record->arm_insn <<= 16;
+      insn_record->arm_insn
+	|= (uint32_t) extract_unsigned_integer (&buf[2], 2, endian);
+    }
+
   return 0;
 }

@@ -13188,10 +13199,6 @@ decode_insn (abstract_memory_reader &reader, insn_decode_record *arm_record,
       /* As thumb does not have condition codes, we set negative.  */
       arm_record->cond = -1;

-      /* Swap first half of 32bit thumb instruction with second half.  */
-      arm_record->arm_insn
-	= (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);
-
       ret = thumb2_record_decode_insn_handler (arm_record);

       if (ret != ARM_RECORD_SUCCESS)
-- 
2.7.4


  reply	other threads:[~2018-03-12 15:42 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-12  3:09 Simon Marchi
2018-03-12 14:16 ` Yao Qi
2018-03-12 15:42   ` Simon Marchi [this message]
2018-03-12 17:09     ` Yao Qi
2018-03-12 18:54       ` Simon Marchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fb6d077c-d731-03b9-c9cd-b03a8f1ab161@ericsson.com \
    --to=simon.marchi@ericsson.com \
    --cc=gdb-patches@sourceware.org \
    --cc=qiyaoltc@gmail.com \
    --cc=simon.marchi@polymtl.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox