]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/ldd.cc
Cygwin: add 3.2.1 release file and add fixes up to this point
[newlib-cygwin.git] / winsup / utils / ldd.cc
CommitLineData
61522196 1/* Copyright (c) 2009, 2010, 2011, 2013 Chris Faylor
086dc27f
CF
2
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
6e623e93
CV
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
086dc27f
CF
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
15 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*/
26
27#include <errno.h>
28#include <getopt.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
2e13058e 33#include <wchar.h>
2e13058e 34#include <locale.h>
086dc27f 35#include <sys/cygwin.h>
92b499ac 36#include <cygwin/version.h>
086dc27f 37#include <unistd.h>
962acfe5 38#include <libgen.h>
086dc27f 39
d21b6359 40#define _WIN32_WINNT 0x0a00
086dc27f 41#include <windows.h>
e3ca53d9 42#include <winternl.h>
086dc27f
CF
43#include <imagehlp.h>
44#include <psapi.h>
45
086dc27f
CF
46struct option longopts[] =
47{
92b499ac
CV
48 {"help", no_argument, NULL, 'h'},
49 {"verbose", no_argument, NULL, 'v'},
50 {"version", no_argument, NULL, 'V'},
086dc27f
CF
51 {"data-relocs", no_argument, NULL, 'd'},
52 {"function-relocs", no_argument, NULL, 'r'},
53 {"unused", no_argument, NULL, 'u'},
54 {0, no_argument, NULL, 0}
55};
92b499ac 56const char *opts = "dhruvV";
086dc27f 57
2e13058e 58static int process_file (const wchar_t *);
e3ca53d9 59static void *drive_map;
962acfe5 60
086dc27f 61static int
92b499ac 62error (const char *fmt, ...)
086dc27f
CF
63{
64 va_list ap;
65 va_start (ap, fmt);
66 fprintf (stderr, "ldd: ");
67 vfprintf (stderr, fmt, ap);
68 fprintf (stderr, "\nTry `ldd --help' for more information.\n");
69 exit (1);
70}
71
e7fca6f8 72static void __attribute__ ((__noreturn__))
92b499ac
CV
73usage ()
74{
75 printf ("Usage: %s [OPTION]... FILE...\n\
76\n\
77Print shared library dependencies\n\
78\n\
79 -h, --help print this help and exit\n\
80 -V, --version print version information and exit\n\
81 -r, --function-relocs process data and function relocations\n\
82 (currently unimplemented)\n\
83 -u, --unused print unused direct dependencies\n\
84 (currently unimplemented)\n\
85 -v, --verbose print all information\n\
86 (currently unimplemented)\n",
87 program_invocation_short_name);
e7fca6f8 88 exit (0);
92b499ac
CV
89}
90
91static void
92print_version ()
93{
94 printf ("ldd (cygwin) %d.%d.%d\n"
1b23b30b
CF
95 "Print shared library dependencies\n"
96 "Copyright (C) 2009 - %s Chris Faylor\n"
97 "This is free software; see the source for copying conditions. There is NO\n"
92b499ac 98 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
1b23b30b
CF
99 CYGWIN_VERSION_DLL_MAJOR / 1000,
100 CYGWIN_VERSION_DLL_MAJOR % 1000,
101 CYGWIN_VERSION_DLL_MINOR,
102 strrchr (__DATE__, ' ') + 1);
92b499ac
CV
103}
104
086dc27f
CF
105#define print_errno_error_and_return(__fn) \
106 do {\
107 fprintf (stderr, "ldd: %s: %s\n", (__fn), strerror (errno));\
108 return 1;\
109 } while (0)
110
111#define set_errno_and_return(x) \
112 do {\
113 cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2);\
114 return (x);\
115 } while (0)
116
117
118static HANDLE hProcess;
119
c8fe6dc4
CF
120static struct filelist
121{
122 struct filelist *next;
123 char *name;
124} *head;
125
126static bool
127saw_file (char *name)
128{
129 filelist *p;
130
131 for (p = head; p; p = p->next)
132 if (strcasecmp (name, p->name) == 0)
133 return true;
134
135 p = (filelist *) malloc(sizeof (struct filelist));
136 p->next = head;
137 p->name = strdup (name);
138 head = p;
139 return false;
140}
141
2e13058e 142static wchar_t *
d5e4f55b
CF
143get_module_filename (HANDLE hp, HMODULE hm)
144{
145 size_t len;
2e13058e 146 wchar_t *buf = NULL;
d5e4f55b 147 DWORD res;
2e13058e 148 for (len = 1024; (res = GetModuleFileNameExW (hp, hm, (buf = (wchar_t *) realloc (buf, len * sizeof (wchar_t))), len)) == len; len += 1024)
d5e4f55b
CF
149 continue;
150 if (!res)
151 {
152 free (buf);
153 buf = NULL;
154 }
155 return buf;
156}
157
e3ca53d9
MG
158static BOOL
159GetFileNameFromHandle(HANDLE hFile, WCHAR pszFilename[MAX_PATH+1])
160{
161 BOOL result = FALSE;
162 ULONG len = 0;
163 OBJECT_NAME_INFORMATION *ntfn = (OBJECT_NAME_INFORMATION *) alloca (65536);
164 NTSTATUS status = NtQueryObject (hFile, ObjectNameInformation,
165 ntfn, 65536, &len);
166 if (NT_SUCCESS (status))
167 {
168 PWCHAR win32path = ntfn->Name.Buffer;
169 win32path[ntfn->Name.Length / sizeof (WCHAR)] = L'\0';
170
171 /* NtQueryObject returns a native NT path. (Try to) convert to Win32. */
172 if (!drive_map)
173 drive_map = (void *) cygwin_internal (CW_ALLOC_DRIVE_MAP);
174 if (drive_map)
175 win32path = (PWCHAR) cygwin_internal (CW_MAP_DRIVE_MAP, drive_map,
176 win32path);
177 pszFilename[0] = L'\0';
178 wcsncat (pszFilename, win32path, MAX_PATH);
179 result = TRUE;
180 }
181 return result;
182}
183
2e13058e
CF
184static wchar_t *
185load_dll (const wchar_t *fn)
d5e4f55b 186{
2e13058e 187 wchar_t *buf = get_module_filename (GetCurrentProcess (), NULL);
d5e4f55b
CF
188 if (!buf)
189 {
61522196
CV
190 printf ("ldd: GetModuleFileName returned an error %u\n",
191 (unsigned int) GetLastError ());
d5e4f55b
CF
192 exit (1); /* FIXME */
193 }
d5e4f55b 194
2e13058e
CF
195 wchar_t *newbuf = (wchar_t *) malloc ((sizeof (L"\"\" -- ") + wcslen (buf) + wcslen (fn)) * sizeof (wchar_t));
196 newbuf[0] = L'"';
197 wcscpy (newbuf + 1, buf);
198 wchar_t *p = wcsstr (newbuf, L"\\ldd");
199 if (!p)
200 {
201 printf ("ldd: can't parse my own filename \"%ls\"\n", buf);
202 exit (1);
203 }
204 p[3] = L'h';
205 wcscat (newbuf, L"\" -- ");
206 wcscat (newbuf, fn);
207 free (buf);
208 return newbuf;
209}
d5e4f55b 210
086dc27f 211static int
2e13058e 212start_process (const wchar_t *fn, bool& isdll)
086dc27f 213{
2e13058e 214 STARTUPINFOW si = {};
086dc27f
CF
215 PROCESS_INFORMATION pi;
216 si.cb = sizeof (si);
2e13058e 217 wchar_t *cmd;
abd9714a
YS
218 /* OCaml natdynlink plugins (.cmxs) cannot be handled by ldd because they
219 can only be loaded by flexdll_dlopen() */
220 if (wcslen (fn) < 4 || (wcscasecmp (wcschr (fn, L'\0') - 4, L".dll") != 0
221 && wcscasecmp (wcschr (fn, L'\0') - 4, L".oct") != 0
222 && wcscasecmp (wcschr (fn, L'\0') - 3, L".so") != 0))
086dc27f 223 {
2e13058e 224 cmd = wcsdup (fn);
d5e4f55b
CF
225 isdll = false;
226 }
227 else
228 {
229 cmd = load_dll (fn);
230 isdll = true;
231 }
2e13058e 232 if (CreateProcessW (NULL, cmd, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi))
d5e4f55b
CF
233 {
234 free (cmd);
086dc27f
CF
235 hProcess = pi.hProcess;
236 DebugSetProcessKillOnExit (true);
237 return 0;
238 }
239
d5e4f55b 240 free (cmd);
086dc27f
CF
241 set_errno_and_return (1);
242}
243
086dc27f
CF
244struct dlls
245 {
246 LPVOID lpBaseOfDll;
e3ca53d9 247 HANDLE hFile;
086dc27f
CF
248 struct dlls *next;
249 };
250
962acfe5
CF
251#define SLOP strlen (" (?)")
252char *
2e13058e 253tocyg (wchar_t *win_fn)
962acfe5 254{
2e13058e 255 ssize_t cwlen = cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, NULL, 0);
962acfe5
CF
256 char *fn;
257 if (cwlen <= 0)
2e13058e
CF
258 {
259 int len = wcstombs (NULL, win_fn, 0) + 1;
260 if ((fn = (char *) malloc (len)))
261 wcstombs (fn, win_fn, len);
262 }
962acfe5
CF
263 else
264 {
265 char *fn_cyg = (char *) malloc (cwlen + SLOP + 1);
2e13058e 266 if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, fn_cyg, cwlen) == 0)
962acfe5
CF
267 fn = fn_cyg;
268 else
269 {
270 free (fn_cyg);
2e13058e
CF
271 int len = wcstombs (NULL, win_fn, 0);
272 fn = (char *) malloc (len + SLOP + 1);
273 wcstombs (fn, win_fn, len + SLOP + 1);
962acfe5
CF
274 }
275 }
276 return fn;
277}
278
2e13058e 279#define CYGWIN_DLL_LEN (wcslen (L"\\cygwin1.dll"))
086dc27f 280static int
2e13058e 281print_dlls (dlls *dll, const wchar_t *dllfn, const wchar_t *process_fn)
086dc27f 282{
c8fe6dc4 283 head = NULL; /* FIXME: memory leak */
086dc27f
CF
284 while ((dll = dll->next))
285 {
286 char *fn;
2e13058e 287 wchar_t *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll);
d5e4f55b 288 if (!fullpath)
e3ca53d9
MG
289 {
290 // if no path found yet, try getting it from an open handle to the DLL
291 wchar_t dllname[MAX_PATH+1];
292 if (GetFileNameFromHandle (dll->hFile, dllname))
293 {
294 fn = tocyg (dllname);
295 saw_file (basename (fn));
296 }
297 else
298 fn = strdup ("???");
299 }
2e13058e
CF
300 else if (dllfn && wcscmp (fullpath, dllfn) == 0)
301 {
302 free (fullpath);
303 continue;
304 }
086dc27f 305 else
d5e4f55b 306 {
2e13058e 307 fn = tocyg (fullpath);
c8fe6dc4 308 saw_file (basename (fn));
d5e4f55b
CF
309 free (fullpath);
310 }
962acfe5 311 printf ("\t%s => %s (%p)\n", basename (fn), fn, dll->lpBaseOfDll);
086dc27f
CF
312 free (fn);
313 }
962acfe5
CF
314 if (process_fn)
315 return process_file (process_fn);
086dc27f
CF
316 return 0;
317}
318
319static int
320report (const char *in_fn, bool multiple)
321{
322 if (multiple)
323 printf ("%s:\n", in_fn);
324 char *fn = realpath (in_fn, NULL);
962acfe5
CF
325 if (!fn)
326 print_errno_error_and_return (in_fn);
327
2e13058e 328 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, NULL, 0);
962acfe5
CF
329 if (len <= 0)
330 print_errno_error_and_return (fn);
331
d5e4f55b 332 bool isdll;
16e1c98c
CV
333 wchar_t fn_win[len + 1];
334 if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, fn_win, len))
962acfe5
CF
335 print_errno_error_and_return (fn);
336
d5e4f55b 337 if (!fn || start_process (fn_win, isdll))
086dc27f
CF
338 print_errno_error_and_return (in_fn);
339
340 DEBUG_EVENT ev;
341
086dc27f
CF
342 dlls dll_list = {};
343 dlls *dll_last = &dll_list;
2e13058e 344 const wchar_t *process_fn = NULL;
a9da3e4e
JT
345
346 int res = 0;
347
086dc27f
CF
348 while (1)
349 {
2e13058e
CF
350 bool exitnow = false;
351 DWORD cont = DBG_CONTINUE;
352 if (!WaitForDebugEvent (&ev, INFINITE))
353 break;
086dc27f
CF
354 switch (ev.dwDebugEventCode)
355 {
85db2173
CV
356 case CREATE_PROCESS_DEBUG_EVENT:
357 if (!isdll)
358 {
359 PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER) alloca (4096);
360 PIMAGE_NT_HEADERS nt_header;
361 PVOID entry_point;
362 static const unsigned char int3 = 0xcc;
363 SIZE_T bytes;
364
365 if (!ReadProcessMemory (hProcess,
366 ev.u.CreateProcessInfo.lpBaseOfImage,
367 dos_header, 4096, &bytes))
368 print_errno_error_and_return (in_fn);
369
370 nt_header = PIMAGE_NT_HEADERS (PBYTE (dos_header)
371 + dos_header->e_lfanew);
372 entry_point = (PVOID)
373 ((caddr_t) ev.u.CreateProcessInfo.lpBaseOfImage
374 + nt_header->OptionalHeader.AddressOfEntryPoint);
375
376 if (!WriteProcessMemory (hProcess, entry_point, &int3, 1, &bytes))
377 print_errno_error_and_return (in_fn);
378 }
379 break;
086dc27f 380 case LOAD_DLL_DEBUG_EVENT:
086dc27f
CF
381 dll_last->next = (dlls *) malloc (sizeof (dlls));
382 dll_last->next->lpBaseOfDll = ev.u.LoadDll.lpBaseOfDll;
e3ca53d9 383 dll_last->next->hFile = ev.u.LoadDll.hFile;
086dc27f
CF
384 dll_last->next->next = NULL;
385 dll_last = dll_last->next;
386 break;
387 case EXCEPTION_DEBUG_EVENT:
d5e4f55b
CF
388 switch (ev.u.Exception.ExceptionRecord.ExceptionCode)
389 {
23ad79d7
CV
390 case STATUS_ENTRYPOINT_NOT_FOUND:
391 /* A STATUS_ENTRYPOINT_NOT_FOUND might be encountered right after
392 loading all DLLs. We have to handle it here, otherwise ldd
393 runs into an endless loop. */
394 goto print_and_exit;
d5e4f55b
CF
395 case STATUS_DLL_NOT_FOUND:
396 process_fn = fn_win;
397 break;
398 case STATUS_BREAKPOINT:
399 if (!isdll)
9f54cead 400 TerminateProcess (hProcess, 0);
d5e4f55b
CF
401 break;
402 }
a9da3e4e
JT
403 if (ev.u.Exception.ExceptionRecord.ExceptionFlags &
404 EXCEPTION_NONCONTINUABLE) {
405 res = 1;
406 goto print_and_exit;
407 }
d5e4f55b
CF
408 break;
409 case EXIT_PROCESS_DEBUG_EVENT:
f4a1b6ae
JT
410 if (ev.u.ExitProcess.dwExitCode != 0)
411 process_fn = fn_win;
23ad79d7 412print_and_exit:
2e13058e
CF
413 print_dlls (&dll_list, isdll ? fn_win : NULL, process_fn);
414 exitnow = true;
086dc27f
CF
415 break;
416 default:
417 break;
418 }
2e13058e 419 if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, cont))
086dc27f
CF
420 {
421 cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2);
422 print_errno_error_and_return (in_fn);
423 }
2e13058e
CF
424 if (exitnow)
425 break;
086dc27f
CF
426 }
427
a9da3e4e 428 return res;
086dc27f
CF
429}
430
086dc27f
CF
431int
432main (int argc, char **argv)
433{
434 int optch;
73535010
CV
435
436 /* Use locale from environment. If not set or set to "C", use UTF-8. */
437 setlocale (LC_CTYPE, "");
438 if (!strcmp (setlocale (LC_CTYPE, NULL), "C"))
439 setlocale (LC_CTYPE, "en_US.UTF-8");
92b499ac 440 while ((optch = getopt_long (argc, argv, opts, longopts, NULL)) != -1)
086dc27f
CF
441 switch (optch)
442 {
443 case 'd':
444 case 'r':
445 case 'u':
92b499ac 446 error ("option not implemented `-%c'", optch);
086dc27f 447 exit (1);
92b499ac
CV
448 case 'h':
449 usage ();
92b499ac
CV
450 case 'V':
451 print_version ();
452 return 0;
453 default:
454 fprintf (stderr, "Try `%s --help' for more information.\n",
455 program_invocation_short_name);
456 return 1;
086dc27f
CF
457 }
458 argv += optind;
459 if (!*argv)
92b499ac 460 error ("missing file arguments");
086dc27f
CF
461
462 int ret = 0;
463 bool multiple = !!argv[1];
464 char *fn;
465 while ((fn = *argv++))
466 if (report (fn, multiple))
467 ret = 1;
e3ca53d9
MG
468 if (drive_map)
469 cygwin_internal (CW_FREE_DRIVE_MAP, drive_map);
086dc27f
CF
470 exit (ret);
471}
962acfe5 472
962acfe5
CF
473static bool printing = false;
474
962acfe5
CF
475
476/* dump of import directory
477 section begins at pointer 'section base'
478 section RVA is 'section_rva'
479 import directory begins at pointer 'imp' */
480static int
481dump_import_directory (const void *const section_base,
482 const DWORD section_rva,
483 const IMAGE_IMPORT_DESCRIPTOR *imp)
484{
485 /* get memory address given the RVA */
486 #define adr(rva) ((const void*) ((char*) section_base+((DWORD) (rva))-section_rva))
487
488 /* continue until address inaccessible or there's no DLL name */
489 for (; !IsBadReadPtr (imp, sizeof (*imp)) && imp->Name; imp++)
490 {
2e13058e
CF
491 wchar_t full_path[PATH_MAX];
492 wchar_t *dummy;
962acfe5
CF
493 char *fn = (char *) adr (imp->Name);
494
495 if (saw_file (fn))
496 continue;
497
2e13058e
CF
498 int len = mbstowcs (NULL, fn, 0);
499 if (len <= 0)
1b23b30b 500 continue;
2e13058e
CF
501 wchar_t fnw[len + 1];
502 mbstowcs (fnw, fn, len + 1);
962acfe5
CF
503 /* output DLL's name */
504 char *print_fn;
2e13058e 505 if (!SearchPathW (NULL, fnw, NULL, PATH_MAX, full_path, &dummy))
962acfe5
CF
506 {
507 print_fn = strdup ("not found");
508 printing = true;
509 }
510 else if (!printing)
511 continue;
512 else
513 {
514 print_fn = tocyg (full_path);
515 strcat (print_fn, " (?)");
516 }
517
518 printf ("\t%s => %s\n", (char *) fn, print_fn);
519 free (print_fn);
520 }
521 #undef adr
522
523 return 0;
524}
525
526/* load a file in RAM (memory-mapped)
527 return pointer to loaded file
528 0 if no success */
529static void *
2e13058e 530map_file (const wchar_t *filename)
962acfe5
CF
531{
532 HANDLE hFile, hMapping;
533 void *basepointer;
2e13058e 534 if ((hFile = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
962acfe5
CF
535 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
536 {
2e13058e 537 fprintf (stderr, "couldn't open %ls\n", filename);
962acfe5
CF
538 return 0;
539 }
540 if (!(hMapping = CreateFileMapping (hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
541 {
61522196
CV
542 fprintf (stderr, "CreateFileMapping failed with windows error %u\n",
543 (unsigned int) GetLastError ());
962acfe5
CF
544 CloseHandle (hFile);
545 return 0;
546 }
547 if (!(basepointer = MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, 0)))
548 {
61522196
CV
549 fprintf (stderr, "MapViewOfFile failed with windows error %u\n",
550 (unsigned int) GetLastError ());
962acfe5
CF
551 CloseHandle (hMapping);
552 CloseHandle (hFile);
553 return 0;
554 }
1b23b30b 555
962acfe5
CF
556 CloseHandle (hMapping);
557 CloseHandle (hFile);
558
559 return basepointer;
560}
561
562
563/* this will return a pointer immediatly behind the DOS-header
564 0 if error */
565static void *
566skip_dos_stub (const IMAGE_DOS_HEADER *dos_ptr)
567{
568 /* look there's enough space for a DOS-header */
569 if (IsBadReadPtr (dos_ptr, sizeof (*dos_ptr)))
570 {
571 fprintf (stderr, "not enough space for DOS-header\n");
572 return 0;
573 }
574
575 /* validate MZ */
576 if (dos_ptr->e_magic != IMAGE_DOS_SIGNATURE)
577 {
578 fprintf (stderr, "not a DOS-stub\n");
579 return 0;
580 }
581
582 /* ok, then, go get it */
583 return (char*) dos_ptr + dos_ptr->e_lfanew;
584}
585
586
587/* find the directory's section index given the RVA
588 Returns -1 if impossible */
589static int
590get_directory_index (const unsigned dir_rva,
591 const unsigned dir_length,
592 const int number_of_sections,
593 const IMAGE_SECTION_HEADER *sections)
594{
595 int sect;
596 for (sect = 0; sect < number_of_sections; sect++)
597 {
598 /* compare directory RVA to section RVA */
599 if (sections[sect].VirtualAddress <= dir_rva
600 && dir_rva < sections[sect].VirtualAddress+sections[sect].SizeOfRawData)
601 return sect;
602 }
603
604 return -1;
605}
606
607/* dump imports of a single file
608 Returns 0 if successful, !=0 else */
609static int
2e13058e 610process_file (const wchar_t *filename)
962acfe5
CF
611{
612 void *basepointer; /* Points to loaded PE file
613 * This is memory mapped stuff
614 */
615 int number_of_sections;
616 DWORD import_rva; /* RVA of import directory */
617 DWORD import_length; /* length of import directory */
618 int import_index; /* index of section with import directory */
619
620 /* ensure byte-alignment for struct tag_header */
621 #include <pshpack1.h>
622
623 const struct tag_header
624 {
625 DWORD signature;
626 IMAGE_FILE_HEADER file_head;
627 IMAGE_OPTIONAL_HEADER opt_head;
c8fe6dc4 628 IMAGE_SECTION_HEADER section_header[1]; /* an array of unknown length */
962acfe5
CF
629 } *header;
630
631 /* revert to regular alignment */
632 #include <poppack.h>
633
962acfe5
CF
634 printing = false;
635
636 /* first, load file */
637 basepointer = map_file (filename);
638 if (!basepointer)
639 {
640 puts ("cannot load file");
641 return 1;
642 }
643
644 /* get header pointer; validate a little bit */
c8fe6dc4 645 header = (tag_header *) skip_dos_stub ((IMAGE_DOS_HEADER *) basepointer);
962acfe5
CF
646 if (!header)
647 {
648 puts ("cannot skip DOS stub");
649 UnmapViewOfFile (basepointer);
650 return 2;
651 }
652
653 /* look there's enough space for PE headers */
654 if (IsBadReadPtr (header, sizeof (*header)))
655 {
656 puts ("not enough space for PE headers");
657 UnmapViewOfFile (basepointer);
658 return 3;
659 }
660
661 /* validate PE signature */
c8fe6dc4 662 if (header->signature != IMAGE_NT_SIGNATURE)
962acfe5
CF
663 {
664 puts ("not a PE file");
665 UnmapViewOfFile (basepointer);
666 return 4;
667 }
668
669 /* get number of sections */
670 number_of_sections = header->file_head.NumberOfSections;
671
672 /* check there are sections... */
c8fe6dc4 673 if (number_of_sections < 1)
962acfe5
CF
674 {
675 UnmapViewOfFile (basepointer);
676 return 5;
677 }
678
679 /* validate there's enough space for section headers */
680 if (IsBadReadPtr (header->section_header, number_of_sections*sizeof (IMAGE_SECTION_HEADER)))
681 {
682 puts ("not enough space for section headers");
683 UnmapViewOfFile (basepointer);
684 return 6;
685 }
686
687 /* get RVA and length of import directory */
688 import_rva = header->opt_head.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
689 import_length = header->opt_head.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
690
691 /* check there's stuff to care about */
692 if (!import_rva || !import_length)
693 {
694 UnmapViewOfFile (basepointer);
695 return 0; /* success! */
696 }
697
698 /* get import directory pointer */
699 import_index = get_directory_index (import_rva,import_length,number_of_sections,header->section_header);
700
701 /* check directory was found */
c8fe6dc4 702 if (import_index < 0)
962acfe5
CF
703 {
704 puts ("couldn't find import directory in sections");
705 UnmapViewOfFile (basepointer);
706 return 7;
707 }
708
c8fe6dc4
CF
709 /* The pointer to the start of the import directory's section */
710 const void *section_address = (char*) basepointer + header->section_header[import_index].PointerToRawData;
711 if (dump_import_directory (section_address,
712 header->section_header[import_index].VirtualAddress,
713 /* the last parameter is the pointer to the import directory:
714 section address + (import RVA - section RVA)
715 The difference is the offset of the import directory in the section */
716 (const IMAGE_IMPORT_DESCRIPTOR *) ((char *) section_address+import_rva-header->section_header[import_index].VirtualAddress)))
717 {
718 UnmapViewOfFile (basepointer);
719 return 8;
720 }
1b23b30b 721
962acfe5
CF
722 UnmapViewOfFile (basepointer);
723 return 0;
724}
This page took 0.247204 seconds and 5 git commands to generate.