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.
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
#include <unistd.h>
#include <libgen.h>
-#define _WIN32_WINNT 0x0501
+#define _WIN32_WINNT 0x0a00
#include <windows.h>
+#include <winternl.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'},
const char *opts = "dhruvV";
static int process_file (const wchar_t *);
+static void *drive_map;
static int
error (const char *fmt, ...)
exit (1);
}
-static void
+static void __attribute__ ((__noreturn__))
usage ()
{
printf ("Usage: %s [OPTION]... FILE...\n\
-v, --verbose print all information\n\
(currently unimplemented)\n",
program_invocation_short_name);
+ exit (0);
}
static void
return buf;
}
+static BOOL
+GetFileNameFromHandle(HANDLE hFile, WCHAR pszFilename[MAX_PATH+1])
+{
+ BOOL result = FALSE;
+ ULONG len = 0;
+ OBJECT_NAME_INFORMATION *ntfn = (OBJECT_NAME_INFORMATION *) alloca (65536);
+ NTSTATUS status = NtQueryObject (hFile, ObjectNameInformation,
+ ntfn, 65536, &len);
+ if (NT_SUCCESS (status))
+ {
+ PWCHAR win32path = ntfn->Name.Buffer;
+ win32path[ntfn->Name.Length / sizeof (WCHAR)] = L'\0';
+
+ /* NtQueryObject returns a native NT path. (Try to) convert to Win32. */
+ if (!drive_map)
+ drive_map = (void *) cygwin_internal (CW_ALLOC_DRIVE_MAP);
+ if (drive_map)
+ win32path = (PWCHAR) cygwin_internal (CW_MAP_DRIVE_MAP, drive_map,
+ win32path);
+ pszFilename[0] = L'\0';
+ wcsncat (pszFilename, win32path, MAX_PATH);
+ result = TRUE;
+ }
+ return result;
+}
+
static wchar_t *
load_dll (const wchar_t *fn)
{
set_errno_and_return (1);
}
-static int
-set_entry_point_break ()
-{
- HMODULE hm;
- DWORD cbe;
- SIZE_T cbw;
- if (!EnumProcessModules (hProcess, &hm, sizeof (hm), &cbe) || !cbe)
- 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, &cbw) || cbw != 1)
- set_errno_and_return (1);
- return 0;
-}
-
struct dlls
{
LPVOID lpBaseOfDll;
+ HANDLE hFile;
struct dlls *next;
};
char *fn;
wchar_t *fullpath = get_module_filename (hProcess, (HMODULE) dll->lpBaseOfDll);
if (!fullpath)
- fn = strdup ("???");
+ {
+ // if no path found yet, try getting it from an open handle to the DLL
+ wchar_t dllname[MAX_PATH+1];
+ if (GetFileNameFromHandle (dll->hFile, dllname))
+ {
+ fn = tocyg (dllname);
+ saw_file (basename (fn));
+ }
+ else
+ fn = strdup ("???");
+ }
else if (dllfn && wcscmp (fullpath, dllfn) == 0)
{
free (fullpath);
DEBUG_EVENT ev;
- unsigned dll_count = 0;
-
dlls dll_list = {};
dlls *dll_last = &dll_list;
const wchar_t *process_fn = NULL;
+
+ int res = 0;
+
while (1)
{
bool exitnow = false;
break;
switch (ev.dwDebugEventCode)
{
+ case CREATE_PROCESS_DEBUG_EVENT:
+ if (!isdll)
+ {
+ PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER) alloca (4096);
+ PIMAGE_NT_HEADERS nt_header;
+ PVOID entry_point;
+ static const unsigned char int3 = 0xcc;
+ SIZE_T bytes;
+
+ if (!ReadProcessMemory (hProcess,
+ ev.u.CreateProcessInfo.lpBaseOfImage,
+ dos_header, 4096, &bytes))
+ print_errno_error_and_return (in_fn);
+
+ nt_header = PIMAGE_NT_HEADERS (PBYTE (dos_header)
+ + dos_header->e_lfanew);
+ entry_point = (PVOID)
+ ((caddr_t) ev.u.CreateProcessInfo.lpBaseOfImage
+ + nt_header->OptionalHeader.AddressOfEntryPoint);
+
+ if (!WriteProcessMemory (hProcess, entry_point, &int3, 1, &bytes))
+ print_errno_error_and_return (in_fn);
+ }
+ break;
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->hFile = ev.u.LoadDll.hFile;
dll_last->next->next = NULL;
dll_last = dll_last->next;
break;
case EXCEPTION_DEBUG_EVENT:
switch (ev.u.Exception.ExceptionRecord.ExceptionCode)
{
+ case STATUS_ENTRYPOINT_NOT_FOUND:
+ /* A STATUS_ENTRYPOINT_NOT_FOUND might be encountered right after
+ loading all DLLs. We have to handle it here, otherwise ldd
+ runs into an endless loop. */
+ goto print_and_exit;
case STATUS_DLL_NOT_FOUND:
process_fn = fn_win;
break;
case STATUS_BREAKPOINT:
if (!isdll)
- cont = DBG_EXCEPTION_NOT_HANDLED;
+ TerminateProcess (hProcess, 0);
break;
}
- break;
- case CREATE_THREAD_DEBUG_EVENT:
- TerminateProcess (hProcess, 0);
+ if (ev.u.Exception.ExceptionRecord.ExceptionFlags &
+ EXCEPTION_NONCONTINUABLE) {
+ res = 1;
+ goto print_and_exit;
+ }
break;
case EXIT_PROCESS_DEBUG_EVENT:
+ if (ev.u.ExitProcess.dwExitCode != 0)
+ process_fn = fn_win;
+print_and_exit:
print_dlls (&dll_list, isdll ? fn_win : NULL, process_fn);
exitnow = true;
break;
break;
}
- return 0;
+ return res;
}
int
exit (1);
case 'h':
usage ();
- exit (0);
case 'V':
print_version ();
return 0;
while ((fn = *argv++))
if (report (fn, multiple))
ret = 1;
+ if (drive_map)
+ cygwin_internal (CW_FREE_DRIVE_MAP, drive_map);
exit (ret);
}