Bug 381085

Summary: Use of SXTX in a memory address is treated as an illegal instruction on Aarch64
Product: [Developer tools] valgrind Reporter: IsaacOscar
Component: callgrindAssignee: Josef Weidendorfer <josef.weidendorfer>
Status: REPORTED ---    
Severity: crash CC: jseward
Priority: NOR    
Version First Reported In: 3.12.0   
Target Milestone: ---   
Platform: Compiled Sources   
OS: Linux   
Latest Commit: Version Fixed/Implemented In:
Sentry Crash Report:

Description IsaacOscar 2017-06-11 02:10:06 UTC
When using a SXTX as part of a memory operand in

e.g, when running the following c program compiled with GCC 5.4.0
    int main()
    {
        asm("MOV X0, #0\n"
            "LDR X0, [X29, X0, SXTX #3]");
    }

Through callgrind (valgrind --tool=callgrind -v ./a.out) I recieve an illegal instruction error (specifically I get the following output):

==31690== Callgrind, a call-graph generating cache profiler
==31690== Copyright (C) 2002-2015, and GNU GPL'd, by Josef Weidendorfer et al.
==31690== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==31690== Command: ./a.out
==31690==
--31690-- Valgrind options:
--31690--    --tool=callgrind
--31690--    -v
--31690-- Contents of /proc/version:
--31690--   Linux version 4.4.0-75-generic (buildd@bos01-arm64-049) (gcc version 5.4.0 20160609 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.4) ) #96-Ubuntu SMP Thu Apr 20 09:56:48 UTC 2017
--31690--
--31690-- Arch and hwcaps: ARM64, LittleEndian, baseline
--31690-- Page sizes: currently 4096, max supported 65536
--31690-- Valgrind library directory: /usr/lib/valgrind
==31690== For interactive control, run 'callgrind_control -h'.
--31690-- Reading syms from /home/isaacg/a.out
--31690-- Reading syms from /lib/aarch64-linux-gnu/ld-2.23.so
--31690--   Considering /lib/aarch64-linux-gnu/ld-2.23.so ..
--31690--   .. CRC mismatch (computed 0cfa2cfe wanted e5fee7d4)
--31690--   Considering /usr/lib/debug/lib/aarch64-linux-gnu/ld-2.23.so ..
--31690--   .. CRC is valid
--31690-- Reading syms from /usr/lib/valgrind/callgrind-arm64-linux
--31690--   Considering /usr/lib/valgrind/callgrind-arm64-linux ..
--31690--   .. CRC mismatch (computed 8bef36ae wanted 0f59708e)
--31690--    object doesn't have a symbol table
--31690--    object doesn't have a dynamic symbol table
--31690-- Scheduler: using generic scheduler lock implementation.
==31690== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-31690-by-isaacg-on-???
==31690== embedded gdbserver: writing to   /tmp/vgdb-pipe-to-vgdb-from-31690-by-isaacg-on-???
==31690== embedded gdbserver: shared mem   /tmp/vgdb-pipe-shared-mem-vgdb-31690-by-isaacg-on-???
==31690==
==31690== TO CONTROL THIS PROCESS USING vgdb (which you probably
==31690== don't want to do, unless you know exactly what you're doing,
==31690== or are doing some strange experiment):
==31690==   /usr/lib/valgrind/../../bin/vgdb --pid=31690 ...command...
==31690==
==31690== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==31690==   /path/to/gdb ./a.out
==31690== and then give GDB the following command
==31690==   target remote | /usr/lib/valgrind/../../bin/vgdb --pid=31690
==31690== --pid is optional if only one valgrind process is running
==31690==
--31690-- Reading syms from /usr/lib/valgrind/vgpreload_core-arm64-linux.so
--31690--   Considering /usr/lib/valgrind/vgpreload_core-arm64-linux.so ..
--31690--   .. CRC mismatch (computed ce9dff7a wanted 728c1b44)
--31690--    object doesn't have a symbol table
--31690-- Reading syms from /lib/aarch64-linux-gnu/libc-2.23.so
--31690--   Considering /lib/aarch64-linux-gnu/libc-2.23.so ..
--31690--   .. CRC mismatch (computed 8dc9f479 wanted a6ed6c12)
--31690--   Considering /usr/lib/debug/lib/aarch64-linux-gnu/libc-2.23.so ..
--31690--   .. CRC is valid
--31690-- Symbol match: found runtime_resolve: ld-2.23.so +0x136f8=0x40136f8
gen_indexed_EA: unhandled case optS == 0xF
ARM64 front end: load_store
disInstr(arm64): unhandled instruction 0xF860FBA0
disInstr(arm64): 1111'1000 0110'0000 1111'1011 1010'0000
==31690== valgrind: Unrecognised instruction at address 0x400574.
==31690==    at 0x400574: main (in /home/isaacg/a.out)
==31690== Your program just tried to execute an instruction that Valgrind
==31690== did not recognise.  There are two possible reasons for this.
==31690== 1. Your program has a bug and erroneously jumped to a non-code
==31690==    location.  If you are running Memcheck and you just saw a
==31690==    warning about a bad jump, it's probably your program's fault.
==31690== 2. The instruction is legitimate but Valgrind doesn't handle it,
==31690==    i.e. it's Valgrind's fault.  If you think this is the case or
==31690==    you are not sure, please let us know and we'll try to fix it.
==31690== Either way, Valgrind will now raise a SIGILL signal which will
==31690== probably kill your program.
==31690==
==31690== Process terminating with default action of signal 4 (SIGILL)
==31690==  Illegal opcode at address 0x400574
==31690==    at 0x400574: main (in /home/isaacg/a.out)
==31690==
--31690-- Start dumping at BB 15696 (Prg.Term.)...
--31690-- Dump to /home/isaacg/callgrind.out.31690
--31690-- Dumping done.
==31690== Events    : Ir
==31690== Collected : 78499
==31690==
==31690== I   refs:      78,499
Illegal instruction (core dumped)

