diff options
-rw-r--r-- | winsup/utils/ChangeLog | 17 | ||||
-rw-r--r-- | winsup/utils/ldd.cc | 100 |
2 files changed, 104 insertions, 13 deletions
diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 09f570077..0d8e4681b 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,20 @@ +2009-03-14 Christopher Faylor <me+cygwin@cgf.cx> + + * ldd.cc (longopts): Add --dll option. + (get_module_filename): Generalized wrapper function which avoid path + length restrictions. + (load_dll): Handle special-case of inspecting a DLL. + (start_process): Accept an output parameter "isdll". Detect when file + to start is a DLL and start a wrapper instead. + (print_dlls_and_kill_inferior): When dealing with a DLL, avoid printing + everything before the DLL itself first appears. (This is not strictly + correct and should be fixed eventually) + (report): Deal with DLLs. Don't set a breakpoint for DLLs, just let + captive ldd process terminate normally. Pass dll info to + print_dlls_and_kill_inferior. + (main): Handle special-case "--dll" option by loading the DLL and + exiting. + 2009-03-14 Corinna Vinschen <corinna@vinschen.de> * path.cc (from_fstab): Use wcstombs/mbstowcs instead of diff --git a/winsup/utils/ldd.cc b/winsup/utils/ldd.cc index df374b49e..aaebe8413 100644 --- a/winsup/utils/ldd.cc +++ b/winsup/utils/ldd.cc @@ -50,6 +50,7 @@ struct option longopts[] = {"help", no_argument, NULL, 0}, {"version", no_argument, NULL, 0}, {"data-relocs", no_argument, NULL, 'd'}, + {"dll", no_argument, NULL, 'D'}, {"function-relocs", no_argument, NULL, 'r'}, {"unused", no_argument, NULL, 'u'}, {0, no_argument, NULL, 0} @@ -83,19 +84,65 @@ usage (const char *fmt, ...) static HANDLE hProcess; +static char * +get_module_filename (HANDLE hp, HMODULE hm) +{ + size_t len; + char *buf = NULL; + DWORD res; + for (len = 1024; (res = GetModuleFileNameEx (hp, hm, (buf = (char *) realloc (buf, len)), len)) == len; len += 1024) + continue; + if (!res) + { + free (buf); + buf = NULL; + } + return buf; +} + +static char * +load_dll (const char *fn) +{ + char *buf = get_module_filename (GetCurrentProcess (), NULL); + if (!buf) + { + printf ("ldd: GetModuleFileName returned an error %lu\n", GetLastError ()); + exit (1); /* FIXME */ + } + buf = (char *) realloc (buf, sizeof (" \"--dll\" \"\"") + strlen (buf)); + strcat (buf, " --dll \""); + strcat (buf, fn); + strcat (buf, "\""); + return buf; +} + + static int -start_process (const char *fn) +start_process (const char *fn, bool& isdll) { STARTUPINFO si = {}; PROCESS_INFORMATION pi; si.cb = sizeof (si); - if (CreateProcess (NULL, (CHAR *) fn, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi)) + CHAR *cmd; + if (strlen (fn) < 4 || strcasecmp (strchr (fn, '\0') - 4, ".dll") != 0) { + cmd = strdup (fn); + isdll = false; + } + else + { + cmd = load_dll (fn); + isdll = true; + } + if (CreateProcess (NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi)) + { + free (cmd); hProcess = pi.hProcess; DebugSetProcessKillOnExit (true); return 0; } + free (cmd); set_errno_and_return (1); } @@ -147,18 +194,31 @@ tocyg (char *win_fn) return fn; } +#define CYGWIN_DLL_LEN (strlen ("\\cygwin1.dll")) static int -print_dlls_and_kill_inferior (dlls *dll, const char *process_fn) +print_dlls_and_kill_inferior (dlls *dll, const char *dllfn, const char *process_fn) { + bool printit = !dllfn; while ((dll = dll->next)) { char *fn; - char fnbuf[MAX_PATH + 1]; - DWORD len = GetModuleFileNameEx (hProcess, (HMODULE) dll->lpBaseOfDll, fnbuf, sizeof(fnbuf) - 1); - if (!len) + char *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll); + if (!fullpath) fn = strdup ("???"); else - fn = tocyg (fnbuf); + { + if (printit) + fn = tocyg (fullpath); + else if (strcasecmp (fullpath, dllfn) != 0) + continue; + else + { + printit = true; + free (fullpath); + continue; + } + free (fullpath); + } printf ("\t%s => %s (%p)\n", basename (fn), fn, dll->lpBaseOfDll); free (fn); } @@ -181,11 +241,12 @@ report (const char *in_fn, bool multiple) if (len <= 0) print_errno_error_and_return (fn); + bool isdll; char fn_win[len + 1]; if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, fn, fn_win, len)) print_errno_error_and_return (fn); - if (!fn || start_process (fn_win)) + if (!fn || start_process (fn_win, isdll)) print_errno_error_and_return (in_fn); DEBUG_EVENT ev; @@ -211,7 +272,7 @@ report (const char *in_fn, bool multiple) switch (ev.dwDebugEventCode) { case LOAD_DLL_DEBUG_EVENT: - if (++dll_count == 2) + if (!isdll && ++dll_count == 2) get_entry_point (); dll_last->next = (dlls *) malloc (sizeof (dlls)); dll_last->next->lpBaseOfDll = ev.u.LoadDll.lpBaseOfDll; @@ -219,10 +280,19 @@ report (const char *in_fn, bool multiple) dll_last = dll_last->next; break; case EXCEPTION_DEBUG_EVENT: - if (ev.u.Exception.ExceptionRecord.ExceptionCode == STATUS_DLL_NOT_FOUND) - process_fn = fn_win; - else - print_dlls_and_kill_inferior (&dll_list, process_fn); + switch (ev.u.Exception.ExceptionRecord.ExceptionCode) + { + case STATUS_DLL_NOT_FOUND: + process_fn = fn_win; + break; + case STATUS_BREAKPOINT: + if (!isdll) + print_dlls_and_kill_inferior (&dll_list, isdll ? fn_win : NULL, process_fn); + break; + } + break; + case EXIT_PROCESS_DEBUG_EVENT: + print_dlls_and_kill_inferior (&dll_list, isdll ? fn_win : NULL, process_fn); break; default: break; @@ -252,6 +322,10 @@ main (int argc, char **argv) case 'u': usage ("option not implemented `-%c'", optch); exit (1); + case 'D': + if (!LoadLibrary (argv[optind])) + exit (1); + exit (0); case 0: if (index == 1) { |