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
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?
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
Created attachment 24716 [details] Test assembly and binary files
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?
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
> ------- 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?
Created attachment 24718 [details] valgrind output with -v -v --trace-signals=yes --vex-guest-max-insns=1
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.
Created attachment 24722 [details] Last 2000 lines from --vex-guest-max-insns=1 --run-libc-freeres=no --trace-notbelow=0 --trace-flags=10001011
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.
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.
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).
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;
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.