Bug 158730 - ppc: illegal opcode crash on instruction fctiwz
Summary: ppc: illegal opcode crash on instruction fctiwz
Status: REPORTED
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (show other bugs)
Version: 3.3.0
Platform: Compiled Sources Linux
: NOR crash
Target Milestone: ---
Assignee: Julian Seward
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-03-03 19:30 UTC by ben
Modified: 2008-10-30 15:03 UTC (History)
0 users

See Also:
Latest Commit:
Version Fixed In:


Attachments
Test assembly and binary files (6.20 KB, application/octet-stream)
2008-05-11 13:52 UTC, ben
Details
valgrind output with -v -v --trace-signals=yes --vex-guest-max-insns=1 (14.89 KB, text/plain)
2008-05-11 15:23 UTC, ben
Details
Last 2000 lines from --vex-guest-max-insns=1 --run-libc-freeres=no --trace-notbelow=0 --trace-flags=10001011 (6.07 KB, application/octet-stream)
2008-05-11 16:22 UTC, ben
Details

Note You need to log in before you can comment on or make changes to this bug.
Description ben 2008-03-03 19:30:28 UTC
valgrind crashes on the following code:

int conv(float f)
{
    return f;
}

The key instruction appears to be fctiwz.  From the disassembled code:

100003dc <conv>:
100003dc:       fc 00 08 1e     fctiwz  f0,f1
100003e0:       94 21 ff f0     stwu    r1,-16(r1)
100003e4:       d8 01 00 08     stfd    f0,8(r1)
100003e8:       80 61 00 0c     lwz     r3,12(r1)
100003ec:       38 21 00 10     addi    r1,r1,16
100003f0:       4e 80 00 20     blr

100003f4 <main>:
100003f4:       3d 20 10 00     lis     r9,4096
100003f8:       c0 29 07 48     lfs     f1,1864(r9)
100003fc:       4b ff ff e0     b       100003dc <conv>

valgrind output:

==3095== Memcheck, a memory error detector.
==3095== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==3095== Using LibVEX rev 1804, a library for dynamic binary translation.
==3095== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==3095== Using valgrind-3.3.0, a dynamic binary instrumentation framework.
==3095== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==3095== For more details, rerun with: -v
==3095== 
==3095== 
==3095== Process terminating with default action of signal 4 (SIGILL)
==3095==  Illegal opcode at address 0x429AD098
==3095==    at 0x100003F8: main (in /tmp/test)
==3095== 
==3095== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 2)
==3095== malloc/free: in use at exit: 0 bytes in 0 blocks.
==3095== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==3095== For counts of detected errors, rerun with: -v
==3095== All heap blocks were freed -- no leaks are possible.
Illegal instruction
Comment 1 Julian Seward 2008-05-11 10:10:48 UTC
Not sure this has anything to do with fctiwz, which I believe is
handled correctly.  The illegal instruction lives at 0x429AD098 and
not in disassembled code shown.

So anyway, what CPU is this on?  What does cat /proc/cpuinfo say?
Comment 2 ben 2008-05-11 13:50:45 UTC
I may be misinterpreting the valgrind output, but it would appear that valgrind is complaining about the instruction at 0x100003F8 in the original code, and that 0x429AD098 refers to some internal structure (address 0x429AD098 is not a valid address in the test binary).  However, that still leaves the valid question that 0x100003F8 does not correspond to fctiwz, which I claimed to be the source of the problem.

I tried a new test where I took the original code, and compiled it down to assembly.  I then created two versions, one with the fctiwz instruction, and one with it simply removed.  The one where it is present fails in the same way, while the one with it removed does not fail.  Strangely though, it still complains about a different instruction in the failing version.

I will attach the two assembly files and resulting binaries and the test output.  Here is the result from /proc/cpuinfo:

processor	: 0
cpu		: e500
revision	: 2.0 (pvr 8020 0020)
bogomips	: 831.48
chipset		: 8555E
Vendor		: SOMA Networks
Machine		: FBS v4 - MPC8555E
clock		: 833MHz
PVR		: 0x80200020
SVR		: 0x80790011
PLL setting	: 0x5
Memory		: 512 MB
Bootloader	: 0.5.3
Comment 3 ben 2008-05-11 13:52:08 UTC
Created attachment 24716 [details]
Test assembly and binary files
Comment 4 Julian Seward 2008-05-11 14:21:22 UTC
To knock some more ambiguity out of this: if you rerun with
--vex-guest-max-insns=1, do you get a different claim as to
where the offending instruction lives?
Comment 5 ben 2008-05-11 14:38:23 UTC
Yes, that makes more sense:

