Installer: Make it easier to compile the script from the IDE
[msysgit.git] / src / depends / depends.c
blob72cbe891df2eefb069538040b4781712acf64ff5
1 #include <windows.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "directory.h"
6 #include "image.h"
7 #define EXECUTABLES "*.exe;*.dll;*.sys;*.pyd"
9 int SearchImport(char *ImportDLL, char *ImportFunction, char *SourcePath);
10 int SearchExport(char *ExportFunction, char *SourcePath);
11 int SearchImportWithImageHlp(char *InputPath, char *ImportDLL, char *ImportFunction);
12 int SearchExportWithImageHlp(char *InputPath, char *ExportFunction);
14 void Usage(char *ProgramName)
16 printf("Usage: %s test.dll c:\\dir\\test.exe\n", ProgramName);
17 printf("\tReport if c:\\dir\\test.exe imports test.dll\n");
18 printf("\nExamples:\n");
19 printf("%s test.dll!funcname c:\\dir\\test.exe\n", ProgramName);
20 printf("\tReport if c:\\dir\\test.exe imports test.dll!funcname\n");
21 printf("%s test.dll c:\\dir\n", ProgramName);
22 printf("\tFind executables importing test.dll in c:\\dir\n");
23 printf("%s test.dll!funcname c:\\dir\n", ProgramName);
24 printf("\tFind executables importing funcname from test.dll in c:\\dir\n");
25 printf("%s test!funcname c:\\dir\n", ProgramName);
26 printf("\tFind executables importing funcname from test.dll in c:\\dir\n");
27 printf("%s test!ord_1234 c:\\dir\n", ProgramName);
28 printf("\tFind executables importing ordinal 1234 (in decimal) from test.dll in c:\\dir\n");
29 printf("\tNOTE: this only works if there is no name associated with the function\n");
30 printf("%s -e funcname c:\\dir\n", ProgramName);
31 printf("\tFind all DLLs exporting funcname in c:\\dir\n");
34 // Try to match Target against Source
35 BOOL CompareFilenames(char *Target, char *Source)
37 DWORD i;
38 BOOL HasExtension = FALSE;
40 if (!Target || !Source || !Target[0] || !Source[0]) return FALSE;
41 if (strchr(Source, '.')) HasExtension = TRUE;
43 // If we don't need to consider that the source may lack an extension,
44 // then the lengths must be the same
45 if (HasExtension && strlen(Target) != strlen(Source)) return FALSE;
47 for (i = 0; i < strlen(Source); i++)
49 if (tolower(Target[i]) != tolower(Source[i])) return FALSE;
53 if (HasExtension)
55 if (Target[i]) return FALSE;
56 else return TRUE;
58 else
60 if (Target[i] == '.') return TRUE;
61 else return FALSE;
65 int main(int argc, char* argv[])
67 char *ImportFunction;
69 if (argc < 2)
71 Usage(argv[0]);
72 return -1;
75 if (argv[1][0] == '-')
78 if (tolower(argv[1][1]) != 'e')
80 fprintf(stderr, "Error: -e is the only valid option\n");
81 Usage(argv[0]);
82 return -1;
85 if (argc != 3 && argc != 4)
87 fprintf(stderr, "Error: incorrect number of parameters for export searching\n");
88 Usage(argv[0]);
89 return -1;
92 if (strchr(argv[2], '!'))
94 fprintf(stderr, "Error: you cannot pass a dll!func format with -e\n");
95 Usage(argv[0]);
96 return -1;
99 if (argc == 4) return SearchExport(argv[2], argv[3]);
100 else return SearchExport(argv[2], NULL);
103 else
105 if (argc != 3)
107 fprintf(stderr, "Error: incorrect number of parameters for import searching\n");
108 Usage(argv[0]);
109 return -1;
112 if ((ImportFunction = strchr(argv[1], '!')) != NULL)
114 *ImportFunction++ = '\0';
115 return SearchImport(argv[1], ImportFunction, argv[2]);
117 else return SearchImport(argv[1], NULL, argv[2]);
120 return 0;
123 int SearchImport(char *ImportDLL, char *ImportFunction, char *SourcePath)
125 PDIRECTORY_INFO pDirectory;
126 PSEARCH_RESULTS result;
128 if (!(pDirectory = DirectoryOpen(SourcePath, TRUE))) return -1;
129 if (!DirectorySearch(pDirectory, EXECUTABLES)) return -1;
131 for (result = pDirectory->pSearchResults; result; result = result->Next)
133 SearchImportWithImageHlp(result->FilePath, ImportDLL, ImportFunction);
136 DirectoryClose(pDirectory);
137 return 0;
140 int SearchImportWithImageHlp(char *InputPath, char *ImportDLL, char *ImportFunction)
142 DWORD i = 0;
143 BOOL ModuleFound;
144 char *Filename, *ModuleName;
146 // Used to read import table
147 LOADED_IMAGE Image;
148 IMAGE_DATA_DIRECTORY ImportDirectory;
149 PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
150 PIMAGE_THUNK_DATA pThunk, pThunkIAT;
151 PIMAGE_IMPORT_BY_NAME pOrdinalName;
152 USHORT ImportOrdinal = 0;
153 BOOL UseOrdinal = FALSE;
155 if (!(Filename = strrchr(InputPath, '\\')))
157 fprintf(stderr, "Error: unexpected file \"%s\"\n", InputPath);
158 return -1;
160 *Filename++ = '\0';
162 //printf("Loading %s\n", Filename);
163 // TODO: under what circumstances does this fail?
164 if (!MapAndLoad(Filename, InputPath, &Image, FALSE, TRUE))
166 fprintf(stderr, "Unable to map and load %s\n", Filename);
167 return -1;
170 ImportDirectory = Image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
171 if (!ImportDirectory.VirtualAddress) return 0; // no imports
173 if (ImportDirectory.Size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
175 fprintf(stderr, "Error loading %s: invalid import descriptor table (size < sizeof(IMAGE_IMPORT_DESCRIPTOR))\n", Filename);
176 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
177 return -1;
180 pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)GetAddressFromRVA(Image, ImportDirectory.VirtualAddress);
181 if (!pImportDescriptor)
183 fprintf(stderr, "Error loading %s: invalid import descriptor table (invalid RVA)\n", Filename);
184 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
185 return -1;
188 for (i = 0, ModuleFound = FALSE; i < ImportDirectory.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); i++)
190 ModuleName = (char *)GetAddressFromRVA(Image, pImportDescriptor->Name);
191 if (!ModuleName || !ModuleName[0]) break;
193 if (CompareFilenames(ModuleName, ImportDLL))
195 ModuleFound = TRUE;
196 break;
198 pImportDescriptor++;
201 if (!ModuleFound)
203 if (!UnMapAndLoad(&Image))
205 fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
206 return 0;
208 return -1;
211 if (!ImportFunction)
213 printf("Match found: %s\\%s imports the library %s\n", InputPath, Filename, ImportDLL);
214 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
215 return 1;
218 if (strncmp(ImportFunction, "ord_", 4) == 0)
220 ImportOrdinal = atoi(ImportFunction + 4);
221 if (!ImportOrdinal && ImportFunction[4] != '0')
223 fprintf(stderr, "Error: you passed an invalid ordinal\n");
224 fprintf(stderr, "Should be in the format ord_1234 where 1234 is a decimal number\n");
225 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
226 return -1;
228 UseOrdinal = TRUE;
231 pThunkIAT = (PIMAGE_THUNK_DATA)GetAddressFromRVA(Image, pImportDescriptor->FirstThunk);
232 if (!pImportDescriptor->OriginalFirstThunk) pThunk = pThunkIAT;
233 else pThunk = (PIMAGE_THUNK_DATA)GetAddressFromRVA(Image, pImportDescriptor->OriginalFirstThunk);
234 if (!pThunk || !pThunkIAT)
236 fprintf(stderr, "Error loading %s: invalid import descriptor table (neither thunk is set)\n", Filename);
237 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
238 return -1;
241 for (; ; pThunk++, pThunkIAT++)
243 if (!pThunk->u1.AddressOfData) break;
244 if (UseOrdinal && pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
246 if (ImportOrdinal == IMAGE_ORDINAL(pThunk->u1.Ordinal))
248 printf("Match found: %s\\%s imports ordinal %d from %s\n", InputPath, Filename, ImportOrdinal, ImportDLL);
249 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
250 return 1;
253 else
255 pOrdinalName = (PIMAGE_IMPORT_BY_NAME)GetAddressFromRVA(Image, (DWORD)pThunk->u1.AddressOfData);
256 if (!pOrdinalName) continue;
258 if (_stricmp(pOrdinalName->Name, ImportFunction) == 0)
260 printf("Match found: %s\\%s imports %s!%s\n", InputPath, Filename, ImportDLL, pOrdinalName->Name);
261 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
262 return 1;
267 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
268 return 0;
271 int SearchExport(char *ExportFunction, char *SourcePath)
273 PDIRECTORY_INFO pDirectory;
274 PSEARCH_RESULTS result;
276 if (!(pDirectory = DirectoryOpen(SourcePath, TRUE))) return -1;
277 if (!DirectorySearch(pDirectory, EXECUTABLES)) return -1;
279 for (result = pDirectory->pSearchResults; result; result = result->Next)
281 SearchExportWithImageHlp(result->FilePath, ExportFunction);
284 DirectoryClose(pDirectory);
285 return 0;
288 int SearchExportWithImageHlp(char *InputPath, char *ExportFunction)
290 char *Filename, *FunctionName;
291 // Used to read export table
292 PIMAGE_EXPORT_DIRECTORY pExportTable;
293 IMAGE_DATA_DIRECTORY ExportDirectory;
294 LOADED_IMAGE Image;
295 DWORD *pFunctions; // an RVA
296 DWORD *pNames; // an RVA
297 USHORT *pNameOrdinals;
298 USHORT i, j;
300 if (!(Filename = strrchr(InputPath, '\\')))
302 fprintf(stderr, "Error: unexpected file \"%s\"\n", InputPath);
303 return -1;
305 *Filename++ = '\0';
307 printf("Loading %s\n", Filename);
308 if (!MapAndLoad(Filename, InputPath, &Image, FALSE, TRUE))
310 fprintf(stderr, "Unable to map and load %s\n", Filename);
311 return -1;
314 ExportDirectory = Image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
315 if (!ExportDirectory.VirtualAddress) return 0; // no exports
317 if (ExportDirectory.Size < sizeof(IMAGE_EXPORT_DIRECTORY))
319 fprintf(stderr, "Error loading %s: invalid export table (size < sizeof(IMAGE_EXPORT_DIRECTORY))\n", Filename);
320 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
321 return -1;
324 pExportTable = (PIMAGE_EXPORT_DIRECTORY)GetAddressFromRVA(Image, ExportDirectory.VirtualAddress);
325 if (!pExportTable)
327 fprintf(stderr, "Error loading %s: invalid export table (invalid RVA)\n", Filename);
328 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
329 return -1;
332 pFunctions = (DWORD *)GetAddressFromRVA(Image, pExportTable->AddressOfFunctions);
333 pNameOrdinals = (USHORT *)GetAddressFromRVA(Image, pExportTable->AddressOfNameOrdinals);
334 pNames = (DWORD *)GetAddressFromRVA(Image, pExportTable->AddressOfNames);
336 if (!pFunctions || !pNameOrdinals || !pNames)
338 fprintf(stderr, "Error loading %s: invalid export table (invalid name/function/ordinal RVAs)\n", Filename);
339 if (!UnMapAndLoad(&Image)) fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
340 return -1;
343 // Rather than just read directly from pNames, we do this to ensure that we're matching
344 // a function instead of a variable
345 for (i = 0; i < pExportTable->NumberOfFunctions; i++)
347 if (!pFunctions[i]) continue;
349 for (j = 0; j < pExportTable->NumberOfNames; j++)
351 if (i == pNameOrdinals[j])
353 FunctionName = (char *)GetAddressFromRVA(Image, pNames[j]);
354 if (_stricmp(FunctionName, ExportFunction) == 0)
356 printf("Match found: %s\\%s exports %s\n", InputPath, Filename, FunctionName);
357 exit(0);
359 if (!UnMapAndLoad(&Image))
361 fprintf(stderr, "Error unloading %s (error code 0x%08lx)\n", Filename, GetLastError());
362 return -1;
364 return 1;
370 return 0;