From be56fa04ad36d673271cb860834229095694ce3d Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 15 Oct 2025 23:27:45 -0600 Subject: [PATCH 1/5] Add Xbox 360 platform --- backend/Dockerfile | 4 +- backend/compilers/compilers.linux.yaml | 4 ++ backend/coreapp/compilers.py | 18 +++++ backend/coreapp/platforms.py | 16 ++++- backend/coreapp/views/scratch.py | 2 +- .../PlatformSelect/PlatformIcon.tsx | 2 + .../src/components/PlatformSelect/xbox360.svg | 72 +++++++++++++++++++ .../src/lib/i18n/locales/en/compilers.json | 3 + 8 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/PlatformSelect/xbox360.svg diff --git a/backend/Dockerfile b/backend/Dockerfile index 8266bd73a..ed9a3985b 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -136,6 +136,7 @@ ARG ENABLE_PSP_SUPPORT ARG ENABLE_SATURN_SUPPORT ARG ENABLE_SWITCH_SUPPORT ARG ENABLE_WIN32_SUPPORT +ARG ENABLE_XBOX360_SUPPORT ENV ENABLE_DREAMCAST_SUPPORT=${ENABLE_DREAMCAST_SUPPORT} \ ENABLE_GBA_SUPPORT=${ENABLE_GBA_SUPPORT} \ @@ -150,7 +151,8 @@ ENV ENABLE_DREAMCAST_SUPPORT=${ENABLE_DREAMCAST_SUPPORT} \ ENABLE_PSP_SUPPORT=${ENABLE_PSP_SUPPORT} \ ENABLE_SATURN_SUPPORT=${ENABLE_SATURN_SUPPORT} \ ENABLE_SWITCH_SUPPORT=${ENABLE_SWITCH_SUPPORT} \ - ENABLE_WIN32_SUPPORT=${ENABLE_WIN32_SUPPORT} + ENABLE_WIN32_SUPPORT=${ENABLE_WIN32_SUPPORT} \ + ENABLE_XBOX360_SUPPORT=${ENABLE_XBOX360_SUPPORT} ENTRYPOINT ["/backend/docker_entrypoint.sh"] diff --git a/backend/compilers/compilers.linux.yaml b/backend/compilers/compilers.linux.yaml index 7d209b6a8..d8d638107 100644 --- a/backend/compilers/compilers.linux.yaml +++ b/backend/compilers/compilers.linux.yaml @@ -213,3 +213,7 @@ win32: - msvc7.1 - msvc8.0 - msvc8.0p + +xbox360: + - msvc_ppc_14.00.2110 + - msvc_ppc_16.00.11886.00 diff --git a/backend/coreapp/compilers.py b/backend/coreapp/compilers.py index 04a150aaf..7715702af 100644 --- a/backend/coreapp/compilers.py +++ b/backend/coreapp/compilers.py @@ -42,6 +42,7 @@ DREAMCAST, SWITCH, WIN32, + XBOX360, Platform, ) from django.conf import settings @@ -1497,6 +1498,20 @@ def available_platforms() -> List[Platform]: cc=BORLAND_MSDOS_CC, ) +CL_XBOX = '${WIBO} "${COMPILER_DIR}/cl.exe" /c /nologo ${COMPILER_FLAGS} /Fd"Z:/tmp/" /Bk"Z:/tmp/" /Fo"Z:${OUTPUT}" "Z:${INPUT}"' + +MSVC_PPC_14_00_2110 = MSVCCompiler( + id="msvc_ppc_14.00.2110", + platform=XBOX360, + cc=CL_XBOX, +) + +MSVC_PPC_16_00_11886_00 = MSVCCompiler( + id="msvc_ppc_16.00.11886.00", + platform=XBOX360, + cc=CL_XBOX, +) + _all_compilers: List[Compiler] = [ DUMMY, DUMMY_LONGRUNNING, @@ -1724,6 +1739,9 @@ def available_platforms() -> List[Platform]: # Borland, DOS BORLAND_20_C, BORLAND_31_C, + # Xbox 360 + MSVC_PPC_14_00_2110, + MSVC_PPC_16_00_11886_00, ] _compilers = OrderedDict({c.id: c for c in _all_compilers if c.available()}) diff --git a/backend/coreapp/platforms.py b/backend/coreapp/platforms.py index 75a140371..37c033c15 100644 --- a/backend/coreapp/platforms.py +++ b/backend/coreapp/platforms.py @@ -24,9 +24,9 @@ class Platform: name: str description: str arch: str - assemble_cmd: str - objdump_cmd: str - nm_cmd: str + assemble_cmd: str | None = None + objdump_cmd: str | None = None + nm_cmd: str | None = None diff_flags: Flags = field(default_factory=lambda: COMMON_DIFF_FLAGS, hash=False) supports_objdump_disassemble: bool = False # TODO turn into objdump flag has_decompiler: bool = False @@ -52,7 +52,9 @@ def to_json( "name": self.name, "description": self.description, "arch": self.arch, + "has_assembler": self.assemble_cmd is not None, "has_decompiler": self.has_decompiler, + "has_objdump": self.objdump_cmd is not None, } if include_compilers: ret["compilers"] = [ @@ -248,6 +250,13 @@ def from_id(platform_id: str) -> Platform: nm_cmd="arm-none-eabi-nm", ) +XBOX360 = Platform( + id="xbox360", + name="Xbox 360", + description="PowerPC (64-bit, big-endian)", + arch="ppc", +) + _platforms: OrderedDict[str, Platform] = OrderedDict( { "dummy": DUMMY, @@ -266,5 +275,6 @@ def from_id(platform_id: str) -> Platform: "macosx": MACOSX, "msdos": MSDOS, "win32": WIN32, + "xbox360": XBOX360, } ) diff --git a/backend/coreapp/views/scratch.py b/backend/coreapp/views/scratch.py index 51ae0fb1e..d46accadd 100644 --- a/backend/coreapp/views/scratch.py +++ b/backend/coreapp/views/scratch.py @@ -76,7 +76,7 @@ def cache_object(platform: Platform, file: File[Any]) -> Assembly: obj_bytes = file.read() is_elf = obj_bytes[:4] == b"\x7fELF" is_macho = obj_bytes[:4] == b"\xcf\xfa\xed\xfe" - is_coff = obj_bytes[:2] in (b"\x4c\x01", b"\x64\x86") + is_coff = obj_bytes[:2] in (b"\x4c\x01", b"\x64\x86", b"\xf2\x01") if not (is_elf or is_macho or is_coff): raise serializers.ValidationError("Object must be an ELF, Mach-O, or COFF file") diff --git a/frontend/src/components/PlatformSelect/PlatformIcon.tsx b/frontend/src/components/PlatformSelect/PlatformIcon.tsx index 7c45aedbb..3bbd70b76 100644 --- a/frontend/src/components/PlatformSelect/PlatformIcon.tsx +++ b/frontend/src/components/PlatformSelect/PlatformIcon.tsx @@ -18,6 +18,7 @@ import LogoSaturn from "./saturn.svg"; import LogoSwitch from "./switch.svg"; import UnknownIcon from "./unknown.svg"; import LogoWin32 from "./win32.svg"; +import LogoXbox360 from "./xbox360.svg"; /** In release-date order */ const ICONS = { @@ -36,6 +37,7 @@ const ICONS = { switch: LogoSwitch, saturn: LogoSaturn, dreamcast: LogoDreamcast, + xbox360: LogoXbox360, }; export const PLATFORMS = Object.keys(ICONS); diff --git a/frontend/src/components/PlatformSelect/xbox360.svg b/frontend/src/components/PlatformSelect/xbox360.svg new file mode 100644 index 000000000..748f6f116 --- /dev/null +++ b/frontend/src/components/PlatformSelect/xbox360.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/lib/i18n/locales/en/compilers.json b/frontend/src/lib/i18n/locales/en/compilers.json index d7b65ebff..f86d32cff 100644 --- a/frontend/src/lib/i18n/locales/en/compilers.json +++ b/frontend/src/lib/i18n/locales/en/compilers.json @@ -112,6 +112,9 @@ "msvc8.0": "Microsoft Visual C/C++ 8.0", "msvc8.0p": "Microsoft Visual C/C++ 8.0 (Patched)", + "msvc_ppc_14.00.2110": "Microsoft C/C++ Compiler 14.00.2110 for PowerPC", + "msvc_ppc_16.00.11886.00": "Microsoft C/C++ Compiler 16.00.11886.00 for PowerPC", + "mwcc_20_72": "2.0 build 72 (MW 1.2base)", "mwcc_20_79": "2.0 build 79 (MW 1.2sp2)", "mwcc_20_82": "2.0 build 82 (MW 1.2sp2p3)", From b876df12100a50dbd3dcc30c73729df874d32e51 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 8 Feb 2026 23:07:59 -0700 Subject: [PATCH 2/5] Add xbox360-binutils and restore non-nullable platform fields - Install powerpc-xenon-pe-* binutils from xbox360-binutils 2.45.1-1 in the backend Dockerfile, mirroring the gc-wii-binutils pattern - Configure XBOX360 platform with assemble/objdump/nm commands using the new powerpc-xenon-pe-* tools - Revert assemble_cmd/objdump_cmd/nm_cmd to non-nullable str (no longer needed now that xbox360 has proper binutils) - Remove has_assembler/has_objdump from platform JSON serialization --- backend/Dockerfile | 5 +++++ backend/coreapp/platforms.py | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 67c8362dc..37a4829fd 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -93,6 +93,11 @@ RUN curl -sSL "https://github.com/encounter/gc-wii-binutils/releases/download/2. bsdtar -xvf- -C /usr/bin \ && chmod +x /usr/bin/powerpc-eabi-* +# Xbox 360 (Xenon) PowerPC binutils +RUN curl -sSL "https://github.com/encounter/xbox360-binutils/releases/download/2.45.1-1/linux-x86_64.zip" | \ + bsdtar -xvf- -C /usr/bin \ + && chmod +x /usr/bin/powerpc-xenon-pe-* + # MSDOS specific RUN wget "https://github.com/OmniBlade/binutils-gdb/releases/download/omf-build/omftools.tar.gz" \ && tar xvzf omftools.tar.gz -C /usr/bin jwasm \ diff --git a/backend/coreapp/platforms.py b/backend/coreapp/platforms.py index b07a873d4..b06856c39 100644 --- a/backend/coreapp/platforms.py +++ b/backend/coreapp/platforms.py @@ -24,9 +24,9 @@ class Platform: name: str description: str arch: str - assemble_cmd: str | None = None - objdump_cmd: str | None = None - nm_cmd: str | None = None + assemble_cmd: str + objdump_cmd: str + nm_cmd: str diff_flags: Flags = field(default_factory=lambda: COMMON_DIFF_FLAGS, hash=False) supports_objdump_disassemble: bool = False # TODO turn into objdump flag has_decompiler: bool = False @@ -52,9 +52,7 @@ def to_json( "name": self.name, "description": self.description, "arch": self.arch, - "has_assembler": self.assemble_cmd is not None, "has_decompiler": self.has_decompiler, - "has_objdump": self.objdump_cmd is not None, } if include_compilers: ret["compilers"] = [ @@ -258,6 +256,9 @@ def from_id(platform_id: str) -> Platform: name="Xbox 360", description="PowerPC (64-bit, big-endian)", arch="ppc", + assemble_cmd='powerpc-xenon-pe-as -o "$OUTPUT" "$PRELUDE" "$INPUT"', + objdump_cmd="powerpc-xenon-pe-objdump", + nm_cmd="powerpc-xenon-pe-nm", ) _platforms: OrderedDict[str, Platform] = OrderedDict( From c232ddfde38d9e3be8f3a259ffe559b2ccf8c1b7 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 8 Feb 2026 23:23:22 -0700 Subject: [PATCH 3/5] Bump wibo to 1.0.1 Includes TLS directory and GlobalMemoryStatus support which may fix the msvc_ppc_16.00.11886.00 segfault under wibo. --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 3ab61ff71..b98de24d2 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -83,7 +83,7 @@ RUN wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3 COPY --from=nsjail /nsjail/nsjail /bin/nsjail -COPY --from=ghcr.io/decompals/wibo:1.0.0-beta.5 /usr/local/bin/wibo /usr/bin/ +COPY --from=ghcr.io/decompals/wibo:1.0.1 /usr/local/bin/wibo /usr/bin/ # Patched mips binutils RUN wget "https://github.com/decompals/binutils-mips-ps2-decompals/releases/download/v0.4/binutils-mips-ps2-decompals-linux-x86-64.tar.gz" \ From d3de800bd18125d3eea2a3139bba0336279e2712 Mon Sep 17 00:00:00 2001 From: Mark Street <22226349+mkst@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:37:22 +0000 Subject: [PATCH 4/5] Merge pull request #2 from decompme/fixup-xbox360-svg Fixup svg --- frontend/src/components/PlatformSelect/xbox360.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/PlatformSelect/xbox360.svg b/frontend/src/components/PlatformSelect/xbox360.svg index 748f6f116..c8f5a6b53 100644 --- a/frontend/src/components/PlatformSelect/xbox360.svg +++ b/frontend/src/components/PlatformSelect/xbox360.svg @@ -1,4 +1,4 @@ - + From 06183e95295cd8658116633556486298abf53696 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 9 Feb 2026 10:43:17 -0700 Subject: [PATCH 5/5] Update Xbox 360 description to avoid wrapping --- backend/coreapp/platforms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/coreapp/platforms.py b/backend/coreapp/platforms.py index edf921848..43b9754e6 100644 --- a/backend/coreapp/platforms.py +++ b/backend/coreapp/platforms.py @@ -265,7 +265,7 @@ def from_id(platform_id: str) -> Platform: XBOX360 = Platform( id="xbox360", name="Xbox 360", - description="PowerPC (64-bit, big-endian)", + description="PowerPC 64-bit (big-endian)", arch="ppc", assemble_cmd='powerpc-xenon-pe-as -o "$OUTPUT" "$PRELUDE" "$INPUT"', objdump_cmd="powerpc-xenon-pe-objdump",