* ldd.cc (load_dll): Start helper program rather than ldd.exe.

(set_entry_point_break): Rename from get_entry_point.
(print_dlls): Rename from print_dlls_and_kill_inferior.  Avoid printing
specific dll name if we're looking at a dll.
(report): Always dump dlls on process exit.  Don't allow thread creation.
Accommodate get_entry_point rename.
(start_process): Start process with DEBUG_ONLY_THIS_PROCESS.
(longopts): Eliminate "dll" option.
(main): Ditto.
* ldd.cc: Use wide character Win32 paths throughout.
(load_dll): Fix size expression (add fn) in realloc.
This commit is contained in:
Christopher Faylor 2009-03-18 04:19:05 +00:00
parent cb55223679
commit 2e13058eac
3 changed files with 113 additions and 75 deletions

View File

@ -1,3 +1,21 @@
2009-03-17 Christopher Faylor <me+cygwin@cgf.cx>
* ldd.cc (load_dll): Start helper program rather than ldd.exe.
(set_entry_point_break): Rename from get_entry_point.
(print_dlls): Rename from print_dlls_and_kill_inferior. Avoid printing
specific dll name if we're looking at a dll.
(report): Always dump dlls on process exit. Don't allow thread
creation. Accommodate get_entry_point rename.
(start_process): Start process with DEBUG_ONLY_THIS_PROCESS.
(longopts): Eliminate "dll" option.
(main): Ditto.
2009-03-17 Corinna Vinschen <corinna@vinschen.de>
Christopher Faylor <me+cygwin@cgf.cx>
* ldd.cc: Use wide character Win32 paths throughout.
(load_dll): Fix size expression (add fn) in realloc.
2009-03-14 Christopher Faylor <me+cygwin@cgf.cx> 2009-03-14 Christopher Faylor <me+cygwin@cgf.cx>
* ldd.cc (longopts): Add --dll option. * ldd.cc (longopts): Add --dll option.

View File

