More Windows build fix.
8 #include "GameConfigs.h"
9 #include "MemoryUtils.h"
15 char *game_binary = NULL;
16 char *engine_binary = NULL;
17 char *wgame_binary = NULL;
18 char *wengine_binary = NULL;
19 char *symbols_file = NULL;
21 bool use_symtab = true;
25 inline bool IsDigit( char c )
27 return c < 58 && c > 47;
32 printf("Usage: ./gdc -g <game> -e <engine name> -f <gamedata file> -b <game binary> -x <engine binary> -w <win game binary> -y <win engine binary> [-s <symbols.txt file>]\n");
33 printf("Other options:\n");
34 printf(" -d\tAdd debug output\n");
35 printf(" -n\tDon't use symbol table for lookups (falls back to dlsym)\n");
38 int main(int argc, char **argv)
40 char *gamedata = NULL;
45 while ((opt = getopt(argc, argv, "b:nde:f:g:x:w:y:s:")) != -1)
74 engine_binary = optarg;
78 wgame_binary = optarg;
82 wengine_binary = optarg;
86 symbols_file = optarg;
99 if (!game || !engine || !gamedata || !game_binary || !engine_binary || !wgame_binary || !wengine_binary)
105 printf("Game: %s\n", game);
108 printf("Engine: %s\nGame binary: %s\nEngine binary: %s\nWin game binary: %s\nWin engine binary: %s\n",
109 engine, game_binary, engine_binary, wgame_binary, wengine_binary
112 printf("Gamedata: %s\n\n", gamedata);
115 ghandle = dlopen(game_binary, RTLD_LAZY);
118 printf("Couldn't open %s (%s)\n", game_binary, dlerror());
122 ehandle = dlopen(engine_binary, RTLD_LAZY);
125 printf("Couldn't open %s (%s)\n", engine_binary, dlerror());
129 int wgfile = open(wgame_binary, O_RDONLY);
132 printf("Couldn't open %s\n", wgame_binary);
136 int wefile = open(wengine_binary, O_RDONLY);
139 printf("Couldn't open %s\n", wengine_binary);
144 if (!gc.EnterFile(gamedata, err, sizeof(err)))
146 printf("%s: %s\n", gamedata, err);
150 if (!symbols.EnterFile(symbols_file ? symbols_file : "symbols.txt", err, sizeof(err)))
152 printf("symbols.txt: %s\n", err);
156 for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
160 printf("DEBUG %s - l: %d w: %d\n", it->name, it->lin, it->win);
163 const char *symbol = symbols.GetKeyValue(it->name);
166 char symvt[128] = "_ZTV";
167 bool bGotFirstNumbers = false;
168 bool bLastNumberDigit = false;
169 unsigned int symlen = strlen(symbol);
170 unsigned int pos = strlen(symvt);
172 for ( unsigned int i = 0; i < symlen && pos < (sizeof(symvt)-1); ++i )
174 bool isDigit = IsDigit( symbol[i] );
175 if( !isDigit && bLastNumberDigit )
177 bGotFirstNumbers = true;
180 // we're before the class len
181 if( !bGotFirstNumbers && !isDigit )
184 // we're at the function name len
185 if( bGotFirstNumbers && isDigit )
191 // we're at the class len or class name. we want these
192 symvt[pos++] = symbol[i];
195 bLastNumberDigit = isDigit;
206 newvt = (void**)mu.ResolveSymbol(ghandle, symvt);
210 newvt = (void **)dlsym(ghandle, symvt);
215 printf("? O: %-22s - can't find, skipping\n", symvt);
219 newOffset = findVFunc(ghandle, newvt, symbol);
222 if (newOffset == it->lin)
224 printf(" O: %-22s - GOOD. current [ w: %3d, l: %3d ].\n", it->name, it->win, it->lin);
228 printf("! O: %-22s - CHANGED. old [ w: %3d, l: %3d ]. new [ w: %3d, l: %3d ].\n",
231 newOffset - (it->lin - it->win), newOffset
237 printf(" O: %-22s - no Linux symbol, skipping\n", it->name);
241 printf("\nWindows offsets are (semi-)wild guesses!\n\nSignature offsets are wild guesses!\n\n");
243 for (list<Sig>::iterator it = gc.m_Sigs.begin(); it != gc.m_Sigs.end(); it++)
247 printf("DEBUG %s - %s - l: %s\n", it->name, it->lib == Server ? "server" : "engine", it->lin);
250 const char *linSymbol = it->lin;
251 const char *winSymbol = it->win;
252 bool hasLinux = (linSymbol && linSymbol[0]);
253 bool hasWindows = (winSymbol && winSymbol[0]);
254 if (!hasLinux && !hasWindows)
256 printf(" S: %-22s - hasn't linux nor windows data, skipping\n", it->name);
262 if (it->lib == Server)
267 else if (it->lib == Engine)
274 printf(" S: %-22s - isn't from server nor engine, skipping\n", it->name);
278 int linuxMatches = 0, windowsMatches = 0;
280 linuxMatches = checkSigStringL(linHandle, linSymbol);
282 windowsMatches = checkSigStringW(winFile, winSymbol);
284 if (linuxMatches == 1 && windowsMatches == 1)
286 // too much clutter to print current data if it matches anyway, unlike with offsets
288 printf("%-22s (%s) - GOOD. current:\n\t[w:%s]\n\t[l:%s]\n",
290 (it->lib == Server) ? "server" : "engine",
291 winSymbol ? winSymbol : "",
292 linSymbol ? linSymbol : ""
295 printf(" S: %-22s (%s) - w: GOOD - l: GOOD \n",
297 (it->lib == Server) ? "server" : "engine"
300 //Check if they signature has a matching offset
301 CheckWindowsSigOffset(it->name, winSymbol, winFile);
302 CheckLinuxSigOffset(it->name, linSymbol, linHandle);
308 // right now the only option is to ignore
309 const char *options = symbols.GetOptionValue(it->name);
310 bool allowMulti = ( options && strstr(options, "allowmultiple") != NULL );
311 bool allowMidfunc = ( options && strstr(options, "allowmidfunc") != NULL );
313 bool bWinGood = false;
315 snprintf( winStatus, sizeof(winStatus), "UNKNOWN" );
317 else if( windowsMatches == -1 && !allowMidfunc) {
318 snprintf( winStatus, sizeof(winStatus), "MIDFUNC" );
320 else if( windowsMatches == 0 ) {
321 snprintf( winStatus, sizeof(winStatus), "NOTFOUND" );
323 else if( windowsMatches > 1 && !allowMulti) {
324 snprintf( winStatus, sizeof(winStatus), "MULTIPLE" );
328 snprintf( winStatus, sizeof(winStatus), "GOOD" );
332 bool bLinGood = false;
334 snprintf( linStatus, sizeof(linStatus), "UNKNOWN" );
336 else if( linuxMatches == 0 ) {
337 snprintf( linStatus, sizeof(linStatus), "NOTFOUND" );
339 else if( linuxMatches == 1 ) {
341 snprintf( linStatus, sizeof(linStatus), "GOOD" );
344 snprintf( linStatus, sizeof(linStatus), "CHECK" );
347 bool showWinExtra = (hasWindows && !bWinGood);
348 bool showLinExtra = ( ( hasLinux && !bLinGood ) || showWinExtra );
350 printf("%s S: %-22s (%s)", (showWinExtra || showLinExtra) ? "!" : " ", it->name, (it->lib == Server) ? "server" : "engine" );
351 printf(" - w: %-8s - l: %-8s\n", winStatus, linStatus );
353 if( showWinExtra || showLinExtra )
354 printf( "! current:\n" );
358 printf("! w: \"%s\"\n",
359 winSymbol ? winSymbol : ""
365 // extra \n at end is intentional to add buffer after possibly long sigs
366 printf("! l: \"%s\"\n\n",
367 linSymbol ? linSymbol : ""
375 void CheckWindowsSigOffset(char* name, const char* symbol, int file)
377 void *ptr = GetWindowsSigPtr(file, symbol);
382 const char* sigOffsetKey = NULL;
383 const char* sigOffsetByte = NULL;
385 char sigOffsetName[128];
386 char sigByteName[128];
388 snprintf(sigOffsetName, sizeof(sigOffsetName), "%s_Offset", name);
389 snprintf(sigByteName, sizeof(sigByteName), "%s_Byte_Win", name);
391 sigOffsetKey = symbols.GetKeyValue((const char *)sigOffsetName);
392 if(sigOffsetKey == NULL)
395 //Maybe it has multiple?
396 for(unsigned int i = 1; i <= 4; i++)
398 snprintf(sigOffsetName, sizeof(sigOffsetName), "%s_Offset%i", name, i);
399 snprintf(sigByteName, sizeof(sigByteName), "%s_Byte_Win%i", name, i);
400 sigOffsetKey = symbols.GetKeyValue((const char *)sigOffsetName);
402 if(sigOffsetKey == NULL)
407 sigOffset = GetOffset(sigOffsetKey, true);
408 sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
410 if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
412 uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
414 if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
416 printf(" w: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
420 printf("! w: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
427 sigOffset = GetOffset(sigOffsetKey, true);
428 sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
430 if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
432 uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
434 if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
436 printf(" w: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
440 printf("! w: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
445 void CheckLinuxSigOffset(char* name, const char* symbol, void * handle)
447 void *ptr = GetLinuxSigPtr(handle, symbol);
452 const char* sigOffsetKey = NULL;
453 const char* sigOffsetByte = NULL;
455 char sigOffsetName[128];
456 char sigByteName[128];
458 snprintf(sigOffsetName, sizeof(sigOffsetName), "%s_Offset", name);
459 snprintf(sigByteName, sizeof(sigByteName), "%s_Byte_Lin", name);
461 sigOffsetKey = symbols.GetKeyValue((const char *)sigOffsetName);
463 if(sigOffsetKey == NULL)
466 //Maybe it has multiple?
467 for(unsigned int i = 1; i <= 4; i++)
469 snprintf(sigOffsetName, sizeof(sigOffsetName), "%s_Offset%i", name, i);
470 snprintf(sigByteName, sizeof(sigByteName), "%s_Byte_Lin%i", name, i);
471 sigOffsetKey = symbols.GetKeyValue((const char *)sigOffsetName);
473 if(sigOffsetKey == NULL)
478 sigOffset = GetOffset(sigOffsetKey, false);
479 sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
481 if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
483 uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
485 if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
487 printf(" l: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
491 printf("! l: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
498 sigOffset = GetOffset(sigOffsetKey, false);
499 sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
501 if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
503 uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
505 if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
507 printf(" l: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
511 printf("! l: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
516 int GetOffset(const char* key, bool windows)
518 for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
520 if (strcmp(it->name, key) == 0)
530 void *GetWindowsSigPtr(int file, const char* symbol)
533 bool atFuncStart = true;
534 bool isAt = (symbol[0] == '@');
535 // we can't support this on windows from here
539 unsigned char real_sig[511];
540 size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
544 return mu.FindPatternInFile(file, (char*)real_sig, real_bytes, matches, atFuncStart);
549 void *GetLinuxSigPtr(void *handle, const char* symbol)
551 bool isAt = (symbol[0] == '@' && symbol[1] != '\0');
557 if( use_symtab && mu.ResolveSymbol(handle, &symbol[1]) )
558 return mu.ResolveSymbol(handle, &symbol[1]);
559 else if( !use_symtab && dlsym(handle, &symbol[1]) )
560 return dlsym(handle, &symbol[1]);
564 unsigned char real_sig[511];
565 size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
569 return mu.FindPattern(handle, (char*)real_sig, real_bytes, matches, dummy);
575 int checkSigStringW(int file, const char* symbol)
578 bool atFuncStart = true;
579 bool isAt = (symbol[0] == '@');
580 // we can't support this on windows from here
584 unsigned char real_sig[511];
585 size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
589 mu.FindPatternInFile(file, (char*)real_sig, real_bytes, matches, atFuncStart);
598 int checkSigStringL(void *handle, const char* symbol)
600 bool isAt = (symbol[0] == '@' && symbol[1] != '\0');
606 if( use_symtab && mu.ResolveSymbol(handle, &symbol[1]) )
608 else if( !use_symtab && dlsym(handle, &symbol[1]) )
613 unsigned char real_sig[511];
614 size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
618 mu.FindPattern(handle, (char*)real_sig, real_bytes, matches, dummy);
626 takes a mangled member function symbol and returns the position where the function name and parameters start
627 01234567890123456789012345678
628 _ZN9CTFPlayer12ForceRespawnEv
631 void findFuncPos(const char *sym, int &func, int ¶ms)
634 while ((sym[i] < '0') || (sym[i] > '9')) i++;
635 int classLen = atoi(sym + i);
636 func = i + (int)ceil(log10(classLen)) + classLen;
637 int funcLen = atoi(sym + func);
638 params = func + (int)ceil(log10(funcLen)) + funcLen;
641 int findVFunc(void *handle, void **vt, const char *symbol)
645 for (int i = 0; i < 1000; i++ )
651 if( pFunc == dlsym(handle, symbol ) )
658 int funcPos, paramPos;
659 findFuncPos(symbol, funcPos, paramPos);
661 for (int i = 0; i < 1000; i++)
669 if (!(s = mu.ResolveAddr(handle, pFunc)))
672 if ((i > 1) && (strncmp(s, "_ZTI", 4) == 0))
676 int tempFuncPos, tempParamPos;
677 findFuncPos(s, tempFuncPos, tempParamPos);
679 if (strcmp(s + tempFuncPos, symbol + funcPos) == 0)
688 unsigned int strncopy(char *dest, const char *src, size_t count)
696 while ((*src) && (--count))
702 return (dest - start);
705 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
709 size_t len = vsnprintf(buffer, maxlength, fmt, ap);
712 if (len >= maxlength)
714 buffer[maxlength - 1] = '\0';
715 return (maxlength - 1);
723 size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr)
726 size_t length = strlen(hexstr);
728 for (size_t i = 0; i < length; i++)
730 if (written >= maxlength)
733 buffer[written++] = hexstr[i];
734 if (hexstr[i] == '\\' && hexstr[i + 1] == 'x')
738 /* Get the hex part. */
741 s_byte[0] = hexstr[i + 2];
742 s_byte[1] = hexstr[i + 3];
744 /* Read it as an integer */
745 sscanf(s_byte, "%x", &r_byte);
747 buffer[written - 1] = r_byte;