OSDN Git Service

* dcrt0.cc (dll_crt0_0): Check for wincap.wow64_has_secondary_stack
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / wow64.cc
1 /* wow64.cc
2
3    Copyright 2011 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include "cygtls.h"
13 #include "ntdll.h"
14 #include <sys/param.h>
15
16 #define PTR_ADD(p,o)    ((PVOID)((PBYTE)(p)+(o)))
17
18 bool NO_COPY wow64_needs_stack_adjustment = false;
19
20 static void
21 wow64_eval_expected_main_stack (PVOID &allocbase, PVOID &stackbase)
22 {
23   PIMAGE_DOS_HEADER dosheader;
24   PIMAGE_NT_HEADERS32 ntheader;
25   DWORD size;
26
27   dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
28   ntheader = (PIMAGE_NT_HEADERS32) ((PBYTE) dosheader + dosheader->e_lfanew);
29   /* The main thread stack is expected to be located at 0x30000, which is the
30      case for all observed NT systems up to Server 2003 R2, unless the
31      stacksize requested by the StackReserve field in the PE/COFF header is
32      so big that the stack doesn't fit in the area between 0x30000 and the
33      start of the image.  In case of a conflict, the OS allocates the stack
34      right after the image.
35      Sidenote: While post-2K3 32 bit systems continue to have the default
36      main thread stack address located at 0x30000, the default main thread
37      stack address on Vista/2008 64 bit is 0x80000 and on W7/2K8R2 64 bit
38      it is 0x90000.  However, this is no problem because the system sticks
39      to that address for all WOW64 processes, not only for the first one
40      started from a 64 bit parent. */
41   allocbase = (PVOID) 0x30000;
42   /* Stack size.  The OS always rounds the size up to allocation granularity
43      and it never allocates less than 256K. */
44   size = roundup2 (ntheader->OptionalHeader.SizeOfStackReserve,
45                    wincap.allocation_granularity ());
46   if (size < 256 * 1024)
47     size = 256 * 1024;
48   /* If the stack doesn't fit in the area before the image, it's allocated
49      right after the image, rounded up to allocation granularity boundary. */
50   if (PTR_ADD (allocbase, size) > (PVOID) ntheader->OptionalHeader.ImageBase)
51     allocbase = PTR_ADD (ntheader->OptionalHeader.ImageBase,
52                          ntheader->OptionalHeader.SizeOfImage);
53   allocbase = (PVOID) roundup2 ((uintptr_t) allocbase,
54                                 wincap.allocation_granularity ());
55   stackbase = PTR_ADD (allocbase, size);
56   debug_printf ("expected allocbase: %p, stackbase: %p", allocbase, stackbase);
57 }
58
59 bool
60 wow64_test_for_64bit_parent ()
61 {
62   /* On Windows XP 64 and 2003 64 there's a problem with processes running
63      under WOW64.  The first process started from a 64 bit process has its
64      main thread stack not where it should be.  Rather, it uses another
65      stack while the original stack is used for other purposes.
66      The problem is, the child has its stack in the usual spot again, thus
67      we have to "alloc_stack_hard_way".  However, this fails in almost all
68      cases because the stack slot of the parent process is taken by something
69      else in the child process.
70      What we do here is to check if the current stack is the excpected main
71      thread stack and if not, if we really have been started from a 64 bit
72      process here.  If so, we note this fact in wow64_needs_stack_adjustment
73      so we can workaround the stack problem in _dll_crt0.  See there for how
74      we go along. */
75   NTSTATUS ret;
76   PROCESS_BASIC_INFORMATION pbi;
77   HANDLE parent;
78   PVOID allocbase, stackbase;
79
80   ULONG wow64 = TRUE;   /* Opt on the safe side. */
81
82   /* First check if the current stack is where it belongs.  If so, we don't
83      have to do anything special.  This is the case on Vista and later. */
84   wow64_eval_expected_main_stack (allocbase, stackbase);
85   if (&wow64 >= (PULONG) allocbase && &wow64 < (PULONG) stackbase)
86     return false;
87
88   /* Check if the parent is a native 64 bit process.  Unfortunately there's
89      no simpler way to retrieve the parent process in NT, as far as I know.
90      Hints welcome. */
91   ret = NtQueryInformationProcess (NtCurrentProcess (),
92                                    ProcessBasicInformation,
93                                    &pbi, sizeof pbi, NULL);
94   if (NT_SUCCESS (ret)
95       && (parent = OpenProcess (PROCESS_QUERY_INFORMATION,
96                                 FALSE,
97                                 pbi.InheritedFromUniqueProcessId)))
98     {
99       NtQueryInformationProcess (parent, ProcessWow64Information,
100                                  &wow64, sizeof wow64, NULL);
101       CloseHandle (parent);
102     }
103   return !wow64;
104 }
105
106 PVOID
107 wow64_revert_to_original_stack (PVOID &allocationbase)
108 {
109   /* Test if the original stack exists and has been set up as usual.  Even
110      though the stack of the WOW64 process is at an unusual address, it appears
111      that the "normal" stack has been created as usual.  It's partially in use
112      by the 32->64 bit transition layer of the OS to help along the WOW64
113      process, but it's otherwise mostly unused. */
114   MEMORY_BASIC_INFORMATION mbi;
115   PVOID stackbase;
116
117   wow64_eval_expected_main_stack (allocationbase, stackbase);
118
119   /* The stack is allocated in a single call, so the entire stack has the
120      same AllocationBase.  At the start we expect a reserved region big
121      enough still to host as the main stack. The OS apparently reserves
122      always at least 256K for the main thread stack.  We err on the side
123      of caution so we test here for a reserved region of at least 256K.
124      That should be enough (knock on wood). */
125   VirtualQuery (allocationbase, &mbi, sizeof mbi);
126   if (mbi.State != MEM_RESERVE || mbi.RegionSize < 256 * 1024)
127     return NULL;
128
129   /* Next we expect a guard page.  We fetch the size of the guard area to
130      see how big it is.  Apparently the guard area on 64 bit systems spans
131      2 pages. */
132   PVOID addr = PTR_ADD (mbi.BaseAddress, mbi.RegionSize);
133   VirtualQuery (addr, &mbi, sizeof mbi);
134   if (mbi.AllocationBase != allocationbase
135       || mbi.State != MEM_COMMIT
136       || !(mbi.Protect & PAGE_GUARD))
137     return NULL;
138   PVOID guardaddr = mbi.BaseAddress;
139   SIZE_T guardsize = mbi.RegionSize;
140
141   /* Next we expect a committed R/W region, the in-use area of that stack.
142      This is just a sanity check. */
143   addr = PTR_ADD (mbi.BaseAddress, mbi.RegionSize);
144   VirtualQuery (addr, &mbi, sizeof mbi);
145   if (mbi.AllocationBase != allocationbase
146       || PTR_ADD (mbi.BaseAddress, mbi.RegionSize) != stackbase
147       || mbi.State != MEM_COMMIT
148       || mbi.Protect != PAGE_READWRITE)
149     return NULL;
150
151   /* The original stack is used by the OS.  Leave enough space for the OS
152      to be happy (another 64K) and constitute a second stack within the so
153      far reserved stack area. */
154   PVOID newbase = PTR_ADD (guardaddr, -wincap.allocation_granularity ());
155   PVOID newtop = PTR_ADD (newbase, -wincap.allocation_granularity ());
156   guardaddr = PTR_ADD (newtop, -guardsize);
157   if (!VirtualAlloc (newtop, wincap.allocation_granularity (),
158                      MEM_COMMIT, PAGE_READWRITE))
159     return NULL;
160   if (!VirtualAlloc (guardaddr, guardsize, MEM_COMMIT,
161                      PAGE_READWRITE | PAGE_GUARD))
162     return NULL;
163
164   /* We're going to reuse the original stack.  Yay, no more respawn!
165      Set the StackBase and StackLimit values in the TEB, set _main_tls
166      accordingly, and return the new address for the stack pointer.
167      The second half of the stack move is done by the caller _dll_crt0. */
168   _tlsbase = (char *) newbase;
169   _tlstop = (char *) newtop;
170   _main_tls = &_my_tls;
171   return PTR_ADD (_main_tls, -4);
172 }
173
174 /* Respawn WOW64 process. This is only called if we can't reuse the original
175    stack.  See comment in wow64_revert_to_original_stack for details.  See
176    _dll_crt0 for the call of this function.
177
178    Historical note:
179
180    Originally we just always respawned, right from dll_entry.  This stopped
181    working with Cygwin 1.7.10 on Windows 2003 R2 64.  Starting with Cygwin
182    1.7.10 we don't link against advapi32.dll anymore.  However, any process
183    linked against advapi32, directly or indirectly, failed to respawn when
184    trying respawning during DLL_PROCESS_ATTACH initialization.  In that
185    case CreateProcessW returns with ERROR_ACCESS_DENIED for some reason. */
186 void
187 wow64_respawn_process ()
188 {
189   WCHAR path[PATH_MAX];
190   PROCESS_INFORMATION pi;
191   STARTUPINFOW si;
192   DWORD ret = 0;
193
194   GetModuleFileNameW (NULL, path, PATH_MAX);
195   GetStartupInfoW (&si);
196   if (!CreateProcessW (path, GetCommandLineW (), NULL, NULL, TRUE,
197                        CREATE_DEFAULT_ERROR_MODE
198                        | GetPriorityClass (GetCurrentProcess ()),
199                        NULL, NULL, &si, &pi))
200     api_fatal ("Failed to create process <%W> <%W>, %E",
201                path, GetCommandLineW ());
202   CloseHandle (pi.hThread);
203   if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED)
204     api_fatal ("Waiting for process %d failed, %E", pi.dwProcessId);
205   GetExitCodeProcess (pi.hProcess, &ret);
206   CloseHandle (pi.hProcess);
207   TerminateProcess (GetCurrentProcess (), ret);
208   ExitProcess (ret);
209 }