mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
295 lines
8.1 KiB
C++
295 lines
8.1 KiB
C++
// MAP maker utility
|
|
#include "pch.h"
|
|
|
|
typedef struct opMarker {
|
|
uint32_t offset;
|
|
bool blr;
|
|
} opMarker;
|
|
|
|
typedef struct funcDesc {
|
|
uint32_t checksum;
|
|
uint32_t nameoffset;
|
|
} funcDesc;
|
|
|
|
FILE *Map;
|
|
|
|
opMarker * Map_marks;
|
|
int Map_marksSize, Map_marksMaxSize;
|
|
|
|
std::vector<uint8_t> temp;
|
|
uint8_t * Map_buffer;
|
|
int Map_functionsSize;
|
|
funcDesc * Map_functions;
|
|
char * Map_functionsNamesTable;
|
|
|
|
#define MAPDAT_FILE "./Data/makemap.dat"
|
|
#define MAP_MAXFUNCNAME 100
|
|
|
|
/*
|
|
* Allocates more space for the markers array
|
|
*/
|
|
static void MAPGrow (int num)
|
|
{
|
|
Map_marksMaxSize += num;
|
|
Map_marks = (opMarker *)realloc(Map_marks, Map_marksMaxSize * sizeof(opMarker));
|
|
}
|
|
|
|
/*
|
|
* Calculates a custom Checksum for a range of opcodes
|
|
*/
|
|
static uint32_t MAPFuncChecksum (uint32_t offsetStart, uint32_t offsetEnd)
|
|
{
|
|
uint32_t sum = 0, offset;
|
|
uint32_t opcode, auxop, op, op2, op3;
|
|
|
|
for (offset = offsetStart; offset <= offsetEnd; offset+=4) {
|
|
opcode = _BYTESWAP_UINT32(*((uint32_t *)&mi.ram[offset & RAMMASK]));
|
|
op = opcode & 0xFC000000;
|
|
op2 = 0;
|
|
op3 = 0;
|
|
auxop = op >> 26;
|
|
switch (auxop) {
|
|
case 4:
|
|
op2 = opcode & 0x0000003F;
|
|
switch ( op2 ) {
|
|
case 0:
|
|
case 8:
|
|
case 16:
|
|
case 21:
|
|
case 22:
|
|
op3 = opcode & 0x000007C0;
|
|
}
|
|
break;
|
|
case 19:
|
|
case 31:
|
|
case 63:
|
|
op2 = opcode & 0x000007FF;
|
|
break;
|
|
case 59:
|
|
op2 = opcode & 0x0000003F;
|
|
if ( op2 < 16 )
|
|
op3 = opcode & 0x000007C0;
|
|
break;
|
|
}
|
|
// Checksum only uses opcode, not opcode data, because opcode data changes
|
|
// in all compilations, but opcodes dont!
|
|
sum = ( ( (sum << 17 ) & 0xFFFE0000 ) | ( (sum >> 15) & 0x0001FFFF ) );
|
|
sum = sum ^ (op | op2 | op3);
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
/*
|
|
* Open the file with the information about common recognized functions
|
|
*/
|
|
static void MAPOpen ()
|
|
{
|
|
temp = Util::FileLoad((std::string)MAPDAT_FILE);
|
|
|
|
Map_buffer = temp.data();
|
|
if (Map_buffer == NULL) return;
|
|
Map_functionsSize = *(uint32_t *)(Map_buffer);
|
|
Map_functions = (funcDesc *)(Map_buffer + sizeof(uint32_t));
|
|
Map_functionsNamesTable = (char *)((char *)Map_functions
|
|
+ Map_functionsSize * sizeof(funcDesc));
|
|
|
|
/*
|
|
// This just prints a list of all the common functions
|
|
FILE *f = fopen(MAPDAT_FILE ".txt", "w");
|
|
fprintf(f, "[%08x]\n",Map_functionsSize);
|
|
for (int i = 0; i < Map_functionsSize; i++)
|
|
fprintf(f, "[%08x][%s]\n",Map_functions[i].checksum,
|
|
&Map_functionsNamesTable[Map_functions[i].nameoffset] );
|
|
fclose ( f ) ;
|
|
*/
|
|
}
|
|
|
|
static void MAPClose ()
|
|
{
|
|
if (Map_buffer == NULL) return;
|
|
|
|
Map_buffer = NULL;
|
|
Map_functionsSize = 0;
|
|
Map_functions = NULL;
|
|
Map_functionsNamesTable = NULL;
|
|
}
|
|
|
|
static char * MAPFind (uint32_t checksum)
|
|
{
|
|
int inf, med, sup;
|
|
if (Map_buffer == NULL) return NULL;
|
|
|
|
inf = 0;
|
|
sup = Map_functionsSize - 1;
|
|
while (inf <= sup) {
|
|
med = (inf + sup) / 2;
|
|
if (Map_functions[med].checksum == checksum)
|
|
return &Map_functionsNamesTable[Map_functions[med].nameoffset];
|
|
if (checksum < Map_functions[med].checksum)
|
|
sup = med - 1;
|
|
else
|
|
inf = med + 1;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Starts the creation of a new map
|
|
*/
|
|
void MAPInit(const wchar_t * mapname)
|
|
{
|
|
MAPOpen ();
|
|
Map = fopen( Util::WstringToString(mapname).c_str(), "w");
|
|
|
|
Map_marksMaxSize = 500;
|
|
Map_marksSize = 0;
|
|
Map_marks = (opMarker *)malloc(Map_marksMaxSize * sizeof(opMarker));
|
|
}
|
|
|
|
/*
|
|
* Adds a mark to the opcode at the specified offset.
|
|
* if blr is false, the mark is considerated an entrypoint to a function
|
|
* if blr is not false, the mark is considerated an exitpoint from the function
|
|
* Use carefully!!!
|
|
*/
|
|
void MAPAddMark (uint32_t offset, bool blr)
|
|
{
|
|
int inf, med, sup;
|
|
|
|
if (!Map) return ;
|
|
if (Map_marksSize == Map_marksMaxSize) MAPGrow ( 500 ) ;
|
|
|
|
inf = 0;
|
|
sup = Map_marksSize - 1;
|
|
while (inf <= sup) {
|
|
med = (inf + sup) / 2;
|
|
if (Map_marks[med].offset == offset) return;
|
|
if (offset < Map_marks[med].offset)
|
|
sup = med - 1;
|
|
else
|
|
inf = med + 1;
|
|
}
|
|
|
|
for (sup = Map_marksSize; inf < sup; sup--)
|
|
Map_marks[sup] = Map_marks[sup - 1];
|
|
Map_marks[inf].offset = offset;
|
|
Map_marks[inf].blr = blr;
|
|
Map_marksSize++;
|
|
|
|
}
|
|
|
|
/*
|
|
* Checks the specified range, and automatically adds marks to entry and exit points to functions.
|
|
*/
|
|
void MAPAddRange (uint32_t offsetStart, uint32_t offsetEnd)
|
|
{
|
|
uint32_t opcode;
|
|
uint32_t target;
|
|
uint32_t op, op2;
|
|
|
|
if (!Map) return ;
|
|
if (!Map_marks) return ;
|
|
|
|
MAPAddMark (offsetStart, false);
|
|
while(offsetStart < offsetEnd) {
|
|
|
|
opcode = _BYTESWAP_UINT32(*((uint32_t *)&mi.ram[offsetStart & RAMMASK]));
|
|
op = opcode >> 26, op2 = 0;
|
|
|
|
switch (op) {
|
|
case 18: //bl and bla
|
|
switch(opcode & 3) {
|
|
case 1:
|
|
case 3:
|
|
target = opcode & 0x03fffffc;
|
|
if(target & 0x02000000) target |= 0xfc000000;
|
|
if ((opcode & 3) == 1) target += offsetStart;
|
|
MAPAddMark(target, false);
|
|
break;
|
|
}
|
|
break;
|
|
case 19: //OP2
|
|
op2 = opcode & 0x7ff;
|
|
switch(op2) {
|
|
case 32:
|
|
case 33:
|
|
case 100:
|
|
MAPAddMark (offsetStart, true);
|
|
}
|
|
break;
|
|
}
|
|
offsetStart += 4;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Finishes the creation of the current map
|
|
*/
|
|
void MAPFinish()
|
|
{
|
|
int i, k;
|
|
uint32_t Checksum;
|
|
char * name, namebuf[MAP_MAXFUNCNAME];
|
|
size_t namelen;
|
|
|
|
if (!Map) return ;
|
|
|
|
memset ( namebuf, 0, MAP_MAXFUNCNAME );
|
|
|
|
i = 0;
|
|
while (i < Map_marksSize - 1) {
|
|
// find start of function
|
|
while (Map_marks[i].blr && i < Map_marksSize) i++;
|
|
while (i < Map_marksSize - 1 && Map_marks[i+1].blr == false) i++;
|
|
// find end of function
|
|
for ( k = i + 1; k < Map_marksSize - 1 && Map_marks[k+1].blr; k++);
|
|
|
|
if (i < Map_marksSize && k < Map_marksSize &&
|
|
Map_marks[i].blr == false && Map_marks[k].blr) {
|
|
|
|
// look if the function is HLE
|
|
Checksum = MAPFuncChecksum (Map_marks[i].offset , Map_marks[k].offset);
|
|
name = MAPFind (Checksum) ;
|
|
|
|
if (name != NULL) {
|
|
char buf[16], *nameptr;
|
|
nameptr = strchr(name, ',');
|
|
if (nameptr != NULL) {
|
|
// if the function name contains at least a comma, it means that
|
|
// it shares the same checksum with another function.
|
|
// Nothing else can be done to identify this function
|
|
name = buf;
|
|
sprintf (buf, "[0x%08x]", Checksum);
|
|
}
|
|
|
|
// show status
|
|
{
|
|
wchar_t wideName[0x100] = { 0, };
|
|
|
|
wchar_t* wideNamePtr = wideName;
|
|
char* namePtr = name;
|
|
while (*namePtr)
|
|
{
|
|
*wideNamePtr++ = *namePtr++;
|
|
}
|
|
*wideNamePtr++ = 0;
|
|
}
|
|
|
|
namelen = strlen(name);
|
|
if (namelen >= MAP_MAXFUNCNAME) {
|
|
memcpy (namebuf, name, MAP_MAXFUNCNAME - 1);
|
|
fprintf(Map, "%08x %s\n", Map_marks[i].offset, namebuf);
|
|
}
|
|
else
|
|
fprintf(Map, "%08x %s\n", Map_marks[i].offset, name);
|
|
}
|
|
}
|
|
i = k + 1;
|
|
}
|
|
|
|
fclose(Map);
|
|
free(Map_marks);
|
|
Map_marks = NULL;
|
|
|
|
MAPClose();
|
|
}
|