]> sourceware.org Git - newlib-cygwin.git/blob - 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
1 /* Copyright (c) 2009, 2010, 2011, 2013 Chris Faylor
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
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.
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>
33 #include <wchar.h>
34 #include <locale.h>
35 #include <sys/cygwin.h>
36 #include <cygwin/version.h>
37 #include <unistd.h>
38 #include <libgen.h>
39
40 #define _WIN32_WINNT 0x0a00
41 #include <windows.h>
42 #include <winternl.h>
43 #include <imagehlp.h>
44 #include <psapi.h>
45
46 struct option longopts[] =
47 {
48 {"help", no_argument, NULL, 'h'},
49 {"verbose", no_argument, NULL, 'v'},
50 {"version", no_argument, NULL, 'V'},
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 };
56 const char *opts = "dhruvV";
57
58 static int process_file (const wchar_t *);
59 static void *drive_map;
60
61 static int
62 error (const char *fmt, ...)
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
72 static void __attribute__ ((__noreturn__))
73 usage ()
74 {
75 printf ("Usage: %s [OPTION]... FILE...\n\
76 \n\
77 Print 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);
88 exit (0);
89 }
90
91 static void
92 print_version ()
93 {
94 printf ("ldd (cygwin) %d.%d.%d\n"
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"
98 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
99 CYGWIN_VERSION_DLL_MAJOR / 1000,
100 CYGWIN_VERSION_DLL_MAJOR % 1000,
101 CYGWIN_VERSION_DLL_MINOR,
102 strrchr (__DATE__, ' ') + 1);
103 }
104
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
118 static HANDLE hProcess;
119
120 static struct filelist
121 {
122 struct filelist *next;
123 char *name;
124 } *head;
125
126 static bool
127 saw_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
142 static wchar_t *
143 get_module_filename (HANDLE hp, HMODULE hm)
144 {
145 size_t len;
146 wchar_t *buf = NULL;
147 DWORD res;
148 for (len = 1024; (res = GetModuleFileNameExW (hp, hm, (buf = (wchar_t *) realloc (buf, len * sizeof (wchar_t))), len)) == len; len += 1024)
149 continue;
150 if (!res)
151 {
152 free (buf);
153 buf = NULL;
154 }
155 return buf;
156 }
157
158 static BOOL
159 GetFileNameFromHandle(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
184 static wchar_t *
185 load_dll (const wchar_t *fn)
186 {
187 wchar_t *buf = get_module_filename (GetCurrentProcess (), NULL);
188 if (!buf)
189 {
190 printf ("ldd: GetModuleFileName returned an error %u\n",
191 (unsigned int) GetLastError ());
192 exit (1); /* FIXME */
193 }
194
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 }
210
211 static int
212 start_process (const wchar_t *fn, bool& isdll)
213 {
214 STARTUPINFOW si = {};
215 PROCESS_INFORMATION pi;
216 si.cb = sizeof (si);
217 wchar_t *cmd;
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))
223 {
224 cmd = wcsdup (fn);
225 isdll = false;
226 }
227 else
228 {
229 cmd = load_dll (fn);
230 isdll = true;
231 }
232 if (CreateProcessW (NULL, cmd, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi))
233 {
234 free (cmd);
235 hProcess = pi.hProcess;
236 DebugSetProcessKillOnExit (true);
237 return 0;
238 }
239
240 free (cmd);
241 set_errno_and_return (1);
242 }
243
244 struct dlls
245 {
246 LPVOID lpBaseOfDll;
247 HANDLE hFile;
248 struct dlls *next;
249 };
250
251 #define SLOP strlen (" (?)")
252 char *
253 tocyg (wchar_t *win_fn)
254 {
255 ssize_t cwlen = cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, NULL, 0);
256 char *fn;
257 if (cwlen <= 0)
258 {
259 int len = wcstombs (NULL, win_fn, 0) + 1;
260 if ((fn = (char *) malloc (len)))
261 wcstombs (fn, win_fn, len);
262 }
263 else
264 {
265 char *fn_cyg = (char *) malloc (cwlen + SLOP + 1);
266 if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, fn_cyg, cwlen) == 0)
267 fn = fn_cyg;
268 else
269 {
270 free (fn_cyg);
271 int len = wcstombs (NULL, win_fn, 0);
272 fn = (char *) malloc (len + SLOP + 1);
273 wcstombs (fn, win_fn, len + SLOP + 1);
274 }
275 }
276 return fn;
277 }
278
279 #define CYGWIN_DLL_LEN (wcslen (L"\\cygwin1.dll"))
280 static int
281 print_dlls (dlls *dll, const wchar_t *dllfn, const wchar_t *process_fn)
282 {
283 head = NULL; /* FIXME: memory leak */
284 while ((dll = dll->next))
285 {
286 char *fn;
287 wchar_t *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll);
288 if (!fullpath)
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 }
300 else if (dllfn && wcscmp (fullpath, dllfn) == 0)
301 {
302 free (fullpath);
303 continue;
304 }
305 else
306 {
307 fn = tocyg (fullpath);
308 saw_file (basename (fn));
309 free (fullpath);
310 }
311 printf ("\t%s => %s (%p)\n", basename (fn), fn, dll->lpBaseOfDll);
312 free (fn);
313 }
314 if (process_fn)
315 return process_file (process_fn);
316 return 0;
317 }
318
319 static int
320 report (const char *in_fn, bool multiple)
321 {
322 if (multiple)
323 printf ("%s:\n", in_fn);
324 char *fn = realpath (in_fn, NULL);
325 if (!fn)
326 print_errno_error_and_return (in_fn);
327
328 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, NULL, 0);
329 if (len <= 0)
330 print_errno_error_and_return (fn);
331
332 bool isdll;
333 wchar_t fn_win[len + 1];
334 if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, fn_win, len))
335 print_errno_error_and_return (fn);
336
337 if (!fn || start_process (fn_win, isdll))
338 print_errno_error_and_return (in_fn);
339
340 DEBUG_EVENT ev;
341
342 dlls dll_list = {};
343 dlls *dll_last = &dll_list;
344 const wchar_t *process_fn = NULL;
345
346 int res = 0;
347
348 while (1)
349 {
350 bool exitnow = false;
351 DWORD cont = DBG_CONTINUE;
352 if (!WaitForDebugEvent (&ev, INFINITE))
353 break;
354 switch (ev.dwDebugEventCode)
355 {
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;
380 case LOAD_DLL_DEBUG_EVENT:
381 dll_last->next = (dlls *) malloc (sizeof (dlls));
382 dll_last->next->lpBaseOfDll = ev.u.LoadDll.lpBaseOfDll;
383 dll_last->next->hFile = ev.u.LoadDll.hFile;
384 dll_last->next->next = NULL;
385 dll_last = dll_last->next;
386 break;
387 case EXCEPTION_DEBUG_EVENT:
388 switch (ev.u.Exception.ExceptionRecord.ExceptionCode)
389 {
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;
395 case STATUS_DLL_NOT_FOUND:
396 process_fn = fn_win;
397 break;
398 case STATUS_BREAKPOINT:
399 if (!isdll)
400 TerminateProcess (hProcess, 0);
401 break;
402 }
403 if (ev.u.Exception.ExceptionRecord.ExceptionFlags &
404 EXCEPTION_NONCONTINUABLE) {
405 res = 1;
406 goto print_and_exit;
407 }
408 break;
409 case EXIT_PROCESS_DEBUG_EVENT:
410 if (ev.u.ExitProcess.dwExitCode != 0)
411 process_fn = fn_win;
412 print_and_exit:
413 print_dlls (&dll_list, isdll ? fn_win : NULL, process_fn);
414 exitnow = true;
415 break;
416 default:
417 break;
418 }
419 if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, cont))
420 {
421 cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2);
422 print_errno_error_and_return (in_fn);
423 }
424 if (exitnow)
425 break;
426 }
427
428 return res;
429 }
430
431 int
432 main (int argc, char **argv)
433 {
434 int optch;
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");
440 while ((optch = getopt_long (argc, argv, opts, longopts, NULL)) != -1)
441 switch (optch)
442 {
443 case 'd':
444 case 'r':
445 case 'u':
446 error ("option not implemented `-%c'", optch);
447 exit (1);
448 case 'h':
449 usage ();
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;
457 }
458 argv += optind;
459 if (!*argv)
460 error ("missing file arguments");
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;
468 if (drive_map)
469 cygwin_internal (CW_FREE_DRIVE_MAP, drive_map);
470 exit (ret);
471 }
472
473 static bool printing = false;
474
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' */
480 static int
481 dump_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 {
491 wchar_t full_path[PATH_MAX];
492 wchar_t *dummy;
493 char *fn = (char *) adr (imp->Name);
494
495 if (saw_file (fn))
496 continue;
497
498 int len = mbstowcs (NULL, fn, 0);
499 if (len <= 0)
500 continue;
501 wchar_t fnw[len + 1];
502 mbstowcs (fnw, fn, len + 1);
503 /* output DLL's name */
504 char *print_fn;
505 if (!SearchPathW (NULL, fnw, NULL, PATH_MAX, full_path, &dummy))
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 */
529 static void *
530 map_file (const wchar_t *filename)
531 {
532 HANDLE hFile, hMapping;
533 void *basepointer;
534 if ((hFile = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
535 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
536 {
537 fprintf (stderr, "couldn't open %ls\n", filename);
538 return 0;
539 }
540 if (!(hMapping = CreateFileMapping (hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
541 {
542 fprintf (stderr, "CreateFileMapping failed with windows error %u\n",
543 (unsigned int) GetLastError ());
544 CloseHandle (hFile);
545 return 0;
546 }
547 if (!(basepointer = MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, 0)))
548 {
549 fprintf (stderr, "MapViewOfFile failed with windows error %u\n",
550 (unsigned int) GetLastError ());
551 CloseHandle (hMapping);
552 CloseHandle (hFile);
553 return 0;
554 }
555
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 */
565 static void *
566 skip_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 */
589 static int
590 get_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 */
609 static int
610 process_file (const wchar_t *filename)
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;
628 IMAGE_SECTION_HEADER section_header[1]; /* an array of unknown length */
629 } *header;
630
631 /* revert to regular alignment */
632 #include <poppack.h>
633
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 */
645 header = (tag_header *) skip_dos_stub ((IMAGE_DOS_HEADER *) basepointer);
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 */
662 if (header->signature != IMAGE_NT_SIGNATURE)
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... */
673 if (number_of_sections < 1)
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 */
702 if (import_index < 0)
703 {
704 puts ("couldn't find import directory in sections");
705 UnmapViewOfFile (basepointer);
706 return 7;
707 }
708
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 }
721
722 UnmapViewOfFile (basepointer);
723 return 0;
724 }
This page took 0.065274 seconds and 5 git commands to generate.