Compare commits

..

3 commits

Author SHA1 Message Date
KeybadeBlox
d7abbb79c0 Update progress
I really need to automate this.
2026-02-20 21:56:45 -05:00
KeybadeBlox
9cfd8b5bf3 Delink/begin decompiling entry point
That is, xapi0.obj, which has been renamed from crt0.obj because it
appears to be part of the Xbox libraries rather than the C runtime.
2026-02-20 21:50:00 -05:00
KeybadeBlox
9b6c91a12e Prevent repeated name mangling
A symbol could be encountered more than once in headless mode if it
appeared in the body of a function.  The mangler script now tracks which
symbols have been seen to avoid this.
2026-02-20 21:44:43 -05:00
9 changed files with 122 additions and 48 deletions

View file

@ -14,10 +14,10 @@
"source_path": "src/JSRF/Jet2.cpp" "source_path": "src/JSRF/Jet2.cpp"
}, },
"symbol_mappings": { "symbol_mappings": {
"?main_funcinfo@@3UFuncInfo@@A": "$T745", "?main_funcinfo@@3UFuncInfo@@A": "$T747",
"?main_handler@@YAXPAUEHExceptionRecord@@PAKPAXPAU_xDISPATCHER_CONTEXT@@@Z": "$L749", "?main_handler@@YAXPAUEHExceptionRecord@@PAKPAXPAU_xDISPATCHER_CONTEXT@@@Z": "$L751",
"?main_handler_unwind1@@YAXXZ": "$L741", "?main_handler_unwind1@@YAXXZ": "$L743",
"?main_unwindmap@@3PAUUnwindMapEntry@@A": "$T751", "?main_unwindmap@@3PAUUnwindMapEntry@@A": "$T753",
"[.rdata-0]": "[.xdata$x-0]" "[.rdata-0]": "[.xdata$x-0]"
} }
}, },
@ -42,6 +42,15 @@
"?finalizeGameData@@YAXXZ": "_$E2", "?finalizeGameData@@YAXXZ": "_$E2",
"?initGameData@@YAXXZ": "_$E1" "?initGameData@@YAXXZ": "_$E1"
} }
},
{
"name": "XDK/Xapi/xapi0",
"target_path": "target/XDK/Xapi/xapi0.obj",
"base_path": "src/XDK/Xapi/xapi0.obj",
"metadata": {
"complete": false,
"source_path": "src/XDK/Xapi/xapi0.c"
}
} }
] ]
} }

View file

@ -1,33 +0,0 @@
/* JSRF Decompilation: XDK/CRT0.c
C runtime initialization.
Like other CRT code, there's some magic here with symbols that get special
treatment from the compiler and linker.
*/
#include "../Win32.h"
// Every program is supposed to have a main(), so we can just assume its
// existence with a declaration here
int main(void);
void __cdecl mainCRTStartup (void);
DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter);
// Address: 0x00148023
// Status: unimplemented
void __cdecl mainCRTStartup(void) {
/* The true entrypoint of the game, spawning a thread for the rest to run in
The linker automatically sets this function to the entrypoint.
*/
}
// Address: 0x00147FB4
// Status: unimplemented
DWORD __stdcall mainXapiStartup(LPVOID const lpThreadParameter) {
/* Runs some initialization and then calls main() */
main();
return 0;
}

View file

@ -25,7 +25,7 @@ typedef __int64 LONGLONG;
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef unsigned long DWORD; typedef unsigned long DWORD, * PDWORD;
typedef void VOID; typedef void VOID;
typedef void * LPVOID; typedef void * LPVOID;
@ -45,6 +45,8 @@ union LARGE_INTEGER {
LONGLONG QuadPart; LONGLONG QuadPart;
}; };
typedef void * HANDLE;
// Return codes // Return codes
typedef long HRESULT; typedef long HRESULT;

View file

