Compare commits

..

4 commits

Author SHA1 Message Date
KeybadeBlox
022582003d objdiff symbol matching refinements
With name mangling, objdiff.json no longer needs massive lists of which
names to match to what.  Some function signatures were also minorly
refined.
2026-02-12 21:19:46 -05:00
KeybadeBlox
d372c17094 Miscellaneous name mangling improvements
Improved error reporting, skipping undesirable symbols like jump tables,
skipping special symbols like intrinsics, etc.
2026-02-12 21:15:52 -05:00
KeybadeBlox
78127e64ef Arguments via environment variables in delink.sh
It was really annoying having to type all that in every time.
2026-02-12 16:16:07 -05:00
KeybadeBlox
13048fef71 Tidy up compiler options
Nothing affecting codegen.
2026-02-12 16:07:14 -05:00
6 changed files with 107 additions and 221 deletions

View file

@ -3,7 +3,7 @@ all: src/JSRF/Jet2.obj
# Simple inference rule for producing object files # Simple inference rule for producing object files
.SUFFIXES: .cpp .obj .SUFFIXES: .cpp .obj
.cpp.obj: .cpp.obj:
CL.EXE /nologo /Wall /TP /W3 /Ogityb0 /MT /Gf /GX /Fo$@ /c $< CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $<
# Header files used for each object # Header files used for each object
src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/Std.hpp src/XDK/D3D.hpp\ src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/Std.hpp src/XDK/D3D.hpp\

View file

