diff options
Diffstat (limited to 'winsup/utils/ldd.cc')
-rw-r--r-- | winsup/utils/ldd.cc | 664 |
1 files changed, 0 insertions, 664 deletions
diff --git a/winsup/utils/ldd.cc b/winsup/utils/ldd.cc deleted file mode 100644 index 018cdccb3..000000000 --- a/winsup/utils/ldd.cc +++ /dev/null @@ -1,664 +0,0 @@ -/* Copyright (c) 2009, 2010, 2011 Chris Faylor - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Neither the name of the owner nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include <errno.h> -#include <getopt.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <wchar.h> -#include <locale.h> -#include <sys/cygwin.h> -#include <cygwin/version.h> -#include <unistd.h> -#include <libgen.h> - -#define _WIN32_WINNT 0x0501 -#include <windows.h> -#include <imagehlp.h> -#include <psapi.h> - -#ifndef STATUS_DLL_NOT_FOUND -#define STATUS_DLL_NOT_FOUND (0xC0000135L) -#endif - -struct option longopts[] = -{ - {"help", no_argument, NULL, 'h'}, - {"verbose", no_argument, NULL, 'v'}, - {"version", no_argument, NULL, 'V'}, - {"data-relocs", no_argument, NULL, 'd'}, - {"function-relocs", no_argument, NULL, 'r'}, - {"unused", no_argument, NULL, 'u'}, - {0, no_argument, NULL, 0} -}; -const char *opts = "dhruvV"; - -static int process_file (const wchar_t *); - -static int -error (const char *fmt, ...) -{ - va_list ap; - va_start (ap, fmt); - fprintf (stderr, "ldd: "); - vfprintf (stderr, fmt, ap); - fprintf (stderr, "\nTry `ldd --help' for more information.\n"); - exit (1); -} - -static void -usage () -{ - printf ("Usage: %s [OPTION]... FILE...\n\ -\n\ -Print shared library dependencies\n\ -\n\ - -h, --help print this help and exit\n\ - -V, --version print version information and exit\n\ - -r, --function-relocs process data and function relocations\n\ - (currently unimplemented)\n\ - -u, --unused print unused direct dependencies\n\ - (currently unimplemented)\n\ - -v, --verbose print all information\n\ - (currently unimplemented)\n", - program_invocation_short_name); -} - -static void -print_version () -{ - printf ("ldd (cygwin) %d.%d.%d\n" - "Print shared library dependencies\n" - "Copyright (C) 2009 - %s Chris Faylor\n" - "This is free software; see the source for copying conditions. There is NO\n" - "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", - CYGWIN_VERSION_DLL_MAJOR / 1000, - CYGWIN_VERSION_DLL_MAJOR % 1000, - CYGWIN_VERSION_DLL_MINOR, - strrchr (__DATE__, ' ') + 1); -} - -#define print_errno_error_and_return(__fn) \ - do {\ - fprintf (stderr, "ldd: %s: %s\n", (__fn), strerror (errno));\ - return 1;\ - } while (0) - -#define set_errno_and_return(x) \ - do {\ - cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2);\ - return (x);\ - } while (0) - - -static HANDLE hProcess; - -static struct filelist -{ - struct filelist *next; - char *name; -} *head; - -static bool -saw_file (char *name) -{ - filelist *p; - - for (p = head; p; p = p->next) - if (strcasecmp (name, p->name) == 0) - return true; - - p = (filelist *) malloc(sizeof (struct filelist)); - p->next = head; - p->name = strdup (name); - head = p; - return false; -} - -static wchar_t * -get_module_filename (HANDLE hp, HMODULE hm) -{ - size_t len; - wchar_t *buf = NULL; - DWORD res; - for (len = 1024; (res = GetModuleFileNameExW (hp, hm, (buf = (wchar_t *) realloc (buf, len * sizeof (wchar_t))), len)) == len; len += 1024) - continue; - if (!res) - { - free (buf); - buf = NULL; - } - return buf; -} - -static wchar_t * -load_dll (const wchar_t *fn) -{ - wchar_t *buf = get_module_filename (GetCurrentProcess (), NULL); - if (!buf) - { - printf ("ldd: GetModuleFileName returned an error %lu\n", GetLastError ()); - exit (1); /* FIXME */ - } - - wchar_t *newbuf = (wchar_t *) malloc ((sizeof (L"\"\" -- ") + wcslen (buf) + wcslen (fn)) * sizeof (wchar_t)); - newbuf[0] = L'"'; - wcscpy (newbuf + 1, buf); - wchar_t *p = wcsstr (newbuf, L"\\ldd"); - if (!p) - { - printf ("ldd: can't parse my own filename \"%ls\"\n", buf); - exit (1); - } - p[3] = L'h'; - wcscat (newbuf, L"\" -- "); - wcscat (newbuf, fn); - free (buf); - return newbuf; -} - -static int -start_process (const wchar_t *fn, bool& isdll) -{ - STARTUPINFOW si = {}; - PROCESS_INFORMATION pi; - si.cb = sizeof (si); - wchar_t *cmd; - if (wcslen (fn) < 4 || wcscasecmp (wcschr (fn, L'\0') - 4, L".dll") != 0) - { - cmd = wcsdup (fn); - isdll = false; - } - else - { - cmd = load_dll (fn); - isdll = true; - } - if (CreateProcessW (NULL, cmd, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) - { - free (cmd); - hProcess = pi.hProcess; - DebugSetProcessKillOnExit (true); - return 0; - } - - free (cmd); - set_errno_and_return (1); -} - -static int -set_entry_point_break () -{ - HMODULE hm; - DWORD cb; - if (!EnumProcessModules (hProcess, &hm, sizeof (hm), &cb) || !cb) - set_errno_and_return (1); - - MODULEINFO mi = {}; - if (!GetModuleInformation (hProcess, hm, &mi, sizeof (mi)) || !mi.EntryPoint) - set_errno_and_return (1); - - static const unsigned char int3 = 0xcc; - if (!WriteProcessMemory (hProcess, mi.EntryPoint, &int3, 1, &cb) || cb != 1) - set_errno_and_return (1); - return 0; -} - -struct dlls - { - LPVOID lpBaseOfDll; - struct dlls *next; - }; - -#define SLOP strlen (" (?)") -char * -tocyg (wchar_t *win_fn) -{ - ssize_t cwlen = cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, NULL, 0); - char *fn; - if (cwlen <= 0) - { - int len = wcstombs (NULL, win_fn, 0) + 1; - if ((fn = (char *) malloc (len))) - wcstombs (fn, win_fn, len); - } - else - { - char *fn_cyg = (char *) malloc (cwlen + SLOP + 1); - if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, fn_cyg, cwlen) == 0) - fn = fn_cyg; - else - { - free (fn_cyg); - int len = wcstombs (NULL, win_fn, 0); - fn = (char *) malloc (len + SLOP + 1); - wcstombs (fn, win_fn, len + SLOP + 1); - } - } - return fn; -} - -#define CYGWIN_DLL_LEN (wcslen (L"\\cygwin1.dll")) -static int -print_dlls (dlls *dll, const wchar_t *dllfn, const wchar_t *process_fn) -{ - head = NULL; /* FIXME: memory leak */ - while ((dll = dll->next)) - { - char *fn; - wchar_t *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll); - if (!fullpath) - fn = strdup ("???"); - else if (dllfn && wcscmp (fullpath, dllfn) == 0) - { - free (fullpath); - continue; - } - else - { - fn = tocyg (fullpath); - saw_file (basename (fn)); - free (fullpath); - } - printf ("\t%s => %s (%p)\n", basename (fn), fn, dll->lpBaseOfDll); - free (fn); - } - if (process_fn) - return process_file (process_fn); - return 0; -} - -static int -report (const char *in_fn, bool multiple) -{ - if (multiple) - printf ("%s:\n", in_fn); - char *fn = realpath (in_fn, NULL); - if (!fn) - print_errno_error_and_return (in_fn); - - ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, NULL, 0); - if (len <= 0) - print_errno_error_and_return (fn); - - bool isdll; - wchar_t fn_win[len + 1]; - if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, fn_win, len)) - print_errno_error_and_return (fn); - - if (!fn || start_process (fn_win, isdll)) - print_errno_error_and_return (in_fn); - - DEBUG_EVENT ev; - - unsigned dll_count = 0; - - dlls dll_list = {}; - dlls *dll_last = &dll_list; - const wchar_t *process_fn = NULL; - while (1) - { - bool exitnow = false; - DWORD cont = DBG_CONTINUE; - if (!WaitForDebugEvent (&ev, INFINITE)) - break; - switch (ev.dwDebugEventCode) - { - case LOAD_DLL_DEBUG_EVENT: - if (!isdll && ++dll_count == 2) - set_entry_point_break (); - dll_last->next = (dlls *) malloc (sizeof (dlls)); - dll_last->next->lpBaseOfDll = ev.u.LoadDll.lpBaseOfDll; - dll_last->next->next = NULL; - dll_last = dll_last->next; - break; - case EXCEPTION_DEBUG_EVENT: - switch (ev.u.Exception.ExceptionRecord.ExceptionCode) - { - case STATUS_DLL_NOT_FOUND: - process_fn = fn_win; - break; - case STATUS_BREAKPOINT: - if (!isdll) - cont = DBG_EXCEPTION_NOT_HANDLED; - break; - } - break; - case CREATE_THREAD_DEBUG_EVENT: - TerminateProcess (hProcess, 0); - break; - case EXIT_PROCESS_DEBUG_EVENT: - print_dlls (&dll_list, isdll ? fn_win : NULL, process_fn); - exitnow = true; - break; - default: - break; - } - if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, cont)) - { - cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2); - print_errno_error_and_return (in_fn); - } - if (exitnow) - break; - } - - return 0; -} - -int -main (int argc, char **argv) -{ - int optch; - - /* Use locale from environment. If not set or set to "C", use UTF-8. */ - setlocale (LC_CTYPE, ""); - if (!strcmp (setlocale (LC_CTYPE, NULL), "C")) - setlocale (LC_CTYPE, "en_US.UTF-8"); - while ((optch = getopt_long (argc, argv, opts, longopts, NULL)) != -1) - switch (optch) - { - case 'd': - case 'r': - case 'u': - error ("option not implemented `-%c'", optch); - exit (1); - case 'h': - usage (); - exit (0); - case 'V': - print_version (); - return 0; - default: - fprintf (stderr, "Try `%s --help' for more information.\n", - program_invocation_short_name); - return 1; - } - argv += optind; - if (!*argv) - error ("missing file arguments"); - - int ret = 0; - bool multiple = !!argv[1]; - char *fn; - while ((fn = *argv++)) - if (report (fn, multiple)) - ret = 1; - exit (ret); -} - -static bool printing = false; - - -/* dump of import directory - section begins at pointer 'section base' - section RVA is 'section_rva' - import directory begins at pointer 'imp' */ -static int -dump_import_directory (const void *const section_base, - const DWORD section_rva, - const IMAGE_IMPORT_DESCRIPTOR *imp) -{ - /* get memory address given the RVA */ - #define adr(rva) ((const void*) ((char*) section_base+((DWORD) (rva))-section_rva)) - - /* continue until address inaccessible or there's no DLL name */ - for (; !IsBadReadPtr (imp, sizeof (*imp)) && imp->Name; imp++) - { - wchar_t full_path[PATH_MAX]; - wchar_t *dummy; - char *fn = (char *) adr (imp->Name); - - if (saw_file (fn)) - continue; - - int len = mbstowcs (NULL, fn, 0); - if (len <= 0) - continue; - wchar_t fnw[len + 1]; - mbstowcs (fnw, fn, len + 1); - /* output DLL's name */ - char *print_fn; - if (!SearchPathW (NULL, fnw, NULL, PATH_MAX, full_path, &dummy)) - { - print_fn = strdup ("not found"); - printing = true; - } - else if (!printing) - continue; - else - { - print_fn = tocyg (full_path); - strcat (print_fn, " (?)"); - } - - printf ("\t%s => %s\n", (char *) fn, print_fn); - free (print_fn); - } - #undef adr - - return 0; -} - -/* load a file in RAM (memory-mapped) - return pointer to loaded file - 0 if no success */ -static void * -map_file (const wchar_t *filename) -{ - HANDLE hFile, hMapping; - void *basepointer; - if ((hFile = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE) - { - fprintf (stderr, "couldn't open %ls\n", filename); - return 0; - } - if (!(hMapping = CreateFileMapping (hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0))) - { - fprintf (stderr, "CreateFileMapping failed with windows error %lu\n", GetLastError ()); - CloseHandle (hFile); - return 0; - } - if (!(basepointer = MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, 0))) - { - fprintf (stderr, "MapViewOfFile failed with windows error %lu\n", GetLastError ()); - CloseHandle (hMapping); - CloseHandle (hFile); - return 0; - } - - CloseHandle (hMapping); - CloseHandle (hFile); - - return basepointer; -} - - -/* this will return a pointer immediatly behind the DOS-header - 0 if error */ -static void * -skip_dos_stub (const IMAGE_DOS_HEADER *dos_ptr) -{ - /* look there's enough space for a DOS-header */ - if (IsBadReadPtr (dos_ptr, sizeof (*dos_ptr))) - { - fprintf (stderr, "not enough space for DOS-header\n"); - return 0; - } - - /* validate MZ */ - if (dos_ptr->e_magic != IMAGE_DOS_SIGNATURE) - { - fprintf (stderr, "not a DOS-stub\n"); - return 0; - } - - /* ok, then, go get it */ - return (char*) dos_ptr + dos_ptr->e_lfanew; -} - - -/* find the directory's section index given the RVA - Returns -1 if impossible */ -static int -get_directory_index (const unsigned dir_rva, - const unsigned dir_length, - const int number_of_sections, - const IMAGE_SECTION_HEADER *sections) -{ - int sect; - for (sect = 0; sect < number_of_sections; sect++) - { - /* compare directory RVA to section RVA */ - if (sections[sect].VirtualAddress <= dir_rva - && dir_rva < sections[sect].VirtualAddress+sections[sect].SizeOfRawData) - return sect; - } - - return -1; -} - -/* dump imports of a single file - Returns 0 if successful, !=0 else */ -static int -process_file (const wchar_t *filename) -{ - void *basepointer; /* Points to loaded PE file - * This is memory mapped stuff - */ - int number_of_sections; - DWORD import_rva; /* RVA of import directory */ - DWORD import_length; /* length of import directory */ - int import_index; /* index of section with import directory */ - - /* ensure byte-alignment for struct tag_header */ - #include <pshpack1.h> - - const struct tag_header - { - DWORD signature; - IMAGE_FILE_HEADER file_head; - IMAGE_OPTIONAL_HEADER opt_head; - IMAGE_SECTION_HEADER section_header[1]; /* an array of unknown length */ - } *header; - - /* revert to regular alignment */ - #include <poppack.h> - - printing = false; - - /* first, load file */ - basepointer = map_file (filename); - if (!basepointer) - { - puts ("cannot load file"); - return 1; - } - - /* get header pointer; validate a little bit */ - header = (tag_header *) skip_dos_stub ((IMAGE_DOS_HEADER *) basepointer); - if (!header) - { - puts ("cannot skip DOS stub"); - UnmapViewOfFile (basepointer); - return 2; - } - - /* look there's enough space for PE headers */ - if (IsBadReadPtr (header, sizeof (*header))) - { - puts ("not enough space for PE headers"); - UnmapViewOfFile (basepointer); - return 3; - } - - /* validate PE signature */ - if (header->signature != IMAGE_NT_SIGNATURE) - { - puts ("not a PE file"); - UnmapViewOfFile (basepointer); - return 4; - } - - /* get number of sections */ - number_of_sections = header->file_head.NumberOfSections; - - /* check there are sections... */ - if (number_of_sections < 1) - { - UnmapViewOfFile (basepointer); - return 5; - } - - /* validate there's enough space for section headers */ - if (IsBadReadPtr (header->section_header, number_of_sections*sizeof (IMAGE_SECTION_HEADER))) - { - puts ("not enough space for section headers"); - UnmapViewOfFile (basepointer); - return 6; - } - - /* get RVA and length of import directory */ - import_rva = header->opt_head.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; - import_length = header->opt_head.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; - - /* check there's stuff to care about */ - if (!import_rva || !import_length) - { - UnmapViewOfFile (basepointer); - return 0; /* success! */ - } - - /* get import directory pointer */ - import_index = get_directory_index (import_rva,import_length,number_of_sections,header->section_header); - - /* check directory was found */ - if (import_index < 0) - { - puts ("couldn't find import directory in sections"); - UnmapViewOfFile (basepointer); - return 7; - } - - /* The pointer to the start of the import directory's section */ - const void *section_address = (char*) basepointer + header->section_header[import_index].PointerToRawData; - if (dump_import_directory (section_address, - header->section_header[import_index].VirtualAddress, - /* the last parameter is the pointer to the import directory: - section address + (import RVA - section RVA) - The difference is the offset of the import directory in the section */ - (const IMAGE_IMPORT_DESCRIPTOR *) ((char *) section_address+import_rva-header->section_header[import_index].VirtualAddress))) - { - UnmapViewOfFile (basepointer); - return 8; - } - - UnmapViewOfFile (basepointer); - return 0; -} |