@ -0,0 +1,83 @@
/* JSRF Decompilation: XDK/Xapi/xapi0.c
Entrypoint for Xbox programs.
Awkwardly, the placement in the .xbe suggests this is not part of the C runtime
(which is normally what provides mainCRTStartup()), but rather part of Xapi.
It's been named xapi0 in analogy to crt0 in a C runtime.
*/
#include "../CRT/stddef.h"
#include "../Win32.h"
// Things that should get declared in a header somewhere
#define XLD_LAUNCH_DASHBOARD_ERROR 1
#define XLD_ERROR_INVALID_XBE 1
extern struct IMAGE_TLS_DIRECTORY {
DWORD StartAddressOfRawData;
DWORD EndAddressOfRawData;
DWORD * AddressOfIndex;
void * AddressOfCallbacks;
DWORD SizeOfZeroFill;
DWORD Characteristics;
} _tls_used;
extern int XapiTlsSize;
DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter);
BOOL __stdcall CloseHandle (HANDLE hHandle );
typedef DWORD (__stdcall * LPTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
HANDLE __stdcall CreateThread(
void * lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
PDWORD lpThreadId
);
void __stdcall XapiBootToDash(
DWORD dwReason,
DWORD dwParameter1,
DWORD dwParameter2
);
// Every program is supposed to have a main(), so we can just assume its
// existence with a declaration here
int main(void);
// Address: 0x00147FB4
// Status: unimplemented
DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter) {
/* Runs some Xbox-specific initialization and then calls main() */
main();
return 0;
}
// Address: 0x00148023
// Status: nonmatching
void mainCRTStartup(void) {
/* The true entrypoint of the game, spawning a thread for the rest to run in
The linker automatically sets this function to the entrypoint.
*/
HANDLE thread;
// Figure out available thread-local storage
XapiTlsSize = (
(_tls_used.EndAddressOfRawData - _tls_used.StartAddressOfRawData) +
_tls_used.SizeOfZeroFill
) + 15 & 0xFFFFFFF0; // Round up to nearest 0x10
*_tls_used.AddressOfIndex = XapiTlsSize / (-4);
// Launch program as a thread
thread = CreateThread(NULL, 0, mainXapiStartup, NULL, 0, NULL);
// Boot back to dashboard with an error message if launching failed
if (thread == NULL)
XapiBootToDash(XLD_LAUNCH_DASHBOARD_ERROR, XLD_ERROR_INVALID_XBE, 0);
CloseHandle(thread);
}

View file

View file

View file

@ -66,8 +66,10 @@ import ghidra.program.model.symbol.Symbol;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.zip.CRC32; import java.util.zip.CRC32;
@ -88,28 +90,35 @@ public class MSVC7Mangle extends GhidraScript {
setCurrentSelection(addr); setCurrentSelection(addr);
} }
final HashSet<Symbol> seenSymbols = new HashSet<>(1024);
for (final Symbol s : currentProgram.getSymbolTable() for (final Symbol s : currentProgram.getSymbolTable()
.getPrimarySymbolIterator(currentSelection, true)) { .getPrimarySymbolIterator(currentSelection, true)) {
mangle(s); mangle(s, seenSymbols);
// Also mangle everything referenced inside functions // Also mangle everything referenced inside functions
// if headless // if headless
if ( if (
isRunningHeadless() && isRunningHeadless() &&
s.getObject() instanceof Function f s.getObject() instanceof Function f
) mangleRefs(f); ) mangleRefs(f, seenSymbols);
} }
} }
private void mangle(final Symbol s) throws Exception { private void mangle(
final Symbol s,
final Set seenSymbols
) throws Exception {
/* Set the given symbol's name to its mangled version */ /* Set the given symbol's name to its mangled version */
// Skip if already mangled; skip jump tables // Skip if already mangled; skip jump tables
final String name = s.getName(true); final String name = s.getName(true);
if ( if (
seenSymbols.contains(s) ||
name.charAt(0) == '?' || name.charAt(0) == '?' ||
name.startsWith("switchD_") name.startsWith("switchD_")
) return; ) return;
seenSymbols.add(s);
// Get mangled name // Get mangled name
final String mangled = switch (s.getObject()) { final String mangled = switch (s.getObject()) {
case Function f -> mangleFn (f); case Function f -> mangleFn (f);
@ -622,7 +631,10 @@ public class MSVC7Mangle extends GhidraScript {
return (int)crc.getValue() ^ 0xFFFFFFFF; return (int)crc.getValue() ^ 0xFFFFFFFF;
} }
private void mangleRefs(final Function f) throws Exception { private void mangleRefs(
final Function f,
final Set seenSymbols
) throws Exception {
/* Mangle all symbols referenced in the body of a function */ /* Mangle all symbols referenced in the body of a function */
for ( for (
Instruction ins = getFirstInstruction(f); Instruction ins = getFirstInstruction(f);
@ -650,7 +662,7 @@ public class MSVC7Mangle extends GhidraScript {
continue; continue;
} }
mangle(symbol); mangle(symbol, seenSymbols);
} }
} }
} }