@ -57,12 +57,12 @@ CYGWIN_BINS := ${addsuffix .exe,cygpath getfacl ldd kill mkgroup \
# List all binaries to be linked in MinGW mode. Each binary on this list # List all binaries to be linked in MinGW mode. Each binary on this list
# must have a corresponding .o of the same name. # must have a corresponding .o of the same name.
MINGW_BINS := ${addsuffix .exe,strace cygcheck} MINGW_BINS := ${addsuffix .exe,cygcheck ldh strace}
# List all objects to be compiled in MinGW mode. Any object not on this # List all objects to be compiled in MinGW mode. Any object not on this
# list will will be compiled in Cygwin mode implicitly, so there is no # list will will be compiled in Cygwin mode implicitly, so there is no
# need for a CYGWIN_OBJS. # need for a CYGWIN_OBJS.
MINGW_OBJS := bloda.o cygcheck.o dump_setup.o path.o strace.o MINGW_OBJS := bloda.o cygcheck.o dump_setup.o ldh.o path.o strace.o
# If a binary should link in any objects besides the .o with the same # If a binary should link in any objects besides the .o with the same
# name as the binary, then list those here. # name as the binary, then list those here.
@ -75,6 +75,9 @@ cygpath.exe: ALL_LDFLAGS += -lntdll
ldd.exe: ALL_LDFLAGS += -lpsapi ldd.exe: ALL_LDFLAGS += -lpsapi
ldh.exe: MINGW_LDLIBS :=
ldh.exe: MINGW_LDFLAGS := -nostdlib -lkernel32
# Check for dumper's requirements and enable it if found. # Check for dumper's requirements and enable it if found.
LIBICONV := @libiconv@ LIBICONV := @libiconv@
libbfd := ${shell $(CC) -B$(bupdir2)/bfd/ --print-file-name=libbfd.a} libbfd := ${shell $(CC) -B$(bupdir2)/bfd/ --print-file-name=libbfd.a}

View File

@ -30,6 +30,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wchar.h>
#undef wcscasecmp /* Disable definition from Cygwin's internal wchar.h. */
#include <locale.h>
#include <sys/cygwin.h> #include <sys/cygwin.h>
#include <unistd.h> #include <unistd.h>
#include <libgen.h> #include <libgen.h>
@ -50,13 +53,12 @@ struct option longopts[] =
{"help", no_argument, NULL, 0}, {"help", no_argument, NULL, 0},
{"version", no_argument, NULL, 0}, {"version", no_argument, NULL, 0},
{"data-relocs", no_argument, NULL, 'd'}, {"data-relocs", no_argument, NULL, 'd'},
{"dll", no_argument, NULL, 'D'},
{"function-relocs", no_argument, NULL, 'r'}, {"function-relocs", no_argument, NULL, 'r'},
{"unused", no_argument, NULL, 'u'}, {"unused", no_argument, NULL, 'u'},
{0, no_argument, NULL, 0} {0, no_argument, NULL, 0}
}; };
static int process_file (const char *); static int process_file (const wchar_t *);
static int static int
usage (const char *fmt, ...) usage (const char *fmt, ...)
@ -84,13 +86,13 @@ usage (const char *fmt, ...)
static HANDLE hProcess; static HANDLE hProcess;
static char * static wchar_t *
get_module_filename (HANDLE hp, HMODULE hm) get_module_filename (HANDLE hp, HMODULE hm)
{ {
size_t len; size_t len;
char *buf = NULL; wchar_t *buf = NULL;
DWORD res; DWORD res;
for (len = 1024; (res = GetModuleFileNameEx (hp, hm, (buf = (char *) realloc (buf, len)), len)) == len; len += 1024) for (len = 1024; (res = GetModuleFileNameExW (hp, hm, (buf = (wchar_t *) realloc (buf, len * sizeof (wchar_t))), len)) == len; len += 1024)
continue; continue;
if (!res) if (!res)
{ {
@ -100,33 +102,42 @@ get_module_filename (HANDLE hp, HMODULE hm)
return buf; return buf;
} }
static char * static wchar_t *
load_dll (const char *fn) load_dll (const wchar_t *fn)
{ {
char *buf = get_module_filename (GetCurrentProcess (), NULL); wchar_t *buf = get_module_filename (GetCurrentProcess (), NULL);
if (!buf) if (!buf)
{ {
printf ("ldd: GetModuleFileName returned an error %lu\n", GetLastError ()); printf ("ldd: GetModuleFileName returned an error %lu\n", GetLastError ());
exit (1); /* FIXME */ exit (1); /* FIXME */
} }
buf = (char *) realloc (buf, sizeof (" \"--dll\" \"\"") + strlen (buf));
strcat (buf, " --dll \""); wchar_t *newbuf = (wchar_t *) malloc ((sizeof (L"\"\" -- ") + wcslen (buf) + wcslen (fn)) * sizeof (wchar_t));
strcat (buf, fn); newbuf[0] = L'"';
strcat (buf, "\""); wcscpy (newbuf + 1, buf);
return 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 static int
start_process (const char *fn, bool& isdll) start_process (const wchar_t *fn, bool& isdll)
{ {
STARTUPINFO si = {}; STARTUPINFOW si = {};
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
si.cb = sizeof (si); si.cb = sizeof (si);
CHAR *cmd; wchar_t *cmd;
if (strlen (fn) < 4 || strcasecmp (strchr (fn, '\0') - 4, ".dll") != 0) if (wcslen (fn) < 4 || wcscasecmp (wcschr (fn, L'\0') - 4, L".dll") != 0)
{ {
cmd = strdup (fn); cmd = wcsdup (fn);
isdll = false; isdll = false;
} }
else else
@ -134,7 +145,7 @@ start_process (const char *fn, bool& isdll)
cmd = load_dll (fn); cmd = load_dll (fn);
isdll = true; isdll = true;
} }
if (CreateProcess (NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi)) if (CreateProcessW (NULL, cmd, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi))
{ {
free (cmd); free (cmd);
hProcess = pi.hProcess; hProcess = pi.hProcess;
@ -147,7 +158,7 @@ start_process (const char *fn, bool& isdll)
} }
static int static int
get_entry_point () set_entry_point_break ()
{ {
HMODULE hm; HMODULE hm;
DWORD cb; DWORD cb;
@ -172,57 +183,55 @@ struct dlls
#define SLOP strlen (" (?)") #define SLOP strlen (" (?)")
char * char *
tocyg (char *win_fn) tocyg (wchar_t *win_fn)
{ {
win_fn[MAX_PATH] = '\0'; ssize_t cwlen = cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, NULL, 0);
ssize_t cwlen = cygwin_conv_path (CCP_WIN_A_TO_POSIX, win_fn, NULL, 0);
char *fn; char *fn;
if (cwlen <= 0) if (cwlen <= 0)
fn = strdup (win_fn); {
int len = wcstombs (NULL, win_fn, 0) + 1;
if ((fn = (char *) malloc (len)))
wcstombs (fn, win_fn, len);
}
else else
{ {
char *fn_cyg = (char *) malloc (cwlen + SLOP + 1); char *fn_cyg = (char *) malloc (cwlen + SLOP + 1);
if (cygwin_conv_path (CCP_WIN_A_TO_POSIX, win_fn, fn_cyg, cwlen) == 0) if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, win_fn, fn_cyg, cwlen) == 0)
fn = fn_cyg; fn = fn_cyg;
else else
{ {
free (fn_cyg); free (fn_cyg);
fn = (char *) malloc (strlen (win_fn) + SLOP + 1); int len = wcstombs (NULL, win_fn, 0);
strcpy (fn, win_fn); fn = (char *) malloc (len + SLOP + 1);
wcstombs (fn, win_fn, len + SLOP + 1);
} }
} }
return fn; return fn;
} }
#define CYGWIN_DLL_LEN (strlen ("\\cygwin1.dll")) #define CYGWIN_DLL_LEN (wcslen (L"\\cygwin1.dll"))
static int static int
print_dlls_and_kill_inferior (dlls *dll, const char *dllfn, const char *process_fn) print_dlls (dlls *dll, const wchar_t *dllfn, const wchar_t *process_fn)
{ {
bool printit = !dllfn;
while ((dll = dll->next)) while ((dll = dll->next))
{ {
char *fn; char *fn;
char *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll); wchar_t *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll);
if (!fullpath) if (!fullpath)
fn = strdup ("???"); fn = strdup ("???");
else if (dllfn && wcscmp (fullpath, dllfn) == 0)
{
free (fullpath);
continue;
}
else else
{ {
if (printit) fn = tocyg (fullpath);
fn = tocyg (fullpath);
else if (strcasecmp (fullpath, dllfn) != 0)
continue;
else
{
printit = true;
free (fullpath);
continue;
}
free (fullpath); free (fullpath);
} }
printf ("\t%s => %s (%p)\n", basename (fn), fn, dll->lpBaseOfDll); printf ("\t%s => %s (%p)\n", basename (fn), fn, dll->lpBaseOfDll);
free (fn); free (fn);
} }
TerminateProcess (hProcess, 0);
if (process_fn) if (process_fn)
return process_file (process_fn); return process_file (process_fn);
return 0; return 0;
@ -237,14 +246,21 @@ report (const char *in_fn, bool multiple)
if (!fn) if (!fn)
print_errno_error_and_return (in_fn); print_errno_error_and_return (in_fn);
ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_A, fn, NULL, 0); ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, NULL, 0);
if (len <= 0) if (len <= 0)
print_errno_error_and_return (fn); print_errno_error_and_return (fn);
bool isdll; bool isdll;
char fn_win[len + 1]; wchar_t fn_win_buf[len + 1];
if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, fn, fn_win, len)) if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, fn, fn_win_buf, len))
print_errno_error_and_return (fn); print_errno_error_and_return (fn);
wchar_t *fn_win = fn_win_buf + 4;
if (wcsncmp (fn_win_buf, L"\\\\?\\UNC\\", 8) == 0)
{
fn_win += 2;
*fn_win = L'\\';
}
if (!fn || start_process (fn_win, isdll)) if (!fn || start_process (fn_win, isdll))
print_errno_error_and_return (in_fn); print_errno_error_and_return (in_fn);
@ -255,25 +271,18 @@ report (const char *in_fn, bool multiple)
dlls dll_list = {}; dlls dll_list = {};
dlls *dll_last = &dll_list; dlls *dll_last = &dll_list;
const char *process_fn = NULL; const wchar_t *process_fn = NULL;
while (1) while (1)
{ {
if (WaitForDebugEvent (&ev, 1000)) bool exitnow = false;
/* ok */; DWORD cont = DBG_CONTINUE;
else if (!WaitForDebugEvent (&ev, INFINITE))
switch (GetLastError ()) break;
{
case WAIT_TIMEOUT:
continue;
default:
usleep (100000);
goto out;
}
switch (ev.dwDebugEventCode) switch (ev.dwDebugEventCode)
{ {
case LOAD_DLL_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT:
if (!isdll && ++dll_count == 2) if (!isdll && ++dll_count == 2)
get_entry_point (); set_entry_point_break ();
dll_last->next = (dlls *) malloc (sizeof (dlls)); dll_last->next = (dlls *) malloc (sizeof (dlls));
dll_last->next->lpBaseOfDll = ev.u.LoadDll.lpBaseOfDll; dll_last->next->lpBaseOfDll = ev.u.LoadDll.lpBaseOfDll;
dll_last->next->next = NULL; dll_last->next->next = NULL;
@ -287,21 +296,27 @@ report (const char *in_fn, bool multiple)
break; break;
case STATUS_BREAKPOINT: case STATUS_BREAKPOINT:
if (!isdll) if (!isdll)
print_dlls_and_kill_inferior (&dll_list, isdll ? fn_win : NULL, process_fn); cont = DBG_EXCEPTION_NOT_HANDLED;
break; break;
} }
break; break;
case CREATE_THREAD_DEBUG_EVENT:
TerminateProcess (hProcess, 0);
break;
case EXIT_PROCESS_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT:
print_dlls_and_kill_inferior (&dll_list, isdll ? fn_win : NULL, process_fn); print_dlls (&dll_list, isdll ? fn_win : NULL, process_fn);
exitnow = true;
break; break;
default: default:
break; break;
} }
if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE)) if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, cont))
{ {
cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2); cygwin_internal (CW_SETERRNO, __FILE__, __LINE__ - 2);
print_errno_error_and_return (in_fn); print_errno_error_and_return (in_fn);
} }
if (exitnow)
break;
} }
out: out:
@ -314,6 +329,7 @@ main (int argc, char **argv)
{ {
int optch; int optch;
int index; int index;
setlocale (LC_ALL, "");
while ((optch = getopt_long (argc, argv, "dru", longopts, &index)) != -1) while ((optch = getopt_long (argc, argv, "dru", longopts, &index)) != -1)
switch (optch) switch (optch)
{ {
@ -322,10 +338,6 @@ main (int argc, char **argv)
case 'u': case 'u':
usage ("option not implemented `-%c'", optch); usage ("option not implemented `-%c'", optch);
exit (1); exit (1);
case 'D':
if (!LoadLibrary (argv[optind]))
exit (1);
exit (0);
case 0: case 0:
if (index == 1) if (index == 1)
{ {
@ -403,16 +415,21 @@ dump_import_directory (const void *const section_base,
/* continue until address inaccessible or there's no DLL name */ /* continue until address inaccessible or there's no DLL name */
for (; !IsBadReadPtr (imp, sizeof (*imp)) && imp->Name; imp++) for (; !IsBadReadPtr (imp, sizeof (*imp)) && imp->Name; imp++)
{ {
char full_path[MAX_PATH]; wchar_t full_path[PATH_MAX];
char *dummy; wchar_t *dummy;
char *fn = (char *) adr (imp->Name); char *fn = (char *) adr (imp->Name);
if (saw_file (fn)) if (saw_file (fn))
continue; 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 */ /* output DLL's name */
char *print_fn; char *print_fn;
if (!SearchPath (NULL, fn, NULL, sizeof (full_path), full_path, &dummy)) if (!SearchPathW (NULL, fnw, NULL, PATH_MAX, full_path, &dummy))
{ {
print_fn = strdup ("not found"); print_fn = strdup ("not found");
printing = true; printing = true;
@ -437,14 +454,14 @@ dump_import_directory (const void *const section_base,
return pointer to loaded file return pointer to loaded file
0 if no success */ 0 if no success */
static void * static void *
map_file (const char *filename) map_file (const wchar_t *filename)
{ {
HANDLE hFile, hMapping; HANDLE hFile, hMapping;
void *basepointer; void *basepointer;
if ((hFile = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, if ((hFile = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE) 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
{ {
fprintf (stderr, "couldn't open %s\n", filename); fprintf (stderr, "couldn't open %ls\n", filename);
return 0; return 0;
} }
if (!(hMapping = CreateFileMapping (hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0))) if (!(hMapping = CreateFileMapping (hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
@ -515,7 +532,7 @@ get_directory_index (const unsigned dir_rva,
/* dump imports of a single file /* dump imports of a single file
Returns 0 if successful, !=0 else */ Returns 0 if successful, !=0 else */
static int static int
process_file (const char *filename) process_file (const wchar_t *filename)
{ {
void *basepointer; /* Points to loaded PE file void *basepointer; /* Points to loaded PE file
* This is memory mapped stuff * This is memory mapped stuff