From 93d606f60aed779c555017828656c8a4e3c9c6a9 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 27 Mar 2008 01:50:40 +0000 Subject: [PATCH] * hookapi.cc (find_first_notloaded_dll): New function. * pinfo.cc (status_exit): New function. Issue message when dll not found. Use find_first_notloaded_dll to find a nonexistent dll. (pinfo::maybe_set_exit_code_from_windows): Call status_exit when exit code >= 0xc0000000UL. * sigproc.cc (child_info::proc_retry): Return exit code when STATUS_DLL_NOT_FOUND. * spawn.cc (spawn_guts): Minor cleanup. * syscalls.cc (close_all_files): Don't actually close stderr filehandle. Just make it noninheritable. * winsup.h (find_first_notloaded_dll): Declare new function. * ntdll.h: Add several missing NTSTATUS defines. --- winsup/cygwin/ChangeLog | 18 +++++++++ winsup/cygwin/dtable.h | 2 +- winsup/cygwin/exceptions.cc | 2 +- winsup/cygwin/hookapi.cc | 79 ++++++++++++++++++++++++++++++++++--- winsup/cygwin/ntdll.h | 6 +++ winsup/cygwin/pinfo.cc | 30 ++++++++++++-- winsup/cygwin/pinfo.h | 2 +- winsup/cygwin/sigproc.cc | 3 ++ winsup/cygwin/spawn.cc | 7 ++-- winsup/cygwin/syscalls.cc | 7 ++++ winsup/cygwin/winsup.h | 3 +- 11 files changed, 143 insertions(+), 16 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a4e5219fb..57d26da74 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,21 @@ +2008-03-26 Christopher Faylor + + * hookapi.cc (find_first_notloaded_dll): New function. + * pinfo.cc (status_exit): New function. Issue message when dll not + found. Use find_first_notloaded_dll to find a nonexistent dll. + (pinfo::maybe_set_exit_code_from_windows): Call status_exit when exit + code >= 0xc0000000UL. + * sigproc.cc (child_info::proc_retry): Return exit code when + STATUS_DLL_NOT_FOUND. + * spawn.cc (spawn_guts): Minor cleanup. + * syscalls.cc (close_all_files): Don't actually close stderr + filehandle. Just make it noninheritable. + * winsup.h (find_first_notloaded_dll): Declare new function. + +2008-03-26 Brian Dessent + + * ntdll.h: Add several missing NTSTATUS defines. + 2008-03-24 Corinna Vinschen * flock.cc (inode_t::get_all_locks_list): Don't allow F_WAIT flag diff --git a/winsup/cygwin/dtable.h b/winsup/cygwin/dtable.h index 74163a0b4..ff82740dc 100644 --- a/winsup/cygwin/dtable.h +++ b/winsup/cygwin/dtable.h @@ -1,6 +1,6 @@ /* dtable.h: fd table definition. - Copyright 2000, 2001, 2003, 2004, 2005 Red Hat, Inc. + Copyright 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 6eb17153a..86b793b6f 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -153,7 +153,7 @@ open_stackdumpfile () p, strlen (p)) * sizeof (WCHAR); RtlAppendUnicodeToString (&ucore, L".stackdump"); /* Create an object attribute which refers to .stackdump - in Cygwin's cwd. */ + in Cygwin's cwd. */ InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE, cygheap->cwd.get_handle (), NULL); HANDLE h; diff --git a/winsup/cygwin/hookapi.cc b/winsup/cygwin/hookapi.cc index 975879bf6..2e9ba0ece 100644 --- a/winsup/cygwin/hookapi.cc +++ b/winsup/cygwin/hookapi.cc @@ -1,6 +1,6 @@ /* hookapi.cc - Copyright 2005, 2006 Red Hat, Inc. + Copyright 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Cygwin. @@ -9,15 +9,17 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" +#include +#include +#include +#include "ntdll.h" #include "cygerrno.h" #include "security.h" #include "path.h" #include "fhandler.h" #include "dtable.h" #include "cygheap.h" -#include -#include -#include +#include "pinfo.h" #define rva(coerce, base, addr) (coerce) ((char *) (base) + (addr)) #define rvacyg(coerce, addr) rva (coerce, cygwin_hmodule, addr) @@ -158,7 +160,74 @@ makename (const char *name, char *&buf, int& i, int inc) return name; } -// Top level routine to find the EXE's imports, and redirect them +/* Find first missing dll in a given executable. + FIXME: This is not foolproof since it doesn't look for dlls in the + same directory as the given executable, like Windows. Instead it + searches for dlls in the context of the current executable. */ +const char * +find_first_notloaded_dll (path_conv& pc) +{ + const char *res = "?"; + HANDLE hc = NULL; + HMODULE hm = NULL; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + HANDLE h; + NTSTATUS status; + + status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ, + pc.get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + | FILE_OPEN_FOR_BACKUP_INTENT + | FILE_NON_DIRECTORY_FILE); + if (!NT_SUCCESS (status)) + goto out; + + hc = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL); + NtClose (h); + if (!hc) + goto out; + hm = (HMODULE) MapViewOfFile(hc, FILE_MAP_READ, 0, 0, 0); + CloseHandle (hc); + + PIMAGE_NT_HEADERS pExeNTHdr; + pExeNTHdr = PEHeaderFromHModule (hm); + + if (!pExeNTHdr) + goto out; + + DWORD importRVA; + importRVA = pExeNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + if (!importRVA) + goto out; + + long delta = rvadelta (pExeNTHdr, importRVA); + + // Convert imports RVA to a usable pointer + PIMAGE_IMPORT_DESCRIPTOR pdfirst; + pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta); + + // Iterate through each import descriptor, and redirect if appropriate + for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++) + { + const char *lib = rva (PSTR, hm, pd->Name - delta); + if (!LoadLibraryEx (lib, NULL, DONT_RESOLVE_DLL_REFERENCES + | LOAD_LIBRARY_AS_DATAFILE)) + { + static char buf[NT_MAX_PATH]; + res = strcpy (buf, lib); + } + } + +out: + if (hm) + UnmapViewOfFile (hm); + + return res; +} + +// Top level routine to find the EXE's imports and redirect them void * hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys) { diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 4ec281025..695c229cd 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -37,6 +37,12 @@ #define STATUS_INVALID_LEVEL ((NTSTATUS) 0xc0000148) #define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005) #define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006) +#define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135) +#define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139) +#define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251) +#define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269) + + #define PDI_MODULES 0x01 #define PDI_HEAPS 0x04 #define LDRP_IMAGE_DLL 0x00000004 diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 85fdf9b37..d6b5de527 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -104,6 +104,28 @@ pinfo_init (char **envp, int envc) debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid); } +static DWORD +status_exit (DWORD x) +{ + const char *find_first_notloaded_dll (path_conv &); + switch (x) + { + case STATUS_DLL_NOT_FOUND: + { + char posix_prog[NT_MAX_PATH]; + path_conv pc (myself->progname, PC_NOWARN); + mount_table->conv_to_posix_path (pc.get_win32 (), posix_prog, 1); + small_printf ("%s: error while loading shared libraries: %s: cannot open shared object file: No such file or directory\n", + posix_prog, find_first_notloaded_dll (pc)); + x = 127; + } + break; + default: + x = 127; + } + return x; +} + # define self (*this) void pinfo::maybe_set_exit_code_from_windows () @@ -114,10 +136,12 @@ pinfo::maybe_set_exit_code_from_windows () if (hProcess && !(self->exitcode & EXITCODE_SET)) { - WaitForSingleObject (hProcess, INFINITE); // just to be safe, in case - // process hasn't quite exited - // after closing pipe + WaitForSingleObject (hProcess, INFINITE); /* just to be safe, in case + process hasn't quite exited + after closing pipe */ GetExitCodeProcess (hProcess, &x); + if (x >= 0xc0000000UL) + x = status_exit (x); self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8); } sigproc_printf ("pid %d, exit value - old %p, windows %p, cygwin %p", diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 9d45bd2cb..9976ad1a0 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -45,7 +45,7 @@ public: pid_t pid; /* Various flags indicating the state of the process. See PID_ - constants below. */ + constants in . */ DWORD process_state; DWORD exitcode; /* set when process exits */ diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index af2b023d7..4c8c471e9 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -32,6 +32,7 @@ details. */ #include "cygtls.h" #include "sigproc.h" #include "exceptions.h" +#include "ntdll.h" /* * Convenience defines @@ -935,6 +936,8 @@ child_info::proc_retry (HANDLE h) case STILL_ACTIVE: /* shouldn't happen */ sigproc_printf ("STILL_ACTIVE? How'd we get here?"); break; + case STATUS_DLL_NOT_FOUND: + return exit_code; case STATUS_CONTROL_C_EXIT: if (saw_ctrl_c ()) return EXITCODE_OK; diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index cb5af8017..2b728b0c4 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -1,7 +1,7 @@ /* spawn.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Red Hat, Inc. + 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Cygwin. @@ -265,7 +265,7 @@ do_cleanup (void *args) int __stdcall -spawn_guts (const char * prog_arg, const char *const *argv, +spawn_guts (const char *prog_arg, const char *const *argv, const char *const envp[], int mode, int __stdin, int __stdout) { bool rc; @@ -745,8 +745,7 @@ loop: myself->wr_proc_pipe_owner = GetCurrentProcessId (); myself->wr_proc_pipe = orig_wr_proc_pipe; } - DWORD res = ch.proc_retry (pi.hProcess); - if (!res) + if (!ch.proc_retry (pi.hProcess)) { looped++; goto loop; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 337d50282..d5f468344 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -109,12 +109,17 @@ close_all_files (bool norelease) semaphore::terminate (); fhandler_base *fh; + HANDLE h = NULL; + for (int i = 0; i < (int) cygheap->fdtab.size; i++) if ((fh = cygheap->fdtab[i]) != NULL) { #ifdef DEBUGGING debug_printf ("closing fd %d", i); #endif + if (i == 2) + DuplicateHandle (GetCurrentProcess (), fh->get_output_handle (), GetCurrentProcess (), &h, 0, false, + DUPLICATE_SAME_ACCESS); fh->close (); if (!norelease) cygheap->fdtab.release (i); @@ -123,6 +128,8 @@ close_all_files (bool norelease) if (!hExeced && cygheap->ctty) cygheap->close_ctty (); + if (h) + SetStdHandle (STD_ERROR_HANDLE, h); cygheap->fdtab.unlock (); } diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 5d9af096c..33cdba39d 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -261,7 +261,8 @@ void __stdcall close_all_files (bool = false); extern "C" void error_start_init (const char*); extern "C" int try_to_debug (bool waitloop = 1); -extern void ld_preload (); +void ld_preload (); +const char *find_first_notloaded_dll (class path_conv &); void set_file_api_mode (codepage_type);