libretro / mame2010-libretro

Late 2010 version of MAME (0.139) for libretro. Compatible with MAME 0.139 sets.
32 stars 50 forks source link

'illegal instruction' error when trying to launch Gradius 4 (gradius4.zip) #130

Closed c0d3h4x0r closed 4 years ago

c0d3h4x0r commented 5 years ago

This repros on Raspberry Pi 3B+ w/ RetroPie using a build of this core based on commit c87309d.

c0d3h4x0r commented 5 years ago

Here's a stack trace:

Thread 1 "retroarch" received signal SIGILL, Illegal instruction.
0x67fb5198 in ?? ()
(gdb) bt
#0  0x67fb5198 in ?? ()
#1  0x6c96c6c4 in drcbex86_reset(_drcbe_state*) () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#2  0x6c967c18 in drcuml_reset(_drcuml_state*) () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#3  0x6cb88c2c in code_flush_cache(_powerpc_state*) () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#4  0x6cb8a810 in cpu_execute_ppcdrc(legacy_cpu_device*) () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#5  0x6cdc584c in device_scheduler::timeslice() () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#6  0x6cda492c in running_machine::retro_loop() () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#7  0x6cda279c in retro_main_loop() () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#8  0x6c834a4c in retro_run () from /opt/retropie/libretrocores/lr-mame2010/mame2010_libretro.so
#9  0x000201ec in core_run ()
#10 0x0002507c in runloop_iterate ()
#11 0x76fff000 in ?? () from /lib/ld-linux-armhf.so.3
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)
c0d3h4x0r commented 5 years ago

I'm working on getting a stack trace w/ source code info.

c0d3h4x0r commented 5 years ago

Stack trace w/ source info:

Thread 1 "retroarch" received signal SIGILL, Illegal instruction.
0x67e43198 in ?? ()
(gdb) bt
#0  0x67e43198 in ?? ()
#1  0x6c8ac934 in drcbex86_reset (drcbe=0x67e431d0) at src/emu/cpu/drcbex86.c:734
#2  0x6c8a7908 in drcuml_reset (drcuml=0x6c8a7908 <drcuml_reset(_drcuml_state*)+88>) at src/emu/cpu/drcuml.c:611
#3  0x6cb0cc8c in code_flush_cache (ppc=ppc@entry=0x65e42000) at src/emu/cpu/powerpc/ppcdrc.c:879
#4  0x6cb0e870 in cpu_execute_ppcdrc (device=<optimized out>) at src/emu/cpu/powerpc/ppcdrc.c:710
#5  0x6cd7d9c0 in device_scheduler::timeslice (this=0x0, this@entry=0x59c494) at src/emu/schedule.c:192
#6  0x6cd5a708 in running_machine::retro_loop (this=0x59bb50) at src/emu/machine.c:421
#7  0x6cd5806c in retro_main_loop () at src/emu/mame.c:218
#8  0x6c73b24c in retro_run () at src/osd/retro/retromain.c:803
#9  0x000203d4 in core_run () at core_impl.c:446
#10 0x000253e8 in runloop_iterate (sleep_ms=0x7549c <rarch_environment_cb>) at retroarch.c:4515
#11 0x71a75008 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
c0d3h4x0r commented 5 years ago

And here's the code at frame #1 (last line is line 734):

static void drcbex86_reset(drcbe_state *drcbe)
{
        UINT32 (*cpuid_ecx_stub)(void);
        x86code **dst;
        int regnum;

        /* output a note to the log */
        if (drcbe->log != NULL)
                x86log_printf(drcbe->log, "\n\n===========\nCACHE RESET\n===========\n\n");

        /* generate a little bit of glue code to set up the environment */
        dst = (x86code **)drccache_begin_codegen(drcbe->cache, 500);
        if (dst == NULL)
                fatalerror("Out of cache space after a reset!");

        /* generate a simple CPUID stub */
        cpuid_ecx_stub = (UINT32 (*)(void))*dst;
        emit_push_r32(dst, REG_EBX);                                                                                                            // push  ebx
        emit_mov_r32_imm(dst, REG_EAX, 1);                                                                                                      // mov   eax,1
        emit_cpuid(dst);                                                                                                                                        // cpuid
        emit_mov_r32_r32(dst, REG_EAX, REG_ECX);                                                                                        // mov   eax,ecx
        emit_pop_r32(dst, REG_EBX);                                                                                                                     // pop   ebx
        emit_ret(dst);                                                                                                                                          // ret

        /* call it to determine if we have SSE3 support */
        drcbe->sse3 = (((*cpuid_ecx_stub)() & 1) != 0);
c0d3h4x0r commented 5 years ago

Seems to me that something must be wrong with at least one of those emit_ functions (I assume they are for performing CPU opcode translation between emulated CPU and host CPU), b/c that section of code is obviously constructing an invalid native instruction.

c0d3h4x0r commented 5 years ago

Actually, this code looks to specific to Intel x86 architecture, which my hardware is not. I'm running on a Raspberry Pi 3B+ (ARM v8), so it's no surprise that x86 instructions would generate an "illegal instruction" exception. This suggests potentially a build problem someplace, wherein the x86 source code is getting erroneously built into the armv8 build.

c0d3h4x0r commented 5 years ago

Or possibly a missing/bad macro define somewhere.

c0d3h4x0r commented 5 years ago

And this comment from Makefile.common seems to support my suspicions... it sounds like dynamic recompilation is not supported on non-x86 platforms yet

# fixme - need to make this work for other target architectures (PPC)

ifndef FORCE_DRC_C_BACKEND
ifeq ($(PTR64),1)

DRCOBJ += \
        $(CPUOBJ)/drcbex64.o \
        $(CPUOBJ)/x86log.o $(CPUOBJ)/i386/i386dasm.o

DRCDEPS += \
        $(CPUSRC)/x86emit.h

DEFS += -DNATIVE_DRC=drcbe_x64_be_interface

else

DRCOBJ += \
        $(CPUOBJ)/drcbex86.o \
        $(CPUOBJ)/x86log.o $(CPUOBJ)/i386/i386dasm.o

DRCDEPS += \
        $(CPUSRC)/x86emit.h

DEFS += -DNATIVE_DRC=drcbe_x86_be_interface

endif
endif
c0d3h4x0r commented 5 years ago

And in Makefile, it looks like we just need to uncomment one line to define FORCE_DRC_C_BACKEND to hopefully get things working on armv8...

# uncomment the force the universal DRC to always use the C backend
# you may need to do this if your target architecture does not have
# a native backend
# FORCE_DRC_C_BACKEND = 1
c0d3h4x0r commented 5 years ago

Actually, there's already a Raspberry Pi-specific section in Makefile, so we probably just need to define FORCE_DRC_C_BACKEND inside that existing case...

c0d3h4x0r commented 5 years ago

Additionally, the platform is only being detected as 'unix' on my Raspberry Pi, so the added define isn't taking effect. So I'm also adding autodetection of the "retropie" distribution for now, since it will always be for the Raspberry Pi.

c0d3h4x0r commented 5 years ago

Yep, that finally did the trick -- the "illegal instruction" crash is now resolved! I'll prepare a pull request.