Changing the SXTX to an LSL (which operates equivalently but is encoded differently) causes no error messages.

Note: my uname -a output is:
Linux wolf 4.4.0-75-generic #96-Ubuntu SMP Thu Apr 20 09:56:48 UTC 2017 aarch64 aarch64 aarch64 GNU/Linux
Comment 1 Julian Seward 2017-06-12 06:56:47 UTC
(In reply to IsaacOscar from comment #0)
>             "LDR X0, [X29, X0, SXTX #3]");

Did you write that instruction by hand (in the original situation where it
crashed, not in this test case) ?  I ask because I have never seen gcc nor
LLVM/Clang generate a memory address like that.

In VEX/priv/guest_arm64_toIR.c, function gen_indexed_EA, find this

      case BITS4(1,1,1,1): goto fail; //ATC
      case BITS4(0,1,1,1):
         rhs = binop(Iop_Shl64, getIReg64orZR(mm), mkU8(szLg2));
         vex_sprintf(buf, "[%s, %s lsl %u]",
                     nameIReg64orZR(nn), nameIReg64orZR(mm), szLg2);
         break;

and remove the "goto fail;" on the first line, allowing it to fall through
to the 0111 case.  Does that help?  Does it provide the correct behaviour
for you for both positive and negative values of X0 ?
Comment 2 IsaacOscar 2017-06-12 07:35:12 UTC
Actually I found this error when I tried running callgrind through an executable a compiler I am writing generated (it used to output SXTX, but I have since changed it to output LSL because of this).

From my understanding the specification of the ARMv8-A reference manual, SXTX and LSL have identical behaviour but are encoded differently. (probably why GCC and clang don't bother emitting it).

Thank you, I tried that modification on the latest stable 3.12.0 source and it worked, thank you!