@ -14,11 +14,11 @@
"source_path": "src/JSRF/Jet2.cpp" "source_path": "src/JSRF/Jet2.cpp"
}, },
"symbol_mappings": { "symbol_mappings": {
"[.rdata-0]": "[.xdata$x-0]", "?main_funcinfo@@3UFuncInfo@@A": "$T754",
"_main_funcinfo": "$T754", "?main_handler@@YAXPAUEHExceptionRecord@@PAKPAXPAU_xDISPATCHER_CONTEXT@@@Z": "$L758",
"_main_handler": "$L758", "?main_handler_unwind1@@YAXXZ": "$L750",
"_main_handler_unwind1": "$L750", "?main_unwindmap@@3PAUUnwindMapEntry@@A": "$T760",
"_main_unwindmap": "$T760" "[.rdata-0]": "[.xdata$x-0]"
} }
}, },
{ {
@ -28,94 +28,6 @@
"metadata": { "metadata": {
"complete": false, "complete": false,
"source_path": "src/JSRF/Core.cpp" "source_path": "src/JSRF/Core.cpp"
},
"symbol_mappings": {
"DrawTree::DrawTree": "??0DrawTree@@QAE@PAUGameObj@@W4GameObjIndex@@W4GameObjFlags@@@Z",
"DrawTree::`scalar_deleting_destructor'": "??_GDrawTree@@UAEPAXI@Z",
"DrawTree::copySomeVectors": "?copySomeVectors@DrawTree@@QAEXXZ",
"DrawTree::~DrawTree": "??1DrawTree@@UAE@XZ",
"Game::Game": "??0Game@@QAE@PAII@Z",
"Game::`scalar_deleting_destructor'": "??_GGame@@UAEPAXI@Z",
"Game::addToDrawList": "?addToDrawList@Game@@QAEXPAUGameObj@@@Z",
"Game::allocObjIndex": "?allocObjIndex@Game@@QAEHW4GameObjIndex@@0@Z",
"Game::appendToDrawPriorityList": "?appendToDrawPriorityList@Game@@QAEXPAUGameObj@@@Z",
"Game::clearDrawPriorityList": "?clearDrawPriorityList@Game@@QAEXXZ",
"Game::clearScreen": "?clearScreen@Game@@QAEXXZ",
"Game::draw": "?draw@Game@@QAEXXZ",
"Game::drawList": "?drawList@Game@@QAEXW4GameObjFlags@@H@Z",
"Game::drawList_": "?drawList_@Game@@QAEXW4GameObjFlags@@HH0I00@Z",
"Game::drawObj": "?drawObj@Game@@QAEXPAUGameObj@@H@Z",
"Game::drawObjs": "?drawObjs@Game@@QAEXXZ",
"Game::drawTree1": "?drawTree1@Game@@QAEXPAUGameObj@@@Z",
"Game::enableDrawChildren": "?enableDrawChildren@Game@@QAEXXZ",
"Game::enableSkipDraw": "?enableSkipDraw@Game@@QAEXXZ",
"Game::enableSomeExtraDrawListCode": "?enableSomeExtraDrawListCode@Game@@QAEXXZ",
"Game::exec": "?exec@Game@@QAEXXZ",
"Game::fatal": "?fatal@Game@@QAEXXZ",
"Game::frame": "?frame@Game@@QAEXXZ",
"Game::getDrawPriorityListHead": "?getDrawPriorityListHead@Game@@QAEPAUGameObj@@XZ",
"Game::getGlobal": "?getGlobal@Game@@QAEIW4GlobalIndex@@@Z",
"Game::getObj": "?getObj@Game@@QAEPAUGameObj@@W4GameObjIndex@@@Z",
"Game::initRootExecObj": "?initRootExecObj@Game@@QAEXXZ",
"Game::mainLoop": "?mainLoop@Game@@QAEHXZ",
"Game::objIndexAvail": "?objIndexAvail@Game@@QAEHW4GameObjIndex@@@Z",
"Game::removeFromDrawList": "?removeFromDrawList@Game@@QAEXPAUGameObj@@@Z",
"Game::setCoveredPauseNextFrame": "?setCoveredPauseNextFrame@Game@@QAEXH@Z",
"Game::setDrawMode": "?setDrawMode@Game@@QAEXW4DrawMode@@@Z",
"Game::setEventNextFrame": "?setEventNextFrame@Game@@QAEXH@Z",
"Game::setFallbackBgColour": "?setFallbackBgColour@Game@@QAEXKH@Z",
"Game::setFreezeCamNextFrame": "?setFreezeCamNextFrame@Game@@QAEXH@Z",
"Game::setGlobal": "?setGlobal@Game@@QAEXW4GlobalIndex@@I@Z",
"Game::setLogosStarted": "?setLogosStarted@Game@@QAEXH@Z",
"Game::setObj": "?setObj@Game@@QAEXW4GameObjIndex@@PAUGameObj@@@Z",
"Game::setUncoveredPauseNextFrame": "?setUncoveredPauseNextFrame@Game@@QAEXH@Z",
"Game::sortDrawPriorityList": "?sortDrawPriorityList@Game@@QAEXXZ",
"Game::sortDrawPriorityListSingleLevel": "?sortDrawPriorityListSingleLevel@Game@@QAEXD@Z",
"Game::swapObjs": "?swapObjs@Game@@QAEXW4GameObjIndex@@0@Z",
"Game::unsetObj": "?unsetObj@Game@@QAEXW4GameObjIndex@@@Z",
"Game::~Game": "??1Game@@UAE@XZ",
"GameObj::GameObj": "??0GameObj@@QAE@PAU0@W4GameObjIndex@@W4GameObjFlags@@@Z",
"GameObj::`scalar_deleting_destructor'": "??_GGameObj@@UAEPAXI@Z",
"GameObj::`vftable'": "??_7GameObj@@6B@",
"GameObj::addToSiblings": "?addToSiblings@GameObj@@QAEXPAU1@0@Z",
"GameObj::destructChildren": "?destructChildren@GameObj@@QAEXPAU1@@Z",
"GameObj::drawListCoveredPause": "?drawListCoveredPause@GameObj@@QAEXW4GameObjFlags@@HH0I00@Z",
"GameObj::drawListDefault": "?drawListDefault@GameObj@@QAEXW4GameObjFlags@@HH0I00@Z",
"GameObj::drawListEvent": "?drawListEvent@GameObj@@QAEXW4GameObjFlags@@HH0I00@Z",
"GameObj::drawListFreezeCam": "?drawListFreezeCam@GameObj@@QAEXW4GameObjFlags@@HH0I00@Z",
"GameObj::drawListUncoveredPause": "?drawListUncoveredPause@GameObj@@QAEXW4GameObjFlags@@HH0I00@Z",
"GameObj::drawTreeCoveredPause1": "?drawTreeCoveredPause1@GameObj@@QAEXXZ",
"GameObj::drawTreeCoveredPause2": "?drawTreeCoveredPause2@GameObj@@QAEXXZ",
"GameObj::drawTreeDefault1": "?drawTreeDefault1@GameObj@@QAEXXZ",
"GameObj::drawTreeDefault2": "?drawTreeDefault2@GameObj@@QAEXXZ",
"GameObj::drawTreeEvent1": "?drawTreeEvent1@GameObj@@QAEXXZ",
"GameObj::drawTreeEvent2": "?drawTreeEvent2@GameObj@@QAEXXZ",
"GameObj::drawTreeFreezeCam1": "?drawTreeFreezeCam1@GameObj@@QAEXXZ",
"GameObj::drawTreeFreezeCam2": "?drawTreeFreezeCam2@GameObj@@QAEXXZ",
"GameObj::drawTreeUncoveredPause1": "?drawTreeUncoveredPause1@GameObj@@QAEXXZ",
"GameObj::drawTreeUncoveredPause2": "?drawTreeUncoveredPause2@GameObj@@QAEXXZ",
"GameObj::getParent": "?getParent@GameObj@@QAEPAU1@XZ",
"GameObj::nopDraw": "?drawDefault@GameObj@@UAEXH@Z",
"GameObj::nopExec": "?execDefault@GameObj@@UAEXXZ",
"GameObj::recursiveExecCoveredPause": "?recursiveExecCoveredPause@GameObj@@QAEXXZ",
"GameObj::recursiveExecDefault": "?recursiveExecDefault@GameObj@@QAEXXZ",
"GameObj::recursiveExecEvent": "?recursiveExecEvent@GameObj@@QAEXXZ",
"GameObj::recursiveExecFreezeCam": "?recursiveExecFreezeCam@GameObj@@QAEXXZ",
"GameObj::recursiveExecUncoveredPause": "?recursiveExecUncoveredPause@GameObj@@QAEXXZ",
"GameObj::recursivePostExecCoveredPause": "?recursivePostExecCoveredPause@GameObj@@QAEXXZ",
"GameObj::recursivePostExecDefault": "?recursivePostExecDefault@GameObj@@QAEXXZ",
"GameObj::recursivePostExecEvent": "?recursivePostExecEvent@GameObj@@QAEXXZ",
"GameObj::recursivePostExecFreezeCam": "?recursivePostExecFreezeCam@GameObj@@QAEXXZ",
"GameObj::recursivePostExecUncoveredPause": "?recursivePostExecUncoveredPause@GameObj@@QAEXXZ",
"GameObj::removeChildrenFromObjList": "?removeChildrenFromObjList@GameObj@@QAEXPAU1@@Z",
"GameObj::removeFromObjList": "?removeFromObjList@GameObj@@QAEXPAU1@@Z",
"GameObj::setParent": "?setParent@GameObj@@QAEXPAU1@@Z",
"GameObj::~GameObj": "??1GameObj@@UAE@XZ",
"PlayerObj::PlayerObj": "??0PlayerObj@@QAE@PAUGameObj@@W4GameObjIndex@@W4GameObjFlags@@@Z",
"RootExecObj::RootExecObj": "??0RootExecObj@@QAE@PAUGameObj@@W4GameObjIndex@@W4GameObjFlags@@@Z",
"RootExecObj::`scalar_deleting_destructor'": "??_GRootExecObj@@UAEPAXI@Z",
"RootExecObj::~RootExecObj": "??1RootExecObj@@UAE@XZ",
"removeFromObjListByIndex": "?removeFromObjListByIndex@@YAXW4GameObjIndex@@@Z"
} }
}, },
{ {
@ -127,75 +39,9 @@
"source_path": "src/JSRF/GameData.cpp" "source_path": "src/JSRF/GameData.cpp"
}, },
"symbol_mappings": { "symbol_mappings": {
"GameData::GameData": "??0GameData@@QAE@XZ", "?finalizeGameData@@YAXXZ": "_$E2",
"GameData::`scalar_deleting_destructor'": "??_GGameData@@UAEPAXI@Z", "?initGameData@@YGXXZ": "_$E1"
"GameData::addHighScore": "?addHighScore@GameData@@QAEXIW4TestRunType@@PAUTestRunScore@@@Z",
"GameData::characterUnlocked": "?characterUnlocked@GameData@@QAEHI@Z",
"GameData::checkFlagCondition": "?checkFlagCondition@GameData@@QAEHI@Z",
"GameData::checkFlagConditionUnpacked": "?checkFlagConditionUnpacked@GameData@@QAEHW4FlagList@@I@Z",
"GameData::checkFlagConditions": "?checkFlagConditions@GameData@@QAEHPAII@Z",
"GameData::clearHeldSouls": "?clearHeldSouls@GameData@@QAEXXZ",
"GameData::clearStateFlags": "?clearStateFlags@GameData@@QAEXTFlagListOrPtr@@@Z",
"GameData::countMiscObjectives": "?countMiscObjectives@GameData@@QAEIXZ",
"GameData::decrypt": "?decrypt@GameData@@QAEHPAD@Z",
"GameData::encrypt": "?encrypt@GameData@@QAEXPAD@Z",
"GameData::eventSeen": "?eventSeen@GameData@@QAEHI@Z",
"GameData::getCustomTagSelected": "?getCustomTagSelected@GameData@@QAEHIW4TagSize@@H@Z",
"GameData::getGarageMusic": "?getGarageMusic@GameData@@QAEIXZ",
"GameData::getHeldSoulsInStage": "?getHeldSoulsInStage@GameData@@QAEII@Z",
"GameData::getHighScore": "?getHighScore@GameData@@QAEHIW4TestRunType@@IPAUTestRunScore@@@Z",
"GameData::getMiscObjective": "?getMiscObjective@GameData@@QAEHI@Z",
"GameData::getRumbleEnabled": "?getRumbleEnabled@GameData@@QAEHXZ",
"GameData::getSaveDataSize": "?getSaveDataSize@GameData@@QAEIXZ",
"GameData::getSaveDescription": "?getSaveDescription@GameData@@QAEXPAUSaveDescription@@@Z",
"GameData::getSelectedTag": "?getSelectedTag@GameData@@QAEIIW4TagSize@@H@Z",
"GameData::getSoulCollectedBySize": "?getSoulCollectedBySize@GameData@@QAEHW4TagSize@@I@Z",
"GameData::getSoulCount": "?getSoulCount@GameData@@QAEIXZ",
"GameData::getSoulHeld": "?getSoulHeld@GameData@@QAEHI@Z",
"GameData::getSoulSpawned": "?getSoulSpawned@GameData@@QAEHI@Z",
"GameData::getSpawnPosIndex": "?getSpawnPosIndex@GameData@@QAEIXZ",
"GameData::getTagState": "?getTagState@GameData@@QAEHIIH@Z",
"GameData::getTimer": "?getTimer@GameData@@QAEIW4Timer@@@Z",
"GameData::getTotalSoulsInStage": "?getTotalSoulsInStage@GameData@@QAEII@Z",
"GameData::getVolumeSettings": "?getVolumeSettings@GameData@@QAEXPAM0@Z",
"GameData::incrementChapter": "?incrementChapter@GameData@@QAEXXZ",
"GameData::incrementPlaytime": "?incrementPlaytime@GameData@@QAEXXZ",
"GameData::incrementTimer": "?incrementTimer@GameData@@QAEXW4Timer@@@Z",
"GameData::lockCharacter": "?lockCharacter@GameData@@QAEXI@Z",
"GameData::resetExceptSettings": "?resetExceptSettings@GameData@@QAEXXZ",
"GameData::resetExceptSettingsAndHighScores": "?resetExceptSettingsAndHighScores@GameData@@QAEXXZ",
"GameData::resetExceptSettingsAndSouls": "?resetExceptSettingsAndSouls@GameData@@QAEXXZ",
"GameData::resetSelectedTags": "?resetSelectedTags@GameData@@QAEXXZ",
"GameData::resetTimer": "?resetTimer@GameData@@QAEXW4Timer@@@Z",
"GameData::restoreHeldSouls": "?restoreHeldSouls@GameData@@QAEXXZ",
"GameData::setCustomTagSelected": "?setCustomTagSelected@GameData@@QAEXIW4TagSize@@HH@Z",
"GameData::setEventSeen": "?setEventSeen@GameData@@QAEXI@Z",
"GameData::setGarageMusic": "?setGarageMusic@GameData@@QAEXI@Z",
"GameData::setMiscObjective": "?setMiscObjective@GameData@@QAEXI@Z",
"GameData::setMissionDigits34": "?setMissionDigits34@GameData@@QAEXI@Z",
"GameData::setRumbleEnabled": "?setRumbleEnabled@GameData@@QAEXH@Z",
"GameData::setSelectedTag": "?setSelectedTag@GameData@@QAEXIW4TagSize@@IH@Z",
"GameData::setSoulCollected": "?setSoulCollected@GameData@@QAEXI@Z",
"GameData::setSoulSpawned": "?setSoulSpawned@GameData@@QAEXI@Z",
"GameData::setSpawnPosIndex": "?setSpawnPosIndex@GameData@@QAEXI@Z",
"GameData::setTagCovered": "?setTagCovered@GameData@@QAEXIIHI@Z",
"GameData::setTagState": "?setTagState@GameData@@QAEXIIHI@Z",
"GameData::setTimer": "?setTimer@GameData@@QAEXW4Timer@@I@Z",
"GameData::setUnusedBitfield": "?setUnusedBitfield@GameData@@QAEXI@Z",
"GameData::setUnusedPerStageBitmask": "?setUnusedPerStageBitmask@GameData@@QAEXII@Z",
"GameData::setVolumeSettings": "?setVolumeSettings@GameData@@QAEXMM@Z",
"GameData::soulSpawnedUncollected": "?soulSpawnedUncollected@GameData@@QAEHI@Z",
"GameData::stash": "?stash@GameData@@QAEXXZ",
"GameData::stashRestore": "?stashRestore@GameData@@QAEXXZ",
"GameData::stashRestoreExceptHighScores": "?stashRestoreExceptHighScores@GameData@@QAEXXZ",
"GameData::stashRestoreExceptSpecialFlags": "?stashRestoreExceptSpecialFlags@GameData@@QAEXXZ",
"GameData::unlockCharacter": "?unlockCharacter@GameData@@QAEXI@Z",
"GameData::writeStateFlag": "?writeStateFlag@GameData@@QAEXI@Z",
"GameData::writeStateFlagUnpacked": "?writeStateFlagUnpacked@GameData@@QAEXW4FlagList@@II@Z",
"GameData::writeStateFlags": "?writeStateFlags@GameData@@QAEXPAII@Z",
"finalizeGameData": "_$E2",
"initGameData": "_$E1"
} }
} }
] ]
} }

