pureikyubu/SRC/HighLevel/MapMaker.cpp
2020-08-09 21:36:10 +03:00

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();
}