==3114== Process terminating with default action of signal 4 (SIGILL)
==3114==  Illegal opcode at address 0x428E97A0
==3114==    at 0x100003DC: conv (in /tmp/test-fail)
==3114==    by 0xFE7560C: (below main) (libc-start.c:231)

100003dc <conv>:
100003dc:       fc 00 08 1e     fctiwz  f0,f1
100003e0:       94 21 ff f0     stwu    r1,-16(r1)
100003e4:       d8 01 00 08     stfd    f0,8(r1)
100003e8:       80 61 00 0c     lwz     r3,12(r1)
100003ec:       38 21 00 10     addi    r1,r1,16
100003f0:       4e 80 00 20     blr
Comment 6 Julian Seward 2008-05-11 14:45:19 UTC
> ------- Yes, that makes more sense:


I'm still very confused :-)  I don't believe that Valgrind would
reject fctiwz unless it believes your CPU doesn't support floating
point at all.

Can you re-run the test program with -v -v --trace-signals=yes
and send the complete log?
Comment 7 ben 2008-05-11 15:23:24 UTC
Created attachment 24718 [details]
valgrind output with -v -v --trace-signals=yes --vex-guest-max-insns=1
Comment 8 Julian Seward 2008-05-11 16:16:55 UTC
Ah.  Now I understand why we've been going in circles .. it's a backend
problem in the JIT, not a frontend problem.  I need to see what code gets
generated for this block.  Can you run again with

--vex-guest-max-insns=1 --run-libc-freeres=no --trace-notbelow=0 --trace-flags=10001011 

This will generate several megabytes of output.  Chop off the last 
couple of thousand lines or so, compress, and send.
Comment 9 ben 2008-05-11 16:22:12 UTC
Created attachment 24722 [details]
Last 2000 lines from --vex-guest-max-insns=1 --run-libc-freeres=no --trace-notbelow=0 --trace-flags=10001011
Comment 10 Julian Seward 2008-05-11 16:43:27 UTC
Getting there ... maybe ..

In m_signals.c find this

	 if (event != NULL) {
	    if (haveaddr)
	       VG_(message)(Vg_UserMsg, " %s at address %p", 
			    event, info->VKI_SIGINFO_si_addr);

which is around line 1280 in the trunk sources.  I need to know
the value of *(UInt*)(info->VKI_SIGINFO_si_addr) when the message
is printed, iow change to

	       VG_(message)(Vg_UserMsg, " %s at address %p insn=0x%x", 
			    event, info->VKI_SIGINFO_si_addr,
                            *(UInt*)(info->VKI_SIGINFO_si_addr)
                            );

We could also (possibly) short-circuit all this: does your cpu have
some limitation on FP instruction support?  I ask because I think it
is barfing on the code that Valgrind generates for itself to run.
Comment 11 ben 2008-05-11 16:55:02 UTC
It's quite possible there are restrictions, but I'll have to do some research to figure out what they are.  If it helps, though, I can rebuild valgrind with any changes you think will be helpful.
Comment 12 ben 2008-05-11 17:32:41 UTC
With source change recommended, I get the following output:

    Illegal opcode at address 0x429C67A0 insn=0x7de00fae

which appears to translate to 

    stfiwx  f15,0,r1

Looking over the manual for the E500 core, I see that stfiwx is listed in the table of unsupported instructions, along with a few other floating point (and some string and control opcodes as well).
Comment 13 Lukasdz Turon 2008-06-19 23:50:38 UTC
Any update on that issue ? 
We are facing the same problem in our case - it seems that VEX is using stfiwx to "generate" fctiwz instruction:


   case 0x00F: // fctiwz (Float Conv to Int, Round to Zero, PPC32 p405)
      DIP("fctiwz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
      assign( r_tmp32, 
              binop(Iop_F64toI32, mkU32(Irrm_ZERO), mkexpr(frB) ));

    --->

      if (e->Iex.Binop.op == Iop_F64toI32) {
         /* This works in both mode64 and mode32. */
         addInstr(env, PPCInstr_FpSTFIW(r1, ftmp));
          ---> 
             case Pin_FpSTFIW: {
              UInt ir_addr = iregNo(i->Pin.FpSTFIW.addr, mode64);
              UInt fr_data = fregNo(i->Pin.FpSTFIW.data);
              // stfiwx (store fp64[lo32] as int32), PPC32 p517
              // Use rA==0, so that EA == rB == ir_addr
              p = mkFormX(p, 31, fr_data, 0/*rA=0*/, ir_addr, 983, 0);
              goto done;
 
Comment 14 Julian Seward 2008-10-30 15:03:20 UTC
Valgrind doesn't support e500 cpus at present, and there are no
immediate plans to fix this.  Supporting e500 properly looks like
quite a big and complicated chunk of work.