View file

@ -196,7 +196,7 @@ void GameObj::removeChildrenFromObjList(GameObj * firstChild) {
// Address: 0x00011C80 // Address: 0x00011C80
// Matching: yes // Matching: yes
void GameObj::drawDefault(int unknown) {} void GameObj::drawDefault(unsigned unknown) {}
// Address: 0x00011C90 // Address: 0x00011C90
// Matching: yes // Matching: yes
@ -212,7 +212,7 @@ void GameObj::execEvent() {}
void GameObj::postExecEvent() {} void GameObj::postExecEvent() {}
// Eliminated by link time code generation (aliased with 0x00011C80) // Eliminated by link time code generation (aliased with 0x00011C80)
void GameObj::drawEvent(int unknown) {} void GameObj::drawEvent(unsigned unknown) {}
// Eliminated by link time code generation (aliased with 0x00011C90) // Eliminated by link time code generation (aliased with 0x00011C90)
void GameObj::execCoveredPause() {} void GameObj::execCoveredPause() {}
@ -221,7 +221,7 @@ void GameObj::execCoveredPause() {}
void GameObj::postExecCoveredPause() {} void GameObj::postExecCoveredPause() {}
// Eliminated by link time code generation (aliased with 0x00011C80) // Eliminated by link time code generation (aliased with 0x00011C80)
void GameObj::drawCoveredPause(int unknown) {} void GameObj::drawCoveredPause(unsigned unknown) {}
// Eliminated by link time code generation (aliased with 0x00011C90) // Eliminated by link time code generation (aliased with 0x00011C90)
void GameObj::execFreezeCam() {} void GameObj::execFreezeCam() {}
@ -230,7 +230,7 @@ void GameObj::execFreezeCam() {}
void GameObj::postExecFreezeCam() {} void GameObj::postExecFreezeCam() {}
// Eliminated by link time code generation (aliased with 0x00011C80) // Eliminated by link time code generation (aliased with 0x00011C80)
void GameObj::drawFreezeCam(int unknown) {} void GameObj::drawFreezeCam(unsigned unknown) {}
// Eliminated by link time code generation (aliased with 0x00011C90) // Eliminated by link time code generation (aliased with 0x00011C90)
void GameObj::execUncoveredPause() {} void GameObj::execUncoveredPause() {}
@ -239,7 +239,7 @@ void GameObj::execUncoveredPause() {}
void GameObj::postExecUncoveredPause() {} void GameObj::postExecUncoveredPause() {}
// Eliminated by link time code generation (aliased with 0x00011C80) // Eliminated by link time code generation (aliased with 0x00011C80)
void GameObj::drawUncoveredPause(int unknown) {} void GameObj::drawUncoveredPause(unsigned unknown) {}
// Address: 0x00011CA0 // Address: 0x00011CA0
// Matching: no // Matching: no
@ -336,7 +336,7 @@ void Game::exec() {
// Address: 0x00012580 // Address: 0x00012580
// Matching: no // Matching: no
void Game::drawObj(GameObj * obj, int unknown) { void Game::drawObj(GameObj * obj, unsigned unknown) {
} }
// Address: 0x000125E0 // Address: 0x000125E0
@ -510,7 +510,7 @@ void Game::appendToDrawPriorityList(GameObj * obj) {
// Address: 0x00012A20 // Address: 0x00012A20
// Matching: no // Matching: no
void Game::sortDrawPriorityListSingleLevel(char sortKeyBitOffset) { void Game::sortDrawPriorityListSingleLevel(unsigned char sortKeyBitOffset) {
for ( for (
unsigned i = 0; unsigned i = 0;
i < sizeof this->drawPriorityListsByKeyHeads/sizeof *this->drawPriorityListsByKeyHeads; i < sizeof this->drawPriorityListsByKeyHeads/sizeof *this->drawPriorityListsByKeyHeads;

View file

@ -146,23 +146,23 @@ struct GameObj {
// frame. // frame.
virtual void execDefault(); virtual void execDefault();
virtual void postExecDefault(); virtual void postExecDefault();
virtual void drawDefault(int); virtual void drawDefault(unsigned);
virtual void execEvent(); virtual void execEvent();
virtual void postExecEvent(); virtual void postExecEvent();
virtual void drawEvent(int); virtual void drawEvent(unsigned);
virtual void execCoveredPause(); virtual void execCoveredPause();
virtual void postExecCoveredPause(); virtual void postExecCoveredPause();
virtual void drawCoveredPause(int); virtual void drawCoveredPause(unsigned);
virtual void execFreezeCam(); virtual void execFreezeCam();
virtual void postExecFreezeCam(); virtual void postExecFreezeCam();
virtual void drawFreezeCam(int); virtual void drawFreezeCam(unsigned);
virtual void execUncoveredPause(); virtual void execUncoveredPause();
virtual void postExecUncoveredPause(); virtual void postExecUncoveredPause();
virtual void drawUncoveredPause(int); virtual void drawUncoveredPause(unsigned);
void recursivePostExecDefault(); void recursivePostExecDefault();
void recursivePostExecEvent(); void recursivePostExecEvent();
@ -297,7 +297,7 @@ struct Game {
Game(unsigned *, unsigned); Game(unsigned *, unsigned);
virtual ~Game(); virtual ~Game();
void exec(); void exec();
void drawObj(GameObj * obj, int); void drawObj(GameObj * obj, unsigned);
void drawList_( void drawList_(
GameObjFlags flagFilterAny1, GameObjFlags flagFilterAny1,
int drawArg1, int drawArg1,
@ -339,7 +339,7 @@ struct Game {
void clearDrawPriorityList(); void clearDrawPriorityList();
GameObj * getDrawPriorityListHead(); GameObj * getDrawPriorityListHead();
void appendToDrawPriorityList(GameObj * obj); void appendToDrawPriorityList(GameObj * obj);
void sortDrawPriorityListSingleLevel(char sortKeyBitOffset); void sortDrawPriorityListSingleLevel(unsigned char sortKeyBitOffset);
void setFallbackBgColour(D3DCOLOR colour, BOOL useFallback); void setFallbackBgColour(D3DCOLOR colour, BOOL useFallback);
void initRootExecObj(); void initRootExecObj();

View file

@ -3,11 +3,21 @@
# objects.csv and a Ghidra project via boricj's delinker extension # objects.csv and a Ghidra project via boricj's delinker extension
main() { main() {
if [ $# -ne 3 ]; then usage; fi if \
[ $# -eq 0 ] &&\
ghidra_path=$1 [ -n "${GHIDRA_HOME-}" ] &&\
project_path=$2 [ -n "${JSRFDECOMP_PROJECTPATH-}" ] &&\
project_name=$3 [ -n "${JSRFDECOMP_PROJECTNAME-}" ]
then
ghidra_path=$GHIDRA_HOME
project_path=$JSRFDECOMP_PROJECTPATH
project_name=$JSRFDECOMP_PROJECTNAME
elif [ $# -eq 3 ]; then
ghidra_path=$1
project_path=$2
project_name=$3
else usage
fi
printf '=== Delinking object files into ../decompile/target/ ===\n' printf '=== Delinking object files into ../decompile/target/ ===\n'
@ -39,6 +49,9 @@ usage() {
' GHIDRA_PATH is the path to your Ghidra installation'\ ' GHIDRA_PATH is the path to your Ghidra installation'\
' PROJECT_PATH is the path to your JSRF Ghidra project'\ ' PROJECT_PATH is the path to your JSRF Ghidra project'\
' PROJECT_NAME is the name of your JSRF Ghidra project'\ ' PROJECT_NAME is the name of your JSRF Ghidra project'\
'Alternatively, the environment variables $GHIDRA_HOME, $JSRFDECOMP_PROJECTPATH,'\
'and $JSRFDECOMP_PROJECTNAME can be set, and the script can be called with no'\
'arguments.'\
''\ ''\
'Populates the target/ directory with delinked object files using the address'\ 'Populates the target/ directory with delinked object files using the address'\
'ranges given in objects.csv.' >& 2 'ranges given in objects.csv.' >& 2

View file

@ -107,7 +107,10 @@ public class MSVC7Mangle extends GhidraScript{
final Reference[] refs = ins.getReferencesFrom(); final Reference[] refs = ins.getReferencesFrom();
for (int i = 0; i < refs.length; i++) { for (int i = 0; i < refs.length; i++) {
final Symbol symbol = getSymbolAt(refs[i].getToAddress()); final Symbol symbol = getSymbolAt(refs[i].getToAddress());
if (symbol != null) mangle(symbol); if ( // Guard against spurious references to nonexisting things
symbol != null &&
symbol.getObject() != null
) mangle(symbol);
} }
} }
} }
@ -116,13 +119,17 @@ public class MSVC7Mangle extends GhidraScript{
private void mangle(final Symbol s) throws Exception { private void mangle(final Symbol s) 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 if already mangled; skip jump tables
if (s.getName().charAt(0) == '?') return; final String name = s.getName(true);
if (
name.charAt(0) == '?' ||
name.startsWith("switchD_")
) return;
// 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);
case Data d -> mangleData(d, s.getName(true)); case Data d -> mangleData(d, name);
default -> null; default -> null;
}; };
@ -145,17 +152,21 @@ public class MSVC7Mangle extends GhidraScript{
private String mangleFn(final Function f) throws Exception { private String mangleFn(final Function f) throws Exception {
/* Generate a mangled name for a function */ /* Generate a mangled name for a function */
// Special cases for main() final String nameRaw = f.getName(true);
if (f.getName(true).equals("main" )) return "_main";
if (f.getName(true).equals("___CxxFrameHandler")) return "___CxxFrameHandler"; // Special case for main()
if (nameRaw.equals("main")) return "_main";
// Special symbols like intrinsics aren't mangled
if (nameRaw.startsWith("__")) return nameRaw;
final ArrayList<String> dict = new ArrayList<>(); final ArrayList<String> dict = new ArrayList<>();
final List<String> nameParts = Arrays.asList(f.getName(true).split("::")); final List<String> nameParts = Arrays.asList(nameRaw.split("::"));
Collections.reverse(nameParts); Collections.reverse(nameParts);
final boolean isMethod = f.getCallingConventionName().equals("__thiscall") && final boolean isMethod = f.getCallingConventionName().equals("__thiscall") &&
nameParts.size() >= 2; nameParts.size() >= 2;
final String name = mangleIdentifier(f.getName(true), isMethod, f.getReturnType(), dict); final String name = mangleIdentifier(nameRaw, isMethod, f.getReturnType(), dict);
// Special methods with unique formats // Special methods with unique formats
if (isMethod) { if (isMethod) {
@ -163,14 +174,16 @@ public class MSVC7Mangle extends GhidraScript{
final String clsName = nameParts.get(1); final String clsName = nameParts.get(1);
if (unqualified.equals( clsName)) { // Constructor if (unqualified.equals( clsName)) { // Constructor
return "?" + name + "QAE@" + mangleArgs(f.getSignature(true), dict) + "Z"; return "?" + name + "QAE@" +
mangleArgs(f.getSignature(true), dict, nameRaw + "()") +
"Z";
} else if (unqualified.equals("~" + clsName)) { // Destructor } else if (unqualified.equals("~" + clsName)) { // Destructor
return "?" + name + (isVirtual(f) ? "UAE" : "QAE") + "@XZ"; return "?" + name + (isVirtual(f) ? "UAE" : "QAE") + "@XZ";
} }
} }
return "?" + name + mangleFnAttrs(f, nameParts) + return "?" + name + mangleFnAttrs(f, nameParts) +
mangleFnType(f.getSignature(true), dict); mangleFnType(f.getSignature(true), dict, nameRaw + "()");
} }
private static String mangleIdentifier( private static String mangleIdentifier(
@ -272,7 +285,9 @@ public class MSVC7Mangle extends GhidraScript{
final List<T> dict final List<T> dict
) { ) {
/* Produce a backreference string if x is found in dict */ /* Produce a backreference string if x is found in dict */
switch (Integer.valueOf(dict.indexOf(x))) { if (x instanceof String s && s.startsWith("?"))
return Optional.empty(); // No matching special names
else switch (Integer.valueOf(dict.indexOf(x))) {
case -1: case -1:
dict.add(x); dict.add(x);
return Optional.empty(); return Optional.empty();
@ -303,12 +318,15 @@ public class MSVC7Mangle extends GhidraScript{
final Function func = getFunctionContaining(refs[i].getFromAddress()); final Function func = getFunctionContaining(refs[i].getFromAddress());
if (data != null) { if (data != null) {
final String name = getSymbolAt(data.getRoot() final Symbol s = getSymbolAt(data.getRoot()
.getAddress()).getName(false); .getAddress());
if ( if (s != null) {
name.equals("`vftable'") || final String name = s.getName(false);
name.startsWith("??_7") if (
) return true; name.equals("`vftable'") ||
name.startsWith("??_7")
) return true;
}
} else if (func != null) { } else if (func != null) {
final String name = func.getName(false); final String name = func.getName(false);
if ( if (
@ -334,12 +352,13 @@ public class MSVC7Mangle extends GhidraScript{
private static String mangleFnType( private static String mangleFnType(
final FunctionSignature f, final FunctionSignature f,
final List<String> dict final List<String> dict,
final String loc
) throws Exception { ) throws Exception {
/* Mangle everything in f but its name and visibility/linkage */ /* Mangle everything in f but its name and visibility/linkage */
return mangleCallC(f) +
return mangleCallC(f) + mangleType(f.getReturnType(), dict) + mangleType(f.getReturnType(), dict, loc) +
mangleArgs(f, dict) + "Z"; mangleArgs(f, dict, loc) + "Z";
} }
private static String mangleCallC(final FunctionSignature f) throws Exception { private static String mangleCallC(final FunctionSignature f) throws Exception {
@ -358,15 +377,16 @@ public class MSVC7Mangle extends GhidraScript{
private static String mangleType( private static String mangleType(
final DataType t, final DataType t,
final List<String> dict final List<String> dict,
final String loc
) throws Exception { ) throws Exception {
/* Mangle a data type in a function name /* Mangle a data type in a function name
All types are assumed to have no CV qualifiers. All types are assumed to have no CV qualifiers.
*/ */
if (t == null) throw new Exception ( if (t == null) throw new Exception (
"A data type was reported as null. Ensure that all " + "A data type at " + loc + " was reported as null. " +
"data types in the code/data to mangle have been " + "Ensure that all data types in the code/data to " +
"defined." "mangle have been defined."
); );
return switch(t) { return switch(t) {
@ -384,7 +404,7 @@ public class MSVC7Mangle extends GhidraScript{
case LongDoubleDataType _ -> "O"; case LongDoubleDataType _ -> "O";
case Pointer p -> "P" + case Pointer p -> "P" +
(p.getDataType() instanceof FunctionSignature ? "6" : "A") + (p.getDataType() instanceof FunctionSignature ? "6" : "A") +
mangleType(p.getDataType(), dict); mangleType(p.getDataType(), dict, loc);
case Union u -> "T" + mangleIdentifier(u.getName(), false, null, dict); case Union u -> "T" + mangleIdentifier(u.getName(), false, null, dict);
case Structure s -> "U" + mangleIdentifier(s.getName(), false, null, dict); case Structure s -> "U" + mangleIdentifier(s.getName(), false, null, dict);
case Enum e -> "W4" + mangleIdentifier(e.getName(), false, null, dict); case Enum e -> "W4" + mangleIdentifier(e.getName(), false, null, dict);
@ -393,12 +413,12 @@ public class MSVC7Mangle extends GhidraScript{
case UnsignedLongLongDataType _ -> "_K"; case UnsignedLongLongDataType _ -> "_K";
case BooleanDataType _ -> "_N"; case BooleanDataType _ -> "_N";
case WideCharDataType _ -> "_W"; case WideCharDataType _ -> "_W";
case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict); case Array a -> "PA" + mangleArrDims(a) + mangleType(arrType(a), dict, loc);
case FunctionSignature f -> mangleFnType(f, dict); case FunctionSignature f -> mangleFnType(f, dict, "function typedef \"" + f.getName() + "\"");
case TypeDef d -> mangleType(d.getBaseDataType(), dict); case TypeDef d -> mangleType(d.getBaseDataType(), dict, "typedef \"" + d.getName() + "\"");
case DefaultDataType _ -> throw new Exception ("Encountered data marked \"undefined\". Ensure that all data types in the code/data to mangle have been defined."); case DefaultDataType _ -> throw new Exception ("Encountered data marked \"undefined\" at " + loc + ". Ensure that all data types in the code/data to mangle have been defined.");
case Undefined _ -> throw new Exception ("Encountered data marked \"undefined\". Ensure that all data types in the code/data to mangle have been defined."); case Undefined _ -> throw new Exception ("Encountered data marked \"undefined\" at " + loc + ". Ensure that all data types in the code/data to mangle have been defined.");
default -> throw new Exception ("Unknown type \"" + t.getClass().getName() + "\""); default -> throw new Exception ("Unknown type \"" + t.getClass().getName() + "\" at " + loc);
}; };
} }
@ -446,7 +466,8 @@ public class MSVC7Mangle extends GhidraScript{
private static String mangleArgs( private static String mangleArgs(
final FunctionSignature f, final FunctionSignature f,
final List<String> dict final List<String> dict,
final String loc
) throws Exception { ) throws Exception {
/* Mangle the arguments for a function */ /* Mangle the arguments for a function */
final DataType[] args = Arrays.stream(f.getArguments()) final DataType[] args = Arrays.stream(f.getArguments())
@ -469,10 +490,15 @@ public class MSVC7Mangle extends GhidraScript{
// It turns out that academic-sounding stuff everyone // It turns out that academic-sounding stuff everyone
// freaks out at is actually useful (and Optional still // freaks out at is actually useful (and Optional still
// helped us out here) // helped us out here)
String mangled = ""; String mangledArgs = "";
for (int i = 0; i < args.length; i++) for (int i = 0; i < args.length; i++) {
mangled += backref(args[i], argDict).orElse(mangleType(args[i], dict)); final String mangledArg = mangleType(args[i], dict, loc);
return mangled + (f.hasVarArgs() ? "Z" : "@");
mangledArgs += mangledArg.length() == 1 ?
mangledArg :
backref(args[i], argDict).orElse(mangledArg);
}
return mangledArgs + (f.hasVarArgs() ? "Z" : "@");
} }
} }
@ -495,7 +521,8 @@ public class MSVC7Mangle extends GhidraScript{
// vtable // vtable
if (ident.startsWith("?_7")) return "?" + ident + "6B@"; if (ident.startsWith("?_7")) return "?" + ident + "6B@";
return "?" + ident + "3" + mangleType(d.getDataType(), dict) + return "?" + ident + "3" +
mangleType(d.getDataType(), dict, "0x" + d.getAddress().toString()) +
"A"; "A";
} }