tools/gdc-psyfork/gdc.cpp
author David Anderson <dvander@alliedmods.net>
Thu Aug 08 22:02:42 2013 -0700 (2013-08-08)
changeset 3980 dc7dfcd855dc
parent 3956 1ccbc1dfa814
permissions -rw-r--r--
More Windows build fix.
     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <dlfcn.h>
     4 #include <fcntl.h>
     5 #include <math.h>
     6 #include <iostream>
     7 #include "gdc.h"
     8 #include "GameConfigs.h"
     9 #include "MemoryUtils.h"
    10 
    11 MemoryUtils mu;
    12 
    13 char *game = NULL;
    14 char *engine = NULL;
    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;
    20 
    21 bool use_symtab = true;
    22 CGameConfig symbols;
    23 CGameConfig gc;
    24 
    25 inline bool IsDigit( char c )
    26 {
    27 	return c < 58 && c > 47;
    28 }
    29 
    30 void PrintUsage()
    31 {
    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");
    36 }
    37 
    38 int main(int argc, char **argv)
    39 {
    40 	char *gamedata = NULL;
    41 	bool debug = false;
    42 
    43 	opterr = 0;
    44 	int opt;
    45 	while ((opt = getopt(argc, argv, "b:nde:f:g:x:w:y:s:")) != -1)
    46 	{
    47 		switch (opt)
    48 		{
    49 			case 'd':
    50 				debug = true;
    51 				break;
    52 
    53 			case 'n':
    54 				use_symtab = false;
    55 				break;
    56 
    57 			case 'g':
    58 				game = optarg;
    59 				break;
    60 
    61 			case 'e':
    62 				engine = optarg;
    63 				break;
    64 
    65 			case 'f':
    66 				gamedata = optarg;
    67 				break;
    68 
    69 			case 'b':
    70 				game_binary = optarg;
    71 				break;
    72 
    73 			case 'x':
    74 				engine_binary = optarg;
    75 				break;
    76 
    77 			case 'w':
    78 				wgame_binary = optarg;
    79 				break;
    80 
    81 			case 'y':
    82 				wengine_binary = optarg;
    83 				break;
    84 
    85 			case 's':
    86 				symbols_file = optarg;
    87 				break;
    88 
    89 			case '?':
    90 				PrintUsage();
    91 				return 0;
    92 
    93 			default:
    94 				printf("WHAT\n");
    95 				return 0;
    96 		}
    97 	}
    98 
    99 	if (!game || !engine || !gamedata || !game_binary || !engine_binary || !wgame_binary || !wengine_binary)
   100 	{
   101 		PrintUsage();
   102 		return 0;
   103 	}
   104 
   105 	printf("Game: %s\n", game);
   106 	if (debug)
   107 	{
   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
   110 			);
   111 	}
   112 	printf("Gamedata: %s\n\n", gamedata);
   113 
   114 	void *ghandle;
   115 	ghandle = dlopen(game_binary, RTLD_LAZY);
   116 	if (!ghandle)
   117 	{
   118 		printf("Couldn't open %s (%s)\n", game_binary, dlerror());
   119 			return 0;
   120 	}
   121 	void *ehandle;
   122 	ehandle = dlopen(engine_binary, RTLD_LAZY);
   123 	if (!ehandle)
   124 	{
   125 		printf("Couldn't open %s (%s)\n", engine_binary, dlerror());
   126 			return 0;
   127 	}
   128 
   129 	int wgfile = open(wgame_binary, O_RDONLY);
   130 	if (wgfile == -1)
   131 	{
   132 		printf("Couldn't open %s\n", wgame_binary);
   133 		return 0;
   134 	}
   135 
   136 	int wefile = open(wengine_binary, O_RDONLY);
   137 	if (wefile == -1)
   138 	{
   139 		printf("Couldn't open %s\n", wengine_binary);
   140 		return 0;
   141 	}
   142 
   143 	char err[512];
   144 	if (!gc.EnterFile(gamedata, err, sizeof(err)))
   145 	{
   146 		printf("%s: %s\n", gamedata, err);
   147 		return 0;
   148 	}
   149 
   150 	if (!symbols.EnterFile(symbols_file ? symbols_file : "symbols.txt", err, sizeof(err)))
   151 	{
   152 		printf("symbols.txt: %s\n", err);
   153 		return 0;
   154 	}
   155 
   156 	for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
   157 	{
   158 		if (debug)
   159 		{
   160 			printf("DEBUG %s - l: %d w: %d\n", it->name, it->lin, it->win);
   161 		}
   162 
   163 		const char *symbol = symbols.GetKeyValue(it->name);
   164 		if (symbol)
   165 		{
   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);
   171 			
   172 			for ( unsigned int i = 0; i < symlen && pos < (sizeof(symvt)-1); ++i )
   173 			{
   174 				bool isDigit = IsDigit( symbol[i] );
   175 				if( !isDigit && bLastNumberDigit )
   176 				{
   177 					bGotFirstNumbers = true;
   178 				}
   179 				
   180 				// we're before the class len
   181 				if( !bGotFirstNumbers && !isDigit )
   182 					continue;
   183 				
   184 				// we're at the function name len
   185 				if( bGotFirstNumbers && isDigit )
   186 				{
   187 					symvt[pos] = 0;
   188 					break;
   189 				}
   190 				
   191 				// we're at the class len or class name. we want these
   192 				symvt[pos++] = symbol[i];
   193 				if( isDigit )
   194 				{
   195 					bLastNumberDigit = isDigit;
   196 				}
   197 			}
   198 			symvt[pos] = 0;
   199 			
   200 			int newOffset;
   201 			if (symvt[0])
   202 			{
   203                 void **newvt = NULL;
   204 				if( use_symtab )
   205 				{
   206 					newvt = (void**)mu.ResolveSymbol(ghandle, symvt);
   207 				}
   208 				else
   209 				{
   210 					newvt = (void **)dlsym(ghandle, symvt);
   211 				}
   212 				
   213 			    if (!newvt)
   214 				{
   215 					printf("? O: %-22s - can't find, skipping\n", symvt);
   216 					continue;
   217 				}
   218 
   219 				newOffset = findVFunc(ghandle, newvt, symbol);
   220 			}
   221 
   222 			if (newOffset == it->lin)
   223 			{
   224 				printf("  O: %-22s - GOOD.    current [ w: %3d, l: %3d ].\n", it->name, it->win, it->lin);
   225 			}
   226 			else
   227 			{
   228 				printf("! O: %-22s - CHANGED. old [ w: %3d, l: %3d ]. new [ w: %3d, l: %3d ].\n",
   229 					it->name,
   230 					it->win, it->lin,
   231 					newOffset - (it->lin - it->win), newOffset
   232 					);
   233 			}
   234 		}
   235 		else // !symbol
   236 		{
   237 			printf("  O: %-22s - no Linux symbol, skipping\n", it->name);
   238 		}
   239 	}
   240 
   241 	printf("\nWindows offsets are (semi-)wild guesses!\n\nSignature offsets are wild guesses!\n\n");
   242 
   243 	for (list<Sig>::iterator it = gc.m_Sigs.begin(); it != gc.m_Sigs.end(); it++)
   244 	{
   245 		if (debug)
   246 		{
   247 			printf("DEBUG %s - %s - l: %s\n", it->name, it->lib == Server ? "server" : "engine", it->lin);
   248 		}
   249 
   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)
   255 		{
   256 			printf("  S: %-22s - hasn't linux nor windows data, skipping\n", it->name);
   257 			continue;
   258 		}
   259 		
   260 		int  winFile;
   261 		void *linHandle;
   262 		if (it->lib == Server)
   263 		{
   264 			winFile   = wgfile;
   265 			linHandle = ghandle;
   266 		}
   267 		else if (it->lib == Engine)
   268 		{
   269 			winFile   = wefile;
   270 			linHandle = ehandle;
   271 		}
   272 		else
   273 		{
   274 			printf("  S: %-22s - isn't from server nor engine, skipping\n", it->name);
   275 			continue;
   276 		}
   277 		
   278 		int linuxMatches = 0, windowsMatches = 0;
   279 		if( hasLinux )
   280 			linuxMatches = checkSigStringL(linHandle, linSymbol);
   281 		if( hasWindows )
   282 			windowsMatches = checkSigStringW(winFile,   winSymbol);
   283 			
   284 		if (linuxMatches == 1 && windowsMatches == 1)
   285 		{
   286 			// too much clutter to print current data if it matches anyway, unlike with offsets
   287 			/*
   288 			printf("%-22s (%s) - GOOD. current:\n\t[w:%s]\n\t[l:%s]\n",
   289 				it->name,
   290 				(it->lib == Server) ? "server" : "engine",
   291 				winSymbol ? winSymbol : "",
   292 				linSymbol ? linSymbol : ""
   293 				);
   294 			*/
   295 			printf("  S: %-22s (%s) - w: GOOD     - l: GOOD    \n",
   296 				it->name,
   297 				(it->lib == Server) ? "server" : "engine"
   298 				);
   299 
   300 			//Check if they signature has a matching offset
   301 			CheckWindowsSigOffset(it->name, winSymbol, winFile);
   302 			CheckLinuxSigOffset(it->name, linSymbol, linHandle);
   303 
   304 		}
   305 		else
   306 		{
   307 			char winStatus[16];
   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 );
   312 			
   313 			bool bWinGood = false;
   314 			if( !hasWindows ) {
   315 				snprintf( winStatus, sizeof(winStatus), "UNKNOWN" );
   316 			}
   317 			else if( windowsMatches == -1 && !allowMidfunc) {
   318 				snprintf( winStatus, sizeof(winStatus), "MIDFUNC" );
   319 			}
   320 			else if( windowsMatches == 0 ) {
   321 				snprintf( winStatus, sizeof(winStatus), "NOTFOUND" );
   322 			}
   323 			else if( windowsMatches > 1 && !allowMulti) {
   324 				snprintf( winStatus, sizeof(winStatus), "MULTIPLE" );
   325 			}
   326 			else {
   327 				bWinGood = true;
   328 				snprintf( winStatus, sizeof(winStatus), "GOOD" );
   329 			}
   330 			
   331 			char linStatus[16];
   332 			bool bLinGood = false;
   333 			if( !hasLinux ) {
   334 				snprintf( linStatus, sizeof(linStatus), "UNKNOWN" );
   335 			}
   336 			else if( linuxMatches == 0 ) {
   337 				snprintf( linStatus, sizeof(linStatus), "NOTFOUND" );
   338 			}
   339 			else if( linuxMatches == 1 ) {
   340 				bLinGood = true;
   341 				snprintf( linStatus, sizeof(linStatus), "GOOD" );
   342 			}
   343 			else {
   344 				snprintf( linStatus, sizeof(linStatus), "CHECK" );
   345 			}
   346 			
   347 			bool showWinExtra = (hasWindows && !bWinGood);
   348 			bool showLinExtra = ( ( hasLinux && !bLinGood ) || showWinExtra );
   349 			
   350 			printf("%s S: %-22s (%s)", (showWinExtra || showLinExtra) ? "!" : " ", it->name, (it->lib == Server) ? "server" : "engine" );
   351 				printf(" - w: %-8s - l: %-8s\n", winStatus, linStatus );
   352 			
   353 			if( showWinExtra || showLinExtra )
   354 				printf( "!    current:\n" );
   355 			
   356 			if( showWinExtra )
   357 			{
   358 				printf("!    w: \"%s\"\n",
   359 					winSymbol ? winSymbol : ""
   360 					);
   361 			}
   362 			
   363 			if( showLinExtra )
   364 			{
   365 				// extra \n at end is intentional to add buffer after possibly long sigs
   366 				printf("!    l: \"%s\"\n\n",
   367 					linSymbol ? linSymbol : ""
   368 					);
   369 			}			
   370 		}
   371 	}
   372 
   373 	return 0;
   374 }
   375 void CheckWindowsSigOffset(char* name, const char* symbol, int file)
   376 {
   377 	void *ptr = GetWindowsSigPtr(file, symbol);
   378 	if(!ptr)
   379 	{
   380 		return;
   381 	}
   382 	const char* sigOffsetKey = NULL;
   383 	const char* sigOffsetByte = NULL;
   384 	int sigOffset = -1;
   385 	char sigOffsetName[128];
   386 	char sigByteName[128];
   387 
   388 	snprintf(sigOffsetName, sizeof(sigOffsetName), "%s_Offset", name);
   389 	snprintf(sigByteName, sizeof(sigByteName), "%s_Byte_Win", name);
   390 
   391 	sigOffsetKey = symbols.GetKeyValue((const char *)sigOffsetName);
   392 	if(sigOffsetKey == NULL)
   393 	{
   394 
   395 		//Maybe it has multiple?
   396 		for(unsigned int i = 1; i <= 4; i++)
   397 		{
   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);
   401 
   402 			if(sigOffsetKey == NULL)
   403 			{
   404 				break;
   405 			}
   406 			
   407 			sigOffset = GetOffset(sigOffsetKey, true);
   408 			sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
   409 			
   410 			if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
   411 			{
   412 				uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
   413 
   414 				if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
   415 				{
   416 					printf("     w: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   417 				}
   418 				else
   419 				{
   420 					printf("!    w: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   421 				}
   422 			}
   423 		}
   424 	}
   425 	else
   426 	{
   427 		sigOffset = GetOffset(sigOffsetKey, true);
   428 		sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
   429 			
   430 		if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
   431 		{
   432 			uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
   433 
   434 			if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
   435 			{
   436 				printf("     w: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   437 			}
   438 			else
   439 			{
   440 				printf("!    w: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   441 			}
   442 		}
   443 	}
   444 }
   445 void CheckLinuxSigOffset(char* name, const char* symbol, void * handle)
   446 {
   447 	void *ptr = GetLinuxSigPtr(handle, symbol);
   448 	if(!ptr)
   449 	{
   450 		return;
   451 	}
   452 	const char* sigOffsetKey = NULL;
   453 	const char* sigOffsetByte = NULL;
   454 	int sigOffset = -1;
   455 	char sigOffsetName[128];
   456 	char sigByteName[128];
   457 
   458 	snprintf(sigOffsetName, sizeof(sigOffsetName), "%s_Offset", name);
   459 	snprintf(sigByteName, sizeof(sigByteName), "%s_Byte_Lin", name);
   460 
   461 	sigOffsetKey = symbols.GetKeyValue((const char *)sigOffsetName);
   462 
   463 	if(sigOffsetKey == NULL)
   464 	{
   465 
   466 		//Maybe it has multiple?
   467 		for(unsigned int i = 1; i <= 4; i++)
   468 		{
   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);
   472 
   473 			if(sigOffsetKey == NULL)
   474 			{
   475 				break;
   476 			}
   477 			
   478 			sigOffset = GetOffset(sigOffsetKey, false);
   479 			sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
   480 			
   481 			if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
   482 			{
   483 				uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
   484 
   485 				if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
   486 				{
   487 					printf("     l: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   488 				}
   489 				else
   490 				{
   491 					printf("!    l: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   492 				}
   493 			}
   494 		}
   495 	}
   496 	else
   497 	{
   498 		sigOffset = GetOffset(sigOffsetKey, false);
   499 		sigOffsetByte = symbols.GetKeyValue((const char *)sigByteName);
   500 			
   501 		if(sigOffset != -1 && sigOffsetByte != NULL)//Got the offset in the function
   502 		{
   503 			uint8_t iByte = strtoul(sigOffsetByte, NULL, 16);
   504 
   505 			if(iByte == *(uint8_t *)((intptr_t)ptr + sigOffset))
   506 			{
   507 				printf("     l: %s -> %s (%4d) == \\x%s GOOD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   508 			}
   509 			else
   510 			{
   511 				printf("!    l: %s -> %s (%4d) != \\x%s BAD\n", name, sigOffsetKey, sigOffset, sigOffsetByte);
   512 			}
   513 		}
   514 	}
   515 }
   516 int GetOffset(const char* key, bool windows)
   517 {
   518 	for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
   519 	{
   520 		if (strcmp(it->name, key) == 0)
   521 		{
   522 			if(windows)
   523 				return it->win;
   524 			else
   525 				return it->lin;
   526 		}
   527 	}
   528 	return -1;
   529 }
   530 void *GetWindowsSigPtr(int file, const char* symbol)
   531 {
   532 	int matches = 0;
   533 	bool atFuncStart = true;
   534 	bool isAt = (symbol[0] == '@');
   535 	// we can't support this on windows from here
   536 	if (isAt)
   537 		return NULL;
   538 	
   539 	unsigned char real_sig[511];
   540 	size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
   541 
   542 	if (real_bytes >= 1)
   543 	{
   544 		return mu.FindPatternInFile(file, (char*)real_sig, real_bytes, matches, atFuncStart);
   545 	}
   546 	return NULL;
   547 
   548 }
   549 void *GetLinuxSigPtr(void *handle, const char* symbol)
   550 {
   551 	bool isAt = (symbol[0] == '@' && symbol[1] != '\0');
   552 	int matches = 0;
   553 	bool dummy;
   554 	
   555 	if (isAt)
   556 	{
   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]);
   561 	}
   562 	else
   563 	{
   564 		unsigned char real_sig[511];
   565 		size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
   566 
   567 		if (real_bytes >= 1)
   568 		{
   569 			return mu.FindPattern(handle, (char*)real_sig, real_bytes, matches, dummy);
   570 		}
   571 	}
   572 
   573 	return NULL;
   574 }
   575 int checkSigStringW(int file, const char* symbol)
   576 {
   577 	int matches = 0;
   578 	bool atFuncStart = true;
   579 	bool isAt = (symbol[0] == '@');
   580 	// we can't support this on windows from here
   581 	if (isAt)
   582 		return false;
   583 	
   584 	unsigned char real_sig[511];
   585 	size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
   586 
   587 	if (real_bytes >= 1)
   588 	{
   589 		mu.FindPatternInFile(file, (char*)real_sig, real_bytes, matches, atFuncStart);
   590 	}
   591 
   592 	if( !atFuncStart )
   593 		return -1;
   594 	
   595 	return matches;
   596 }
   597 
   598 int checkSigStringL(void *handle, const char* symbol)
   599 {
   600 	bool isAt = (symbol[0] == '@' && symbol[1] != '\0');
   601 	int matches = 0;
   602 	bool dummy;
   603 	
   604 	if (isAt)
   605 	{
   606 		if( use_symtab && mu.ResolveSymbol(handle, &symbol[1]) )
   607 			matches = 1;
   608 		else if( !use_symtab && dlsym(handle, &symbol[1]) )
   609 			matches = 1;
   610 	}
   611 	else
   612 	{
   613 		unsigned char real_sig[511];
   614 		size_t real_bytes = UTIL_DecodeHexString(real_sig, sizeof(real_sig), symbol);
   615 
   616 		if (real_bytes >= 1)
   617 		{
   618 			mu.FindPattern(handle, (char*)real_sig, real_bytes, matches, dummy);
   619 		}
   620 	}
   621 
   622 	return matches;
   623 }
   624 
   625 /* 
   626    takes a mangled member function symbol and returns the position where the function name and parameters start
   627    01234567890123456789012345678
   628    _ZN9CTFPlayer12ForceRespawnEv
   629                 ^13            ^28
   630 */
   631 void findFuncPos(const char *sym, int &func, int &params)
   632 {
   633 	int i = 0;
   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;
   639 }
   640 
   641 int findVFunc(void *handle, void **vt, const char *symbol)
   642 {
   643 	if( !use_symtab )
   644 	{
   645 		for (int i = 0; i < 1000; i++ )
   646 		{
   647 			void *pFunc = vt[i];
   648 			if( !pFunc )
   649 				continue;
   650 			
   651 			if( pFunc == dlsym(handle, symbol ) )
   652 				return i - 2;
   653 		}
   654 		
   655 		return -1;
   656 	}
   657 	
   658 	int funcPos, paramPos;
   659 	findFuncPos(symbol, funcPos, paramPos);
   660 
   661 	for (int i = 0; i < 1000; i++)
   662 	{
   663 		void *pFunc = vt[i];
   664 		if( !pFunc )
   665 			continue;
   666 		
   667 		const char *s;
   668 
   669 		if (!(s = mu.ResolveAddr(handle, pFunc)))
   670 			continue;
   671 
   672 		if ((i > 1) && (strncmp(s, "_ZTI", 4) == 0))
   673 			break;
   674 
   675 
   676 		int tempFuncPos, tempParamPos;
   677 		findFuncPos(s, tempFuncPos, tempParamPos);
   678 
   679 		if (strcmp(s + tempFuncPos, symbol + funcPos) == 0)
   680 		{
   681 			return i - 2;
   682 		}
   683 	}
   684 
   685 	return -1;
   686 }
   687 
   688 unsigned int strncopy(char *dest, const char *src, size_t count)
   689 {
   690 	if (!count)
   691 	{
   692 		return 0;
   693 	}
   694 
   695 	char *start = dest;
   696 	while ((*src) && (--count))
   697 	{
   698 		*dest++ = *src++;
   699 	}
   700 	*dest = '\0';
   701 
   702 	return (dest - start);
   703 }
   704 
   705 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
   706 {
   707 	va_list ap;
   708 	va_start(ap, fmt);
   709 	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
   710 	va_end(ap);
   711 
   712 	if (len >= maxlength)
   713 	{
   714 		buffer[maxlength - 1] = '\0';
   715 		return (maxlength - 1);
   716 	}
   717 	else
   718 	{
   719 		return len;
   720 	}
   721 }
   722 
   723 size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr)
   724 {
   725 	size_t written = 0;
   726 	size_t length = strlen(hexstr);
   727 
   728 	for (size_t i = 0; i < length; i++)
   729 	{
   730 		if (written >= maxlength)
   731 			break;
   732 		
   733 		buffer[written++] = hexstr[i];
   734 		if (hexstr[i] == '\\' && hexstr[i + 1] == 'x')
   735 		{
   736 			if (i + 3 >= length)
   737 				continue;
   738 			/* Get the hex part. */
   739 			char s_byte[3];
   740 			int r_byte;
   741 			s_byte[0] = hexstr[i + 2];
   742 			s_byte[1] = hexstr[i + 3];
   743 			s_byte[2] = '\0';
   744 			/* Read it as an integer */
   745 			sscanf(s_byte, "%x", &r_byte);
   746 			/* Save the value */
   747 			buffer[written - 1] = r_byte;
   748 			/* Adjust index */
   749 			i += 3;
   750 		}
   751 	}
   752 
   753 	return written;
   754 }
   755