tools/vtable_scanner/main.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 25 19:22:36 2009 -0500 (2009-02-25)
changeset 2603 fa286305bd3f
parent 2464 e52d6040f239
child 2677 f6097a2d9812
permissions -rw-r--r--
Allow for second private chat trigger (bug 3667, r,a11=pred).
     1 #include <stdio.h>
     2 #include <dlfcn.h>
     3 #include "string.h"
     4 #include "malloc.h"
     5 
     6 extern "C" char * cplus_demangle(const char *, int);
     7 #define DMGL_PARAMS	 (1 << 0)
     8 
     9 struct VOffset
    10 {
    11 	int linux_offset;
    12 	int windows_offset;
    13 };
    14 
    15 static bool FindVFunc(void *handle, void **vtable, const char* vtable_end, const char *class_function, const char *params, VOffset *offsets);
    16 
    17 int main(int argc, char **argv)
    18 {
    19 	void *handle;
    20 	void **pVtable;
    21 
    22 	VOffset offsets;
    23 	char *params = NULL;
    24 	bool ret;
    25 
    26 	if (argc < 4)
    27 	{
    28 		fprintf(stderr, "Usage: <binary> <vtable start symbol> <function> <optional: params> <optional: vtable end symbol>\n");
    29 		return -1;
    30 	}
    31 
    32 	handle = dlopen(argv[1], RTLD_NOW);
    33 
    34 	if (handle == NULL)
    35 	{
    36 		fprintf(stderr, "Failed to open server image, error [%s]\n", dlerror());
    37 		return -1;
    38 	}
    39 
    40 	pVtable = (void **)dlsym(handle, argv[2]);
    41 
    42 	if (pVtable == NULL)
    43 	{
    44 		fprintf(stderr, "Invalid vtable symbol \"%s\"\n", argv[2]);
    45 		dlclose(handle);
    46 		return -1;
    47 	}
    48 
    49 	if (argc >= 5)
    50 	{
    51 		params = argv[4];
    52 
    53 		if (params[0] == '"')
    54 		{
    55 			params++;
    56 		}
    57 
    58 		int len = strlen(params)-1;
    59 
    60 		if (params[len] == '"')
    61 		{
    62 			params[len] = '\0';
    63 		}
    64 
    65 		if (params[0] == 0)
    66 		{
    67 			params = NULL;
    68 		}
    69 	}
    70 
    71 	if (argc == 6)
    72 	{
    73 		ret = FindVFunc(handle, pVtable, argv[5], argv[3], params, &offsets);
    74 	}
    75 	else
    76 	{
    77 		ret = FindVFunc(handle, pVtable, "_ZTI", argv[3], params, &offsets);
    78 	}
    79 
    80 	if (ret)
    81 	{
    82 		if (params != NULL)
    83 		{
    84 			printf("%s%s - Win: %i  Linux : %i\n", argv[3], params, offsets.windows_offset, offsets.linux_offset);
    85 		}
    86 		else
    87 		{
    88 			printf("%s - Win: %i  Linux : %i\n", argv[3], offsets.windows_offset, offsets.linux_offset);
    89 		}
    90 		
    91 		dlclose(handle);
    92 		return 0;
    93 	}
    94 
    95 	fprintf(stderr, "Failed to find function!");
    96 	dlclose(handle);
    97 	return -1;
    98 }
    99 
   100 static bool FindVFunc(void *handle, void **vtable, const char* vtable_end, const char *class_function, const char *params, VOffset *offsets)
   101 {
   102 	Dl_info d;
   103 
   104 	int linux_offset = -1;
   105 	int windows_offset = -1;
   106 
   107 	int overloads = 0;
   108 	int location = 0;
   109 	int start_offset = -1;
   110 
   111 	for (int i=0; i< 1000; i++)
   112 	{
   113 		void *FuncPtr = vtable[i];
   114 
   115 		int status = dladdr(FuncPtr, &d);
   116 
   117 		if (!status)
   118 		{
   119 			continue;
   120 		}
   121 
   122 		if (i > 1 && strncmp(d.dli_sname, vtable_end, strlen(vtable_end)) == 0)
   123 		{
   124 			break;
   125 		}
   126 
   127 		char *name = cplus_demangle(d.dli_sname, DMGL_PARAMS);
   128 
   129 		if (name == NULL)
   130 		{
   131 			printf("Demangling failed\n");
   132 			continue;
   133 		}
   134 
   135 		char *foundfunction = strpbrk(name, ":");
   136 
   137 		if (foundfunction == NULL)
   138 		{
   139 			//printf("Couldnt split function\n");
   140 			free(name);
   141 			continue;
   142 		}
   143 
   144 		//Skip both ':' chars
   145 		foundfunction += 2;
   146 
   147 
   148 		if (strncmp(foundfunction, class_function, strlen(class_function)) == 0 && foundfunction[strlen(class_function)] == '(')
   149 		{
   150 			//printf("Symbol: %s Demangled: %s Offset: %i\n", d.dli_sname, name, i);
   151 
   152 			//We have a pointer to a function, but it may be overloaded.
   153 			overloads++;
   154 
   155 			if (start_offset == -1)
   156 			{
   157 				start_offset = i-1;
   158 			}
   159 
   160 			char *foundparams = strpbrk(foundfunction, "(");
   161 
   162 			if (foundparams == NULL)
   163 			{
   164 				printf("ARGH\n");
   165 				free(name);
   166 				continue;
   167 			}
   168 
   169 			if(params == NULL || strcmp(foundparams, params) == 0)
   170 			{
   171 				//This is actually our function - So this is the linux offset
   172 				linux_offset = i;
   173 				location = overloads;
   174 			}
   175 		}
   176 
   177 		free(name);
   178 	}
   179 
   180 	windows_offset = (overloads-location) + start_offset;
   181 
   182 	offsets->linux_offset = linux_offset - 2;
   183 	offsets->windows_offset = windows_offset - 2;
   184 
   185 	return true;
   186 }