1 #define _WIN32_WINNT 0x0501
2
3 #undef __STRICT_ANSI__
4
5 #include <errno.h>
6 #include <getopt.h>
7 #include <stdarg.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <wchar.h>
13 #include <locale.h>
14 #ifdef __CYGWIN__
15 #include <sys/cygwin.h>
16 #include <cygwin/version.h>
17 #define _wcsicmp wcscasecmp
18 #define _wcsnicmp wcsncasecmp
19 #define _wcsdup wcsdup
20 #endif
21 #include <unistd.h>
22 #include <libgen.h>
23
24
25 #ifndef _WIN32
26 #include <sys/param.h>
27 #define IsBadReadPtr(p, s) 0
28 #define DWORD unsigned int
29 #define WORD unsigned short
30 #define BYTE unsigned char
31 #define ULONGLONG unsigned long
32 #define _wcsdup(s) wcsdup(s)
33 #define _wcsicmp wcscasecmp
34 #define UnmapViewOfFile(p) free(p)
35
36 #define MAX_PATH PATH_MAX
37
38 typedef struct _IMAGE_IMPORT_DESCRIPTOR {
39 union {
40 DWORD Characteristics;
41 DWORD OriginalFirstThunk;
42 };
43 DWORD TimeDateStamp;
44 DWORD ForwarderChain;
45 DWORD Name;
46 DWORD FirstThunk;
47 } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
48
49 typedef struct _IMAGE_DOS_HEADER {
50 WORD e_magic;
51 WORD e_cblp;
52 WORD e_cp;
53 WORD e_crlc;
54 WORD e_cparhdr;
55 WORD e_minalloc;
56 WORD e_maxalloc;
57 WORD e_ss;
58 WORD e_sp;
59 WORD e_csum;
60 WORD e_ip;
61 WORD e_cs;
62 WORD e_lfarlc;
63 WORD e_ovno;
64 WORD e_res[4];
65 WORD e_oemid;
66 WORD e_oeminfo;
67 WORD e_res2[10];
68 DWORD e_lfanew;
69 } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
70
71 #define IMAGE_DOS_SIGNATURE 0x5A4D
72 #define IMAGE_SIZEOF_SHORT_NAME 8
73 #define IMAGE_NT_SIGNATURE 0x00004550
74 #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
75 #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
76
77 typedef struct _IMAGE_DATA_DIRECTORY {
78 DWORD VirtualAddress;
79 DWORD Size;
80 } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
81
82 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
83
84 typedef struct _IMAGE_SECTION_HEADER {
85 BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
86 union {
87 DWORD PhysicalAddress;
88 DWORD VirtualSize;
89 };
90 DWORD VirtualAddress;
91 DWORD SizeOfRawData;
92 DWORD PointerToRawData;
93 DWORD PointerToRelocations;
94 DWORD PointerToLinenumbers;
95 WORD NumberOfRelocations;
96 WORD NumberOfLinenumbers;
97 DWORD Characteristics;
98 } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
99
100 typedef struct _IMAGE_FILE_HEADER {
101 WORD Machine;
102 WORD NumberOfSections;
103 DWORD TimeDateStamp;
104 DWORD PointerToSymbolTable;
105 DWORD NumberOfSymbols;
106 WORD SizeOfOptionalHeader;
107 WORD Characteristics;
108 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
109
110 typedef struct _IMAGE_OPTIONAL_HEADER {
111 WORD Magic;
112 BYTE MajorLinkerVersion;
113 BYTE MinorLinkerVersion;
114 DWORD SizeOfCode;
115 DWORD SizeOfInitializedData;
116 DWORD SizeOfUninitializedData;
117 DWORD AddressOfEntryPoint;
118 DWORD BaseOfCode;
119 DWORD BaseOfData;
120 DWORD ImageBase;
121 DWORD SectionAlignment;
122 DWORD FileAlignment;
123 WORD MajorOperatingSystemVersion;
124 WORD MinorOperatingSystemVersion;
125 WORD MajorImageVersion;
126 WORD MinorImageVersion;
127 WORD MajorSubsystemVersion;
128 WORD MinorSubsystemVersion;
129 DWORD Win32VersionValue;
130 DWORD SizeOfImage;
131 DWORD SizeOfHeaders;
132 DWORD CheckSum;
133 WORD Subsystem;
134 WORD DllCharacteristics;
135 DWORD SizeOfStackReserve;
136 DWORD SizeOfStackCommit;
137 DWORD SizeOfHeapReserve;
138 DWORD SizeOfHeapCommit;
139 DWORD LoaderFlags;
140 DWORD NumberOfRvaAndSizes;
141 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
142 } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;
143
144 typedef struct _IMAGE_OPTIONAL_HEADER64 {
145 WORD Magic;
146 BYTE MajorLinkerVersion;
147 BYTE MinorLinkerVersion;
148 DWORD SizeOfCode;
149 DWORD SizeOfInitializedData;
150 DWORD SizeOfUninitializedData;
151 DWORD AddressOfEntryPoint;
152 DWORD BaseOfCode;
153 ULONGLONG ImageBase;
154 DWORD SectionAlignment;
155 DWORD FileAlignment;
156 WORD MajorOperatingSystemVersion;
157 WORD MinorOperatingSystemVersion;
158 WORD MajorImageVersion;
159 WORD MinorImageVersion;
160 WORD MajorSubsystemVersion;
161 WORD MinorSubsystemVersion;
162 DWORD Win32VersionValue;
163 DWORD SizeOfImage;
164 DWORD SizeOfHeaders;
165 DWORD CheckSum;
166 WORD Subsystem;
167 WORD DllCharacteristics;
168 ULONGLONG SizeOfStackReserve;
169 ULONGLONG SizeOfStackCommit;
170 ULONGLONG SizeOfHeapReserve;
171 ULONGLONG SizeOfHeapCommit;
172 DWORD LoaderFlags;
173 DWORD NumberOfRvaAndSizes;
174 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
175 } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64;
176
177 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1
178
179 #endif
180
181
182 static char const program_name[] = "ldd";
183
184
185 #ifdef _WIN32
186 #include <windows.h>
187 #include <imagehlp.h>
188 #include <psapi.h>
189 #endif
190 #include <wchar.h>
191
192 #ifndef STATUS_DLL_NOT_FOUND
193 # define STATUS_DLL_NOT_FOUND (0xC0000135L)
194 #endif
195
196
197 #ifndef FALSE
198 # define FALSE 0
199 # define TRUE 1
200 #endif
201
202
203 #define VERSION "2.0"
204
205
206 static int shortname;
207 static int pathname;
208
209
error(const char * fmt,...)210 static int error(const char *fmt,...)
211 {
212 va_list ap;
213
214 va_start(ap, fmt);
215 fprintf(stderr, "ldd: ");
216 vfprintf(stderr, fmt, ap);
217 fprintf(stderr, "\nTry `ldd --help' for more information.\n");
218 exit(1);
219 }
220
221
print_usage(void)222 static void print_usage(void)
223 {
224 printf("Usage: %s [OPTION]... FILE...\n\
225 \n\
226 Print shared library dependencies\n\
227 \n\
228 -h, --help print this help and exit\n\
229 -V, --version print version information and exit\n\
230 -r, --function-relocs process data and function relocations\n\
231 (currently unimplemented)\n\
232 -u, --unused print unused direct dependencies\n\
233 (currently unimplemented)\n\
234 -v, --verbose print all information\n\
235 (currently unimplemented)",
236 program_name);
237 }
238
239
print_version(void)240 static void print_version(void)
241 {
242 printf(
243 #if defined(__CYGWIN__)
244 "ldd (Cygwin) %d.%d.%d\n"
245 #elif defined(__MINGW32__)
246 #ifdef _WIN64
247 "ldd (MingW) (64bit) " VERSION "\n"
248 #else
249 "ldd (MingW) " VERSION "\n"
250 #endif
251 #elif defined(__WINE__)
252 #ifdef _WIN64
253 "ldd (wine) (64bit) " VERSION "\n"
254 #else
255 "ldd (wine) " VERSION "\n"
256 #endif
257 #elif defined(_MSC_VER)
258 #ifdef _WIN64
259 "ldd (MSVC) (64bit) " VERSION "\n"
260 #else
261 "ldd (MSVC) " VERSION "\n"
262 #endif
263 #else
264 "ldd " VERSION "\n"
265 #endif
266 "Print shared library dependencies\n"
267 "Copyright (C) 2009 - %s Chris Faylor\n"
268 "This is free software; see the source for copying conditions. There is NO\n"
269 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
270 #if defined(__CYGWIN__)
271 CYGWIN_VERSION_DLL_MAJOR / 1000,
272 CYGWIN_VERSION_DLL_MAJOR % 1000,
273 CYGWIN_VERSION_DLL_MINOR,
274 #endif
275 strrchr (__DATE__, ' ') + 1);
276 }
277
278
279 #define print_errno_error_and_return(__fn) \
280 do {\
281 fprintf (stderr, "ldd: %s: %s\n", (__fn), strerror (errno));\
282 return 1;\
283 } while (0)
284
285 static struct filelist
286 {
287 struct filelist *next;
288 wchar_t *name;
289 } *head;
290
291
292 #ifdef _WIN32
xstrdup(const char * s)293 static char *xstrdup(const char *s)
294 {
295 return strcpy(malloc(strlen(s) + 1), s);
296 }
297 #endif
298
299
saw_file(const wchar_t * name)300 static int saw_file(const wchar_t *name)
301 {
302 struct filelist *p;
303
304 for (p = head; p; p = p->next)
305 if (_wcsicmp(name, p->name) == 0)
306 return TRUE;
307
308 p = (struct filelist *) malloc(sizeof(struct filelist));
309
310 p->next = head;
311 p->name = _wcsdup(name);
312 head = p;
313 return FALSE;
314 }
315
316
317 #ifdef _WIN32
318 #define SLOP strlen (" (?)")
tocyg(wchar_t * win_fn)319 static char *tocyg(wchar_t *win_fn)
320 {
321 char *fn;
322 #ifdef __CYGWIN__
323 ssize_t cwlen = cygwin_conv_path(CCP_WIN_W_TO_POSIX, win_fn, NULL, 0);
324
325 if (cwlen > 0)
326 {
327 char *fn_cyg = (char *) malloc(cwlen + SLOP + 1);
328
329 if (cygwin_conv_path(CCP_WIN_W_TO_POSIX, win_fn, fn_cyg, cwlen) == 0)
330 fn = fn_cyg;
331 else
332 {
333 int len;
334
335 free(fn_cyg);
336 len = wcstombs(NULL, win_fn, 0);
337
338 fn = (char *) malloc(len + SLOP + 1);
339 wcstombs(fn, win_fn, len + SLOP + 1);
340 }
341 } else
342 #endif
343 {
344 int len = wcstombs(NULL, win_fn, 0) + 1;
345
346 if ((fn = (char *) malloc(len)) != NULL)
347 wcstombs(fn, win_fn, len);
348 }
349 return fn;
350 }
351 #endif
352
353
354 static int process_file(const wchar_t *filename, const char *internal_fn, const char *print_fn);
355
356
357 #ifdef _WIN32
358 WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *oldValue);
359 WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OldValue);
360 WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection);
361
362 /*
363 DWORD WINAPI GetFinalPathNameByHandleW(
364 HANDLE hFile,
365 LPWSTR lpszFilePath,
366 DWORD cchFilePath,
367 DWORD dwFlags
368 );
369
370 UINT WINAPI GetSystemWow64DirectoryW(
371 LPWSTR lpBuffer,
372 UINT uSize
373 );
374 */
375
376 typedef WINBOOL (WINAPI *PFNWOW64DISABLEWOW64FSREDIRECTION)(PVOID *oldValue);
377 typedef WINBOOL (WINAPI *PFNWOW64REVERTWOW64FSREDIRECTION)(PVOID OldValue);
378 typedef BOOL (WINAPI *PFNSETDLLDIRECTORYW)(LPWSTR name);
379 typedef DWORD (WINAPI *PFNGETFINALPATHNAMEBYHANDLEW)(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
380 typedef UINT (WINAPI *PFNGETSYSTEMWOW64DIRECTORYW)(LPWSTR buffer, UINT size);
381
382 static PFNWOW64DISABLEWOW64FSREDIRECTION p_Wow64DisableWow64FsRedirection;
383 static PFNWOW64REVERTWOW64FSREDIRECTION p_Wow64RevertWow64FsRedirection;
384 static PFNSETDLLDIRECTORYW p_SetDllDirectoryW;
385 static PFNGETFINALPATHNAMEBYHANDLEW p_GetFinalPathNameByHandleW;
386 static PFNGETSYSTEMWOW64DIRECTORYW p_GetSystemWow64DirectoryW;
387
388 #endif
389
390
391
392 /* dump of import directory
393 section begins at pointer 'section base'
394 section RVA is 'section_rva'
395 import directory begins at pointer 'imp' */
dump_import_directory(wchar_t * search_path,const void * const section_base,const DWORD section_rva,const IMAGE_IMPORT_DESCRIPTOR * imp,int is_64bit)396 static int dump_import_directory(wchar_t *search_path, const void *const section_base,
397 const DWORD section_rva,
398 const IMAGE_IMPORT_DESCRIPTOR *imp, int is_64bit)
399 {
400 int ret = 0;
401
402 /* get memory address given the RVA */
403 #define adr(rva) ((const void*) ((char*) section_base+((DWORD) (rva))-section_rva))
404
405 /* continue until address inaccessible or there's no DLL name */
406 for (; !IsBadReadPtr(imp, sizeof(*imp)) && imp->Name; imp++)
407 {
408 char *fn = (char *) adr(imp->Name);
409 wchar_t *fnw;
410 /* output DLL's name */
411 int len;
412
413 len = mbstowcs(NULL, fn, 0);
414
415 if (len <= 0)
416 continue;
417 fnw = (wchar_t *)malloc((len + 1) * sizeof(*fnw));
418
419 mbstowcs(fnw, fn, len + 1);
420
421 if (!saw_file(fnw))
422 {
423 #ifdef _WIN32
424 PVOID redirect;
425 wchar_t *dummy;
426 char *print_fn;
427 wchar_t full_path[MAX_PATH];
428
429 redirect = NULL;
430
431 if (is_64bit && p_Wow64DisableWow64FsRedirection)
432 p_Wow64DisableWow64FsRedirection(&redirect);
433
434 #ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
435 #define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x00000020
436 #endif
437
438 if (!SearchPathW(search_path, fnw, NULL, MAX_PATH, full_path, &dummy))
439 {
440 print_fn = xstrdup("not found");
441 if (shortname || pathname)
442 printf("notfound:%s\n", fn);
443 else
444 printf("\t%s => %s\n", fn, print_fn);
445 free(print_fn);
446 ret |= 1;
447 } else
448 {
449 if (strncmp(fn, "API-MS-", 7) != 0 && strncmp(fn, "api-ms-", 7) != 0)
450 {
451 print_fn = tocyg(full_path);
452 } else
453 {
454 print_fn = NULL;
455 }
456 ret |= process_file(full_path, fn, print_fn);
457 free(print_fn);
458 }
459 if (is_64bit && p_Wow64RevertWow64FsRedirection)
460 p_Wow64RevertWow64FsRedirection(redirect);
461 #else
462 printf("\t%s\n", fn);
463 #endif
464 }
465 free(fnw);
466 }
467 #undef adr
468
469 return ret;
470 }
471
472
473 /* load a file in RAM (memory-mapped)
474 return pointer to loaded file
475 0 if no success */
map_file(const wchar_t * filename)476 static void *map_file(const wchar_t *filename)
477 {
478 void *basepointer;
479 #ifdef _WIN32
480 HANDLE hFile, hMapping;
481
482 if ((hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
483 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
484 {
485 __extension__ fprintf(stderr, "couldn't open %ls\n", filename);
486 return 0;
487 }
488 if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
489 {
490 fprintf(stderr, "CreateFileMapping failed with windows error %u\n", (unsigned int) GetLastError());
491 CloseHandle(hFile);
492 return 0;
493 }
494 if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)))
495 {
496 fprintf(stderr, "MapViewOfFile failed with windows error %u\n", (unsigned int) GetLastError());
497 CloseHandle(hMapping);
498 CloseHandle(hFile);
499 return 0;
500 }
501 CloseHandle(hMapping);
502 CloseHandle(hFile);
503
504 #else
505 FILE *fp;
506 char fname[PATH_MAX];
507 size_t size;
508
509 wcstombs(fname, filename, sizeof(fname));
510 fp = fopen(fname, "rb");
511 if (fp == NULL)
512 {
513 fprintf(stderr, "can't open %s: %s\n", fname, strerror(errno));
514 return NULL;
515 }
516 fseek(fp, 0l, SEEK_END);
517 size = ftell(fp);
518 fseek(fp, 0l, SEEK_SET);
519 basepointer = malloc(size);
520 if (fread(basepointer, 1, size, fp) != size)
521 {
522 fprintf(stderr, "fread failed on %s: %s\n", fname, strerror(errno));
523 fclose(fp);
524 free(basepointer);
525 return NULL;
526 }
527 fclose(fp);
528 #endif
529 return basepointer;
530 }
531
532
533 /* this will return a pointer immediatly behind the DOS-header
534 0 if error */
skip_dos_stub(const wchar_t * filename,const IMAGE_DOS_HEADER * dos_ptr)535 static void *skip_dos_stub(const wchar_t *filename, const IMAGE_DOS_HEADER *dos_ptr)
536 {
537 /* look there's enough space for a DOS-header */
538 if (IsBadReadPtr(dos_ptr, sizeof(*dos_ptr)))
539 {
540 __extension__ fprintf(stderr, "%ls: not enough space for DOS-header\n", filename);
541 return 0;
542 }
543 /* validate MZ */
544 if (dos_ptr->e_magic != IMAGE_DOS_SIGNATURE)
545 {
546 __extension__ fprintf(stderr, "%ls: not a DOS-stub\n", filename);
547 return 0;
548 }
549 if (dos_ptr->e_lfarlc < 0x40 || dos_ptr->e_lfanew == 0)
550 {
551 __extension__ fprintf(stderr, "%ls: invalid DOS-stub\n", filename);
552 return 0;
553 }
554 /* ok, then, go get it */
555 return (char *) dos_ptr + dos_ptr->e_lfanew;
556 }
557
558
559 /* find the directory's section index given the RVA
560 Returns -1 if impossible */
get_directory_index(const unsigned dir_rva,const unsigned dir_length,const int number_of_sections,const IMAGE_SECTION_HEADER * sections)561 static int get_directory_index(const unsigned dir_rva,
562 const unsigned dir_length,
563 const int number_of_sections,
564 const IMAGE_SECTION_HEADER * sections)
565 {
566 int sect;
567
568 for (sect = 0; sect < number_of_sections; sect++)
569 {
570 /* compare directory RVA to section RVA */
571 if (sections[sect].VirtualAddress <= dir_rva
572 && dir_rva < sections[sect].VirtualAddress + sections[sect].SizeOfRawData)
573 return sect;
574 }
575
576 return -1;
577 }
578
579
580 /* ensure byte-alignment for struct tag_header */
581 #ifdef _WIN32
582 #include <pshpack1.h>
583 #else
584 #pragma pack(push,1)
585 #endif
586
587 struct tag_header
588 {
589 DWORD signature;
590 IMAGE_FILE_HEADER file_head;
591 union {
592 IMAGE_OPTIONAL_HEADER32 head32;
593 IMAGE_OPTIONAL_HEADER64 head64;
594 } opt;
595 };
596 /* revert to regular alignment */
597 #ifdef _WIN32
598 #include <poppack.h>
599 #else
600 #pragma pack(pop)
601 #endif
602
603
strccpy(char * s1,const char ** s2,char c)604 static char *strccpy(char *s1, const char **s2, char c)
605 {
606 while (**s2 && **s2 != c)
607 *s1++ = *((*s2)++);
608 *s1 = 0;
609 return s1;
610 }
611
612
combine_path(wchar_t ** list)613 static wchar_t *combine_path(wchar_t **list)
614 {
615 size_t len = 0;
616 wchar_t **p;
617 wchar_t *path, *dst;
618
619 p = list;
620 while (*p != NULL)
621 {
622 len += wcslen(*p) + 1;
623 p++;
624 }
625 path = malloc(len * sizeof(*path));
626 dst = path;
627 p = list;
628 while (*p != NULL)
629 {
630 if (dst > path)
631 *dst++ = ';';
632 wcscpy(dst, *p);
633 dst += wcslen(dst);
634 p++;
635 }
636 return path;
637 }
638
639
split_path(wchar_t * dst,const char * srcpath,size_t size,char delim,int is_64bit)640 static wchar_t **split_path(wchar_t *dst, const char *srcpath, size_t size, char delim, int is_64bit)
641 {
642 char *srcbuf;
643 wchar_t *d = dst - 1;
644 size_t count = 0;
645 int saw_current = 0;
646 #ifdef _WIN32
647 int saw_windows = 0;
648 int saw_system = 0;
649 wchar_t windows_dir[MAX_PATH];
650 wchar_t system_dir[MAX_PATH];
651 wchar_t syswow64_dir[MAX_PATH];
652 #endif
653 wchar_t **path_list, **listp;
654 const char *src = srcpath;
655
656 #ifdef _WIN32
657 GetWindowsDirectoryW(windows_dir, MAX_PATH);
658 GetSystemDirectoryW(system_dir, MAX_PATH);
659 if (!p_GetSystemWow64DirectoryW || !p_GetSystemWow64DirectoryW(syswow64_dir, MAX_PATH))
660 syswow64_dir[0] = 0;
661 #endif
662
663 srcbuf = malloc(size);
664 do
665 {
666 char *srcpath = srcbuf;
667 char *s = strccpy(srcpath, &src, delim);
668 size_t len = s - srcpath;
669 if (len >= MAX_PATH)
670 {
671 errno = ENAMETOOLONG;
672 return NULL;
673 }
674 /* Paths in Win32 path lists in the environment (%Path%), are often
675 enclosed in quotes (usually paths with spaces). Trailing backslashes
676 are common, too.Remove them.
677 */
678 if (delim == ';' && len)
679 {
680 if (*srcpath == '"')
681 {
682 ++srcpath;
683 *--s = '\0';
684 len -= 2;
685 }
686 while (len && s[-1] == '\\')
687 {
688 *--s = '\0';
689 --len;
690 }
691 }
692 if (strcmp(srcbuf, ".") == 0)
693 len = 0;
694 if (len)
695 {
696 ++d;
697 #ifdef __CYGWIN__
698 if (cygwin_conv_path(CCP_POSIX_TO_WIN_W, srcpath, d, size - (d - dst)))
699 return NULL;
700 #else
701 mbstowcs(d, srcpath, size - (d - dst));
702 #endif
703 } else
704 {
705 saw_current = 1;
706 ++d;
707 #ifdef __CYGWIN__
708 if (cygwin_conv_path(CCP_POSIX_TO_WIN_W, ".", d, size - (d - dst)))
709 return NULL;
710 #else
711 #ifdef _WIN32
712 GetCurrentDirectoryW(size - (d - dst), d);
713 #else
714 {
715 char dir[PATH_MAX];
716 getcwd(dir, sizeof(dir));
717 mbstowcs(d, dir, size - (d - dst));
718 }
719 #endif
720 #endif
721 }
722 count++;
723 #ifdef _WIN32
724 if (_wcsicmp(d, windows_dir) == 0)
725 saw_windows = 1;
726 if (_wcsicmp(d, system_dir) == 0)
727 saw_system = 1;
728 #endif
729 d = wcschr(d, '\0');
730 *d = delim;
731 } while (*src++);
732 if (d < dst)
733 d++;
734 *d = '\0';
735
736 path_list = listp = malloc((count + 5) * sizeof(char *));
737
738 d = dst;
739
740 *listp++ = d;
741 wcscpy(d, L"{appdir}");
742 d += wcslen(d);
743 *d++ = '\0';
744
745 #ifdef _WIN32
746 *listp++ = d;
747 if (!is_64bit && syswow64_dir[0])
748 wcscpy(d, syswow64_dir);
749 else
750 wcscpy(d, system_dir);
751 d += wcslen(d);
752 *d++ = '\0';
753
754 *listp++ = d;
755 wcscpy(d, windows_dir);
756 d += wcslen(d);
757 *d = '\0';
758 #endif
759
760 src = srcpath;
761 do
762 {
763 char *srcpath = srcbuf;
764 char *s = strccpy(srcpath, &src, delim);
765 size_t len = s - srcpath;
766 if (len >= MAX_PATH)
767 {
768 errno = ENAMETOOLONG;
769 return NULL;
770 }
771 /* Paths in Win32 path lists in the environment (%Path%), are often
772 enclosed in quotes (usually paths with spaces). Trailing backslashes
773 are common, too.Remove them.
774 */
775 if (delim == ';' && len)
776 {
777 if (*srcpath == '"')
778 {
779 ++srcpath;
780 *--s = '\0';
781 len -= 2;
782 }
783 while (len && s[-1] == '\\')
784 {
785 *--s = '\0';
786 --len;
787 }
788 }
789 if (strcmp(srcbuf, ".") == 0)
790 len = 0;
791 if (len)
792 {
793 ++d;
794 #ifdef __CYGWIN__
795 if (cygwin_conv_path(CCP_POSIX_TO_WIN_W, srcpath, d, size - (d - dst)))
796 return NULL;
797 #else
798 mbstowcs(d, srcpath, size - (d - dst));
799 #endif
800 } else
801 {
802 saw_current = 1;
803 ++d;
804 #ifdef __CYGWIN__
805 if (cygwin_conv_path(CCP_POSIX_TO_WIN_W, ".", d, size - (d - dst)))
806 return NULL;
807 #else
808 #ifdef _WIN32
809 GetCurrentDirectoryW(size - (d - dst), d);
810 #else
811 {
812 char dir[PATH_MAX];
813 getcwd(dir, sizeof(dir));
814 mbstowcs(d, dir, size - (d - dst));
815 }
816 #endif
817 #endif
818 }
819 #ifdef _WIN32
820 if (_wcsicmp(d, system_dir) == 0 && !is_64bit && syswow64_dir[0])
821 wcscpy(d, syswow64_dir);
822 #endif
823 *listp++ = d;
824 d = wcschr(d, '\0');
825 *d = '\0';
826 } while (*src++);
827 *d = '\0';
828 *listp = NULL;
829 free(srcbuf);
830 (void) saw_current;
831 #ifdef _WIN32
832 (void) saw_system;
833 (void) saw_windows;
834 #endif
835 return path_list;
836 }
837
838
839
840 /* dump imports of a single file
841 Returns 0 if successful, !=0 else */
process_file(const wchar_t * filename,const char * internal_fn,const char * print_fn)842 static int process_file(const wchar_t *filename, const char *internal_fn, const char *print_fn)
843 {
844 void *basepointer; /* Points to loaded PE file */
845 int number_of_sections;
846 DWORD import_rva; /* RVA of import directory */
847 DWORD import_length; /* length of import directory */
848 const IMAGE_SECTION_HEADER *section_headers; /* an array of unknown length */
849 int import_index; /* index of section with import directory */
850 const void *section_address;
851 const struct tag_header *header;
852 int is_64bit = 0;
853 wchar_t *dir;
854 wchar_t *p1, *p2;
855 wchar_t *path_w;
856 wchar_t **search_path_split;
857 wchar_t *search_path;
858 ssize_t len;
859 char *path;
860 ULONGLONG ImageBase;
861
862 /* first, load file */
863 basepointer = map_file(filename);
864 if (!basepointer)
865 {
866 __extension__ fprintf(stderr, "%ls: cannot load file\n", filename);
867 return 1;
868 }
869 /* get header pointer; validate a little bit */
870 header = (struct tag_header *) skip_dos_stub(filename, (IMAGE_DOS_HEADER *) basepointer);
871 if (!header)
872 {
873 __extension__ fprintf(stderr, "%ls: cannot skip DOS stub\n", filename);
874 UnmapViewOfFile(basepointer);
875 return 2;
876 }
877 /* look there's enough space for PE headers */
878 if (IsBadReadPtr(header, sizeof(*header)))
879 {
880 __extension__ fprintf(stderr, "%ls: not enough space for PE headers\n", filename);
881 UnmapViewOfFile(basepointer);
882 return 3;
883 }
884 /* validate PE signature */
885 if (header->signature != IMAGE_NT_SIGNATURE)
886 {
887 __extension__ fprintf(stderr, "%ls: not a PE file\n", filename);
888 UnmapViewOfFile(basepointer);
889 return 4;
890 }
891 if (header->opt.head32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
892 header->file_head.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
893 {
894 /* get number of sections */
895 number_of_sections = header->file_head.NumberOfSections;
896
897 /* check there are sections... */
898 if (number_of_sections < 1)
899 {
900 UnmapViewOfFile(basepointer);
901 return 5;
902 }
903 /* get RVA and length of import directory */
904 import_rva = header->opt.head32.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
905 import_length = header->opt.head32.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
906 ImageBase = header->opt.head32.ImageBase;
907 } else if (header->opt.head64.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC &&
908 header->file_head.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
909 {
910 /* get number of sections */
911 number_of_sections = header->file_head.NumberOfSections;
912
913 /* check there are sections... */
914 if (number_of_sections < 1)
915 {
916 UnmapViewOfFile(basepointer);
917 return 5;
918 }
919 /* get RVA and length of import directory */
920 import_rva = header->opt.head64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
921 import_length = header->opt.head64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
922 ImageBase = header->opt.head64.ImageBase;
923 is_64bit = 1;
924 } else
925 {
926 __extension__ fprintf(stderr, "%ls: unknown PE file\n", filename);
927 UnmapViewOfFile(basepointer);
928 return 4;
929 }
930 if (print_fn)
931 {
932 if (pathname)
933 {
934 printf("%s\n", print_fn);
935 } else if (shortname)
936 {
937 printf("%s\n", internal_fn);
938 } else
939 {
940 #ifdef __MINGW32__
941 printf("\t%s => %s (0x%I64x)\n", internal_fn, print_fn, ImageBase);
942 #else
943 printf("\t%s => %s (0x%llx)\n", internal_fn, print_fn, (unsigned long long) ImageBase);
944 #endif
945 }
946 }
947
948 section_headers = (const IMAGE_SECTION_HEADER *)((char *)header + offsetof(struct tag_header, opt) + header->file_head.SizeOfOptionalHeader);
949 /* validate there's enough space for section headers */
950 if (IsBadReadPtr(section_headers, number_of_sections * sizeof(IMAGE_SECTION_HEADER)))
951 {
952 __extension__ fprintf(stderr, "%ls: not enough space for section headers\n", filename);
953 UnmapViewOfFile(basepointer);
954 return 6;
955 }
956
957 /* check there's stuff to care about */
958 if (!import_rva || !import_length)
959 {
960 UnmapViewOfFile(basepointer);
961 return 0; /* success! */
962 }
963 /* get import directory pointer */
964 import_index = get_directory_index(import_rva, import_length, number_of_sections, section_headers);
965
966 /* check directory was found */
967 if (import_index < 0)
968 {
969 __extension__ fprintf(stderr, "%ls: couldn't find import directory in sections\n", filename);
970 UnmapViewOfFile(basepointer);
971 return 7;
972 }
973 /* The pointer to the start of the import directory's section */
974 section_address = (char *) basepointer + section_headers[import_index].PointerToRawData;
975
976 dir = _wcsdup(filename);
977 p1 = wcsrchr(dir, '\\');
978 p2 = wcsrchr(dir, '/');
979 if (p1 == NULL || p2 > p1)
980 p1 = p2;
981 if (p1 == NULL)
982 {
983 free(dir);
984 dir = _wcsdup(L".");
985 } else
986 {
987 p1[0] = 0;
988 }
989
990 /*
991 * setup a path such that SearchPath uses the same
992 * search order as LoadLibrary.
993 * FIXME: this assumes current behavior of Windows
994 * and may break if the behavior of LoadLibrary() changes
995 * in future version of windows.
996 */
997 path = getenv("PATH");
998 #if defined(__CYGWIN__) || !defined(_WIN32)
999 len = strlen(path);
1000 if (len <= 0)
1001 print_errno_error_and_return("PATH");
1002 len = len * 2 + 1 + 5 * MAX_PATH;
1003 path_w = malloc(len * sizeof(*path_w));
1004
1005 search_path_split = split_path(path_w, path, len, ':', is_64bit);
1006 #else
1007 len = mbstowcs(NULL, path, 0) + 1;
1008 if (len <= 0)
1009 print_errno_error_and_return("PATH");
1010 len = len + 1 + 5 * MAX_PATH;
1011 path_w = malloc(len * sizeof(*path_w));
1012 search_path_split = split_path(path_w, path, len, ';', is_64bit);
1013 #endif
1014
1015 if (search_path_split == NULL)
1016 print_errno_error_and_return("PATH");
1017
1018 search_path_split[0] = dir;
1019 search_path = combine_path(search_path_split);
1020 free(path_w);
1021
1022 if (dump_import_directory(search_path, section_address,
1023 section_headers[import_index].VirtualAddress,
1024 /* the last parameter is the pointer to the import directory:
1025 section address + (import RVA - section RVA)
1026 The difference is the offset of the import directory in the section */
1027 (const IMAGE_IMPORT_DESCRIPTOR *) ((char *) section_address + import_rva - section_headers[import_index].VirtualAddress),
1028 is_64bit))
1029 {
1030 free(dir);
1031 UnmapViewOfFile(basepointer);
1032 return 8;
1033 }
1034 free(dir);
1035 UnmapViewOfFile(basepointer);
1036 return 0;
1037 }
1038
1039
report(const char * in_fn)1040 static int report(const char *in_fn)
1041 {
1042 ssize_t len;
1043 wchar_t *fn_win;
1044 struct filelist *p;
1045 int ret;
1046
1047 #ifdef __CYGWIN__
1048 len = cygwin_conv_path(CCP_POSIX_TO_WIN_W, in_fn, NULL, 0);
1049
1050 if (len <= 0)
1051 print_errno_error_and_return(in_fn);
1052 fn_win = malloc((len + 1) * sizeof(*fn_win));
1053
1054 if (cygwin_conv_path(CCP_POSIX_TO_WIN_W, in_fn, fn_win, len))
1055 print_errno_error_and_return(in_fn);
1056 #else
1057 len = mbstowcs(NULL, in_fn, 0) + 1;
1058 if (len <= 0)
1059 print_errno_error_and_return(in_fn);
1060 fn_win = malloc((len + 1) * sizeof(*fn_win));
1061 mbstowcs(fn_win, in_fn, len);
1062 #endif
1063
1064 head = NULL;
1065 ret = process_file(fn_win, NULL, NULL);
1066 while (head)
1067 {
1068 free(head->name);
1069 p = head->next;
1070 free(head);
1071 head = p;
1072 }
1073 free(fn_win);
1074 return ret;
1075 }
1076
1077
1078 static struct option const longopts[] =
1079 {
1080 { "help", no_argument, NULL, 'h' },
1081 { "verbose", no_argument, NULL, 'v' },
1082 { "version", no_argument, NULL, 'V' },
1083 { "data-relocs", no_argument, NULL, 'd' },
1084 { "function-relocs", no_argument, NULL, 'r' },
1085 { "unused", no_argument, NULL, 'u' },
1086 { "short", no_argument, NULL, 's' },
1087 { "path", no_argument, NULL, 'p' },
1088 { "multiple", no_argument, NULL, 'm' },
1089 { 0, no_argument, NULL, 0 }
1090 };
1091
1092
main(int argc,char ** argv)1093 int main(int argc, char **argv)
1094 {
1095 int optch;
1096 int ret = 0;
1097 int multiple;
1098 char *fn;
1099
1100 /* Use locale from environment. If not set or set to "C", use UTF-8. */
1101 setlocale(LC_CTYPE, "");
1102 if (!strcmp(setlocale(LC_CTYPE, NULL), "C"))
1103 setlocale(LC_CTYPE, "en_US.UTF-8");
1104
1105 multiple = 0;
1106 shortname = 0;
1107 pathname = 0;
1108
1109 while ((optch = getopt_long(argc, argv, "mdhprsuvV", longopts, NULL)) != -1)
1110 {
1111 switch (optch)
1112 {
1113 case 'd':
1114 case 'r':
1115 case 'u':
1116 error("option not implemented `-%c'", optch);
1117 exit(1);
1118 break;
1119 case 'v':
1120 break;
1121 case 'm':
1122 multiple = 1;
1123 break;
1124 case 's':
1125 shortname = 1;
1126 break;
1127 case 'p':
1128 pathname = 1;
1129 break;
1130 case 'h':
1131 print_usage();
1132 return 0;
1133 case 'V':
1134 print_version();
1135 return 0;
1136 default:
1137 fprintf (stderr, "Try `%s --help' for more information.\n", program_name);
1138 return 1;
1139 }
1140 }
1141
1142 if ((argc - optind) <= 0)
1143 error("missing file arguments");
1144
1145 if ((argc - optind) > 1)
1146 multiple = 1;
1147
1148 #ifdef _WIN32
1149 p_Wow64DisableWow64FsRedirection = (PFNWOW64DISABLEWOW64FSREDIRECTION)GetProcAddress(GetModuleHandleA("kernel32.dll"), "Wow64DisableWow64FsRedirection");
1150 p_Wow64RevertWow64FsRedirection = (PFNWOW64REVERTWOW64FSREDIRECTION)GetProcAddress(GetModuleHandleA("kernel32.dll"), "Wow64RevertWow64FsRedirection");
1151 p_SetDllDirectoryW = (PFNSETDLLDIRECTORYW)GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryW");
1152 p_GetFinalPathNameByHandleW = (PFNGETFINALPATHNAMEBYHANDLEW)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetFinalPathNameByHandleW");
1153 p_GetSystemWow64DirectoryW = (PFNGETSYSTEMWOW64DIRECTORYW)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetSystemWow64DirectoryW");
1154 #endif
1155
1156 while (optind < argc)
1157 {
1158 fn = argv[optind++];
1159 if (multiple)
1160 printf("%s:\n", fn);
1161
1162 if (report(fn) != 0)
1163 {
1164 ret = 1;
1165 }
1166 }
1167 exit(ret);
1168 return ret;
1169 }
1170