View file

@ -3,13 +3,14 @@ JSRF/Core.obj,true,0x00011000-0x00013FEB,,,0x00186BA0-0x00186C14,,,,,,0x001C4390
JSRF/GameData.obj,true,0x00039B50-0x0003B937,0x0018AD60-0x0018AD75,0x0018C9A0-0x0018C9AA,,,,,,,0x001CA16C-0x001CA3DB,,0x001EB790-0x001EB793,0x001EFC88-0x001F7047, JSRF/GameData.obj,true,0x00039B50-0x0003B937,0x0018AD60-0x0018AD75,0x0018C9A0-0x0018C9AA,,,,,,,0x001CA16C-0x001CA3DB,,0x001EB790-0x001EB793,0x001EFC88-0x001F7047,
JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620C-0x001E622F,,0x0022FCE0-0x0022FCE3, JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620C-0x001E622F,,0x0022FCE0-0x0022FCE3,
ADX (need to decompose),false,0x0013A570-0x0014555F,?,?,?,?,,,,,,?,?,?, ADX (need to decompose),false,0x0013A570-0x0014555F,?,?,?,?,,,,,,?,?,?,
XDK Core (need to decompose),false,0x00145560-0x0014B79F,?,?,?,?,,,,,,?,?,?, Xapi (need to decompose),false,0x00145560-0x0014B79F,?,?,?,?,,,,,,?,?,?,
XDK/Xapi/xapi0.obj,true,0x00147FB4-0x0014807C,,,,,,,,,,,,,
Smilebit libs (need to decompose),false,0x0014B7A0-0x0017BF3F,?,?,?,?,,,,,,?,?,?-0x0022ED2B, Smilebit libs (need to decompose),false,0x0014B7A0-0x0017BF3F,?,?,?,?,,,,,,?,?,?-0x0022ED2B,
C runtime,false,0x0017BF40-0x00182B80,?,?,?,,,,,?,?,0x0022ED2C-?,?,?, C runtime (need to decompose),false,0x0017BF40-0x00182B80,?,?,?,,,,,?,?,0x0022ED2C-?,?,?,
Unknown MS math lib,false,0x00182B81-0x0018694F,?,?,?,,,,,?,?,?,?,?, Unknown MS math lib,false,0x00182B81-0x0018694F,?,?,?,,,,,?,?,?,?,?,
Another (tiny) Smilebit math lib,false,0x00186950-0x00186B7F,?,?,?,,,,,?,?,?,?,?, Another (tiny) Smilebit math lib,false,0x00186950-0x00186B7F,?,?,?,,,,,?,?,?,?,?,
Direct3D8 (need to decompose),false,,?,,0x0018CB40-0x0019E334,,,,,?,?,?,?,?, Direct3D8 (need to decompose),false,,?,,0x0018CB40-0x0019E334,,,,,?,?,?,?,?,
DirectSound8 (need to decompose),false,,?,?,,,0x0019E340-0x001BA89B,,,,?,?,?,?,0x0027E080-0x00284E17 DirectSound8 (need to decompose),false,,?,?,,,0x0019E340-0x001BA89B,,,,?,?,?,?,0x0027E080-0x00284E17
MMatrix.obj,false,,?,,,,0x001BA8A0-0x001BBAAF,,,,,?,?,0x00264BD8-0x00264C13, Smilebit/MMatrix.obj,false,,?,,,,0x001BA8A0-0x001BBAAF,,,,,?,?,0x00264BD8-0x00264C13,
Xgraphics (need to decompose),false,,?,,,,,0x001BBAC0-0x001BC7BB,,,,?,?,, Xgraphics (need to decompose),false,,?,,,,,0x001BBAC0-0x001BC7BB,,,,?,?,,
XDK Peripherals (need to decompose),false,,?,,,,,,0x001BC7C0-0x001C3F57,,,?,?,, XDK Peripherals (need to decompose),false,,?,,,,,,0x001BC7C0-0x001C3F57,,,?,?,,

