Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Simon Marchi via Gdb-patches <gdb-patches@sourceware.org>
To: Alan Hayward <Alan.Hayward@arm.com>
Cc: nd <nd@arm.com>,
	"gdb-patches\\@sourceware.org" <gdb-patches@sourceware.org>
Subject: Re: [PATCH] gdb/arm: avoid undefined behavior shift when decoding immediate value
Date: Wed, 11 Nov 2020 15:44:55 -0500	[thread overview]
Message-ID: <66ee1922-d144-29bc-a8c7-7eceb0b345ce@efficios.com> (raw)
In-Reply-To: <735CB03B-2500-4CAE-8FB3-FA253DA4E414@arm.com>

On 2020-11-11 5:00 a.m., Alan Hayward wrote:
>
>
>> On 9 Nov 2020, at 20:49, Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> wrote:
>>
>> From: Simon Marchi <simon.marchi@polymtl.ca>
>>
>> When loading the code file provided in PR 26828 and GDB is build with
>> UBSan, we get:
>>
>>    Core was generated by `./Foo'.
>>    Program terminated with signal SIGABRT, Aborted.
>>    #0  0xb6c3809c in pthread_cond_wait () from /home/simark/build/binutils-gdb/gdb/repo/lib/libpthread.so.0
>>    [Current thread is 1 (LWP 29367)]
>>    (gdb) bt
>>    /home/simark/src/binutils-gdb/gdb/arm-tdep.c:1551:30: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
>>
>
> This error is because the code is technically wrong - but in reality
> compilers will plant what we really wanted?

Well, we don't really know, different things can happen on different
systems.  I did this program for fun:

    #include <stdlib.h>
    #include <stdio.h>

    int main(int argc, char **argv) {
            unsigned int foo = 0xabababab;
            unsigned int shift = atoi(argv[1]);
            printf("Shifting by %d\n", shift);
            foo = foo >> shift;
            printf("%x\n", foo);
            return 0;
    }

Running `./a.out 32`, I get this on AMD64:

    Shifting by 32
    abababab

And I get this on PowerPC and ARM:

    Shifting by 32
    0

>> The sequence of instructions at pthread_cond_wait, in the
>> libpthread.so.0 library, contains this instruction with an immediate
>> constant with a "rotate amount" of 0:
>>
>>    e24dd044        sub     sp, sp, #68     ; 0x44
>>
>> Since it shifts by "32 - rotate amount", arm_analyze_prologue does a 32
>> bit shift of a 32 bit type, which is caught by UBSan.
>>
>
> Minor nit - it took me a while to figure out that the “it” in “Since it”
> is the following arm_analyze_prologue and not something in the previous
> sentence.

Good point, I swapped "it" and "arm_analyze_prologue" to make sure
"arm_analyze_prologue" comes before.

>
>> Fix it by factoring out the decoding of immediates in a new function,
>> arm_expand_immediate.
>>
>> I added a selftest for arm_analyze_prologue that replicates the
>> instruction sequence.  Without the fix, it crashes GDB if it is build
>> with --enable-ubsan.
>>
>> I initially wanted to re-use the abstract_memory_reader class already in
>> arm-tdep.c, used to make arm_process_record testable.  However,
>> arm_process_record and arm_analyze_prologue don't use the same kind of
>> memory reading functions.  arm_process_record uses a function that
>> returns an error status on failure while arm_analyze_prologue uses one
>> that throws an exception.  Since i didn't want to introduce any other
>> behavior change, I decided to just introduce a separate interface
>> (arm_instruction_reader).  It is derived from
>> abstract_instruction_reader in aarch64-tdep.c.
>
> I both don’t like this and can’t see a better way of doing it :)
> So, I’m ok with it

Same.  I really wanted not to add another class, but I also didn't want
this simple fix to become a huge refactor.

>> @@ -1485,6 +1511,26 @@ arm_instruction_restores_sp (unsigned int insn)
>>   return 0;
>> }
>>
>> +/* Implement immediate value decoding, as described in section A5.2.4
>> +   (Modified immediate constants in ARM instructions) of the ARM Architecture
>> +   Reference Manual.  */
>
>
> "of the ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition)"
>
> Just to make sure no one is looking for that section in the v8 doc.

Done.

>> @@ -9618,6 +9658,7 @@ vfp - VFP co-processor."),
>>
>> #if GDB_SELF_TEST
>>   selftests::register_test ("arm-record", selftests::arm_record_test);
>> +  selftests::register_test ("arm_analyze_prologue", selftests::arm_analyze_prologue_test);
>> #endif
>
> Given the size of the tdep files, I wonder if it’s worth putting the tests into separate
> files, eg arm-tdep-selftests.c
> (Probably not for this patch though)

Possibly.  That requires exposing (making non-static) functions that are not usually exposed
though.

>> }
>> @@ -13254,6 +13295,63 @@ arm_record_test (void)
>>     SELF_CHECK (arm_record.arm_regs[0] == 7);
>>   }
>> }
>> +
>> +/* Instruction reader from manually cooked instruction sequences.  */
>> +
>> +class test_arm_instruction_reader : public arm_instruction_reader
>> +{
>> +public:
>> +  template<size_t SIZE>
>> +  explicit test_arm_instruction_reader (const uint32_t (&insns)[SIZE])
>> +    : m_insns (insns), m_insns_size (SIZE)
>
> Why the need for a template?
> Is it just so that m_insns_size can be determined automatically?

I don't really know, I just copied the AArch64 one :).  But yeah I think
that's it.  It could also use a gdb::array_view, that would be simpler I
think.  I would change it for:

  /* Instruction reader from manually cooked instruction sequences.  */

  class test_arm_instruction_reader : public arm_instruction_reader
  {
  public:
    explicit test_arm_instruction_reader (gdb::array_view<const uint32_t> insns)
      : m_insns (insns)
    {}

    uint32_t read (CORE_ADDR memaddr, enum bfd_endian byte_order) const override
    {
      SELF_CHECK (memaddr % 4 == 0);
      SELF_CHECK (memaddr / 4 < m_insns.size ());

      return m_insns[memaddr / 4];
    }

  private:
    const gdb::array_view<const uint32_t> m_insns;
  };

Simon

  reply	other threads:[~2020-11-11 20:45 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-09 20:49 Simon Marchi via Gdb-patches
2020-11-11 10:00 ` Alan Hayward via Gdb-patches
2020-11-11 20:44   ` Simon Marchi via Gdb-patches [this message]
2020-11-13 17:05     ` Simon Marchi
2020-11-13 22:35 ` Luis Machado via Gdb-patches
2020-11-14 16:20   ` 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=66ee1922-d144-29bc-a8c7-7eceb0b345ce@efficios.com \
    --to=gdb-patches@sourceware.org \
    --cc=Alan.Hayward@arm.com \
    --cc=nd@arm.com \
    --cc=simon.marchi@efficios.com \
    /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