1 Object Delink? .text .text$yc .text$yd .text$x D3D DSOUND MMATRIX XGRPH XPP .rdata .rdata$x .data$CRT .data DOLBY
3 JSRF/GameData.obj true 0x00039B50-0x0003B937 0x0018AD60-0x0018AD75 0x0018C9A0-0x0018C9AA 0x001CA16C-0x001CA3DB 0x001EB790-0x001EB793 0x001EFC88-0x001F7047
4 JSRF/Jet2.obj true 0x0006F9E0-0x0006FA6F 0x00187710-0x00187724 0x001E620C-0x001E622F 0x0022FCE0-0x0022FCE3
5 ADX (need to decompose) false 0x0013A570-0x0014555F ? ? ? ? ? ? ?
6 XDK Core (need to decompose) Xapi (need to decompose) false 0x00145560-0x0014B79F ? ? ? ? ? ? ?
7 XDK/Xapi/xapi0.obj true 0x00147FB4-0x0014807C
8 Smilebit libs (need to decompose) false 0x0014B7A0-0x0017BF3F ? ? ? ? ? ? ?-0x0022ED2B
9 C runtime C runtime (need to decompose) false 0x0017BF40-0x00182B80 ? ? ? ? ? 0x0022ED2C-? ? ?
10 Unknown MS math lib false 0x00182B81-0x0018694F ? ? ? ? ? ? ? ?
11 Another (tiny) Smilebit math lib false 0x00186950-0x00186B7F ? ? ? ? ? ? ? ?
12 Direct3D8 (need to decompose) false ? 0x0018CB40-0x0019E334 ? ? ? ? ?
13 DirectSound8 (need to decompose) false ? ? 0x0019E340-0x001BA89B ? ? ? ? 0x0027E080-0x00284E17
14 MMatrix.obj Smilebit/MMatrix.obj false ? 0x001BA8A0-0x001BBAAF ? ? 0x00264BD8-0x00264C13
15 Xgraphics (need to decompose) false ? 0x001BBAC0-0x001BC7BB ? ?
16 XDK Peripherals (need to decompose) false ? 0x001BC7C0-0x001C3F57 ? ?

View file

@ -2,8 +2,8 @@
A matching decompilation of the Xbox game Jet Set Radio Future. A matching decompilation of the Xbox game Jet Set Radio Future.
## Progress ## Progress
- Delinking progress: 1.02% (26359 out of 2574172 bytes in XBE address space) - Delinking progress: 1.03% (26559 out of 2574172 bytes in XBE address space)
- Decompilation progress: 18.7% (31 out of the 166 functions delinked so far) - Decompilation progress: 18.5% (31 out of the 168 functions delinked so far)
- **Estimated total progress: 0.19%** (previous two multiplied together) - **Estimated total progress: 0.19%** (previous two multiplied together)
## Roadmap ## Roadmap