1 /* Internal interfaces for the Windows code
2    Copyright (C) 1995-2021 Free Software Foundation, Inc.
3 
4    This file is part of GDB.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "gdbsupport/common-defs.h"
20 #include "nat/windows-nat.h"
21 #include "gdbsupport/common-debug.h"
22 
23 namespace windows_nat
24 {
25 
26 HANDLE current_process_handle;
27 DWORD current_process_id;
28 DWORD main_thread_id;
29 enum gdb_signal last_sig = GDB_SIGNAL_0;
30 DEBUG_EVENT current_event;
31 
32 /* The most recent event from WaitForDebugEvent.  Unlike
33    current_event, this is guaranteed never to come from a pending
34    stop.  This is important because only data from the most recent
35    event from WaitForDebugEvent can be used when calling
36    ContinueDebugEvent.  */
37 static DEBUG_EVENT last_wait_event;
38 
39 DWORD desired_stop_thread_id = -1;
40 std::vector<pending_stop> pending_stops;
41 EXCEPTION_RECORD siginfo_er;
42 
43 #ifdef __x86_64__
44 bool wow64_process = false;
45 bool ignore_first_breakpoint = false;
46 #endif
47 
48 AdjustTokenPrivileges_ftype *AdjustTokenPrivileges;
49 DebugActiveProcessStop_ftype *DebugActiveProcessStop;
50 DebugBreakProcess_ftype *DebugBreakProcess;
51 DebugSetProcessKillOnExit_ftype *DebugSetProcessKillOnExit;
52 EnumProcessModules_ftype *EnumProcessModules;
53 #ifdef __x86_64__
54 EnumProcessModulesEx_ftype *EnumProcessModulesEx;
55 #endif
56 GetModuleInformation_ftype *GetModuleInformation;
57 GetModuleFileNameExA_ftype *GetModuleFileNameExA;
58 GetModuleFileNameExW_ftype *GetModuleFileNameExW;
59 LookupPrivilegeValueA_ftype *LookupPrivilegeValueA;
60 OpenProcessToken_ftype *OpenProcessToken;
61 GetCurrentConsoleFont_ftype *GetCurrentConsoleFont;
62 GetConsoleFontSize_ftype *GetConsoleFontSize;
63 #ifdef __x86_64__
64 Wow64SuspendThread_ftype *Wow64SuspendThread;
65 Wow64GetThreadContext_ftype *Wow64GetThreadContext;
66 Wow64SetThreadContext_ftype *Wow64SetThreadContext;
67 Wow64GetThreadSelectorEntry_ftype *Wow64GetThreadSelectorEntry;
68 #endif
69 GenerateConsoleCtrlEvent_ftype *GenerateConsoleCtrlEvent;
70 
71 /* Note that 'debug_events' must be locally defined in the relevant
72    functions.  */
73 #define DEBUG_EVENTS(fmt, ...) \
74   debug_prefixed_printf_cond (debug_events, "windows events", fmt, \
75 			      ## __VA_ARGS__)
76 
~windows_thread_info()77 windows_thread_info::~windows_thread_info ()
78 {
79 }
80 
81 void
suspend()82 windows_thread_info::suspend ()
83 {
84   if (suspended != 0)
85     return;
86 
87   if (SuspendThread (h) == (DWORD) -1)
88     {
89       DWORD err = GetLastError ();
90 
91       /* We get Access Denied (5) when trying to suspend
92 	 threads that Windows started on behalf of the
93 	 debuggee, usually when those threads are just
94 	 about to exit.
95 	 We can get Invalid Handle (6) if the main thread
96 	 has exited.  */
97       if (err != ERROR_INVALID_HANDLE && err != ERROR_ACCESS_DENIED)
98 	warning (_("SuspendThread (tid=0x%x) failed. (winerr %u)"),
99 		 (unsigned) tid, (unsigned) err);
100       suspended = -1;
101     }
102   else
103     suspended = 1;
104 }
105 
106 void
resume()107 windows_thread_info::resume ()
108 {
109   if (suspended > 0)
110     {
111       stopped_at_software_breakpoint = false;
112 
113       if (ResumeThread (h) == (DWORD) -1)
114 	{
115 	  DWORD err = GetLastError ();
116 	  warning (_("warning: ResumeThread (tid=0x%x) failed. (winerr %u)"),
117 		   (unsigned) tid, (unsigned) err);
118 	}
119     }
120   suspended = 0;
121 }
122 
123 /* Return the name of the DLL referenced by H at ADDRESS.  UNICODE
124    determines what sort of string is read from the inferior.  Returns
125    the name of the DLL, or NULL on error.  If a name is returned, it
126    is stored in a static buffer which is valid until the next call to
127    get_image_name.  */
128 
129 static const char *
get_image_name(HANDLE h,void * address,int unicode)130 get_image_name (HANDLE h, void *address, int unicode)
131 {
132 #ifdef __CYGWIN__
133   static char buf[MAX_PATH];
134 #else
135   static char buf[(2 * MAX_PATH) + 1];
136 #endif
137   DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
138   char *address_ptr;
139   int len = 0;
140   char b[2];
141   SIZE_T done;
142 
143   /* Attempt to read the name of the dll that was detected.
144      This is documented to work only when actively debugging
145      a program.  It will not work for attached processes.  */
146   if (address == NULL)
147     return NULL;
148 
149   /* See if we could read the address of a string, and that the
150      address isn't null.  */
151   if (!ReadProcessMemory (h, address,  &address_ptr,
152 			  sizeof (address_ptr), &done)
153       || done != sizeof (address_ptr)
154       || !address_ptr)
155     return NULL;
156 
157   /* Find the length of the string.  */
158   while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
159 	 && (b[0] != 0 || b[size - 1] != 0) && done == size)
160     continue;
161 
162   if (!unicode)
163     ReadProcessMemory (h, address_ptr, buf, len, &done);
164   else
165     {
166       WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
167       ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
168 			 &done);
169 #ifdef __CYGWIN__
170       wcstombs (buf, unicode_address, MAX_PATH);
171 #else
172       WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, sizeof buf,
173 			   0, 0);
174 #endif
175     }
176 
177   return buf;
178 }
179 
180 /* The exception thrown by a program to tell the debugger the name of
181    a thread.  The exception record contains an ID of a thread and a
182    name to give it.  This exception has no documented name, but MSDN
183    dubs it "MS_VC_EXCEPTION" in one code example.  */
184 #define MS_VC_EXCEPTION 0x406d1388
185 
186 handle_exception_result
handle_exception(struct target_waitstatus * ourstatus,bool debug_exceptions)187 handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
188 {
189 #define DEBUG_EXCEPTION_SIMPLE(x)       if (debug_exceptions) \
190   debug_printf ("gdb: Target exception %s at %s\n", x, \
191     host_address_to_string (\
192       current_event.u.Exception.ExceptionRecord.ExceptionAddress))
193 
194   EXCEPTION_RECORD *rec = &current_event.u.Exception.ExceptionRecord;
195   DWORD code = rec->ExceptionCode;
196   handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
197 
198   memcpy (&siginfo_er, rec, sizeof siginfo_er);
199 
200   ourstatus->kind = TARGET_WAITKIND_STOPPED;
201 
202   /* Record the context of the current thread.  */
203   thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
204 	      DONT_SUSPEND);
205 
206   switch (code)
207     {
208     case EXCEPTION_ACCESS_VIOLATION:
209       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
210       ourstatus->value.sig = GDB_SIGNAL_SEGV;
211       if (handle_access_violation (rec))
212 	return HANDLE_EXCEPTION_UNHANDLED;
213       break;
214     case STATUS_STACK_OVERFLOW:
215       DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
216       ourstatus->value.sig = GDB_SIGNAL_SEGV;
217       break;
218     case STATUS_FLOAT_DENORMAL_OPERAND:
219       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
220       ourstatus->value.sig = GDB_SIGNAL_FPE;
221       break;
222     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
223       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
224       ourstatus->value.sig = GDB_SIGNAL_FPE;
225       break;
226     case STATUS_FLOAT_INEXACT_RESULT:
227       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
228       ourstatus->value.sig = GDB_SIGNAL_FPE;
229       break;
230     case STATUS_FLOAT_INVALID_OPERATION:
231       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
232       ourstatus->value.sig = GDB_SIGNAL_FPE;
233       break;
234     case STATUS_FLOAT_OVERFLOW:
235       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
236       ourstatus->value.sig = GDB_SIGNAL_FPE;
237       break;
238     case STATUS_FLOAT_STACK_CHECK:
239       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
240       ourstatus->value.sig = GDB_SIGNAL_FPE;
241       break;
242     case STATUS_FLOAT_UNDERFLOW:
243       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
244       ourstatus->value.sig = GDB_SIGNAL_FPE;
245       break;
246     case STATUS_FLOAT_DIVIDE_BY_ZERO:
247       DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
248       ourstatus->value.sig = GDB_SIGNAL_FPE;
249       break;
250     case STATUS_INTEGER_DIVIDE_BY_ZERO:
251       DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
252       ourstatus->value.sig = GDB_SIGNAL_FPE;
253       break;
254     case STATUS_INTEGER_OVERFLOW:
255       DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
256       ourstatus->value.sig = GDB_SIGNAL_FPE;
257       break;
258     case EXCEPTION_BREAKPOINT:
259 #ifdef __x86_64__
260       if (ignore_first_breakpoint)
261 	{
262 	  /* For WOW64 processes, there are always 2 breakpoint exceptions
263 	     on startup, first a BREAKPOINT for the 64bit ntdll.dll,
264 	     then a WX86_BREAKPOINT for the 32bit ntdll.dll.
265 	     Here we only care about the WX86_BREAKPOINT's.  */
266 	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
267 	  ignore_first_breakpoint = false;
268 	}
269       else if (wow64_process)
270 	{
271 	  /* This breakpoint exception is triggered for WOW64 processes when
272 	     reaching an int3 instruction in 64bit code.
273 	     gdb checks for int3 in case of SIGTRAP, this fails because
274 	     Wow64GetThreadContext can only report the pc of 32bit code, and
275 	     gdb lets the target process continue.
276 	     So handle it as SIGINT instead, then the target is stopped
277 	     unconditionally.  */
278 	  DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
279 	  rec->ExceptionCode = DBG_CONTROL_C;
280 	  ourstatus->value.sig = GDB_SIGNAL_INT;
281 	  break;
282 	}
283 #endif
284       /* FALLTHROUGH */
285     case STATUS_WX86_BREAKPOINT:
286       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
287       ourstatus->value.sig = GDB_SIGNAL_TRAP;
288       break;
289     case DBG_CONTROL_C:
290       DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
291       ourstatus->value.sig = GDB_SIGNAL_INT;
292       break;
293     case DBG_CONTROL_BREAK:
294       DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
295       ourstatus->value.sig = GDB_SIGNAL_INT;
296       break;
297     case EXCEPTION_SINGLE_STEP:
298     case STATUS_WX86_SINGLE_STEP:
299       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
300       ourstatus->value.sig = GDB_SIGNAL_TRAP;
301       break;
302     case EXCEPTION_ILLEGAL_INSTRUCTION:
303       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
304       ourstatus->value.sig = GDB_SIGNAL_ILL;
305       break;
306     case EXCEPTION_PRIV_INSTRUCTION:
307       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
308       ourstatus->value.sig = GDB_SIGNAL_ILL;
309       break;
310     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
311       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
312       ourstatus->value.sig = GDB_SIGNAL_ILL;
313       break;
314     case MS_VC_EXCEPTION:
315       DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
316       if (handle_ms_vc_exception (rec))
317 	{
318 	  ourstatus->value.sig = GDB_SIGNAL_TRAP;
319 	  result = HANDLE_EXCEPTION_IGNORED;
320 	  break;
321 	}
322 	/* treat improperly formed exception as unknown */
323 	/* FALLTHROUGH */
324     default:
325       /* Treat unhandled first chance exceptions specially.  */
326       if (current_event.u.Exception.dwFirstChance)
327 	return HANDLE_EXCEPTION_UNHANDLED;
328       debug_printf ("gdb: unknown target exception 0x%08x at %s\n",
329 	(unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
330 	host_address_to_string (
331 	  current_event.u.Exception.ExceptionRecord.ExceptionAddress));
332       ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
333       break;
334     }
335 
336   last_sig = ourstatus->value.sig;
337   return result;
338 
339 #undef DEBUG_EXCEPTION_SIMPLE
340 }
341 
342 /* Iterate over all DLLs currently mapped by our inferior, looking for
343    a DLL which is loaded at LOAD_ADDR.  If found, add the DLL to our
344    list of solibs; otherwise do nothing.  LOAD_ADDR NULL means add all
345    DLLs to the list of solibs; this is used when the inferior finishes
346    its initialization, and all the DLLs it statically depends on are
347    presumed loaded.  */
348 
349 static void
windows_add_dll(LPVOID load_addr)350 windows_add_dll (LPVOID load_addr)
351 {
352   HMODULE dummy_hmodule;
353   DWORD cb_needed;
354   HMODULE *hmodules;
355   int i;
356 
357 #ifdef __x86_64__
358   if (wow64_process)
359     {
360       if (EnumProcessModulesEx (current_process_handle, &dummy_hmodule,
361 				sizeof (HMODULE), &cb_needed,
362 				LIST_MODULES_32BIT) == 0)
363 	return;
364     }
365   else
366 #endif
367     {
368       if (EnumProcessModules (current_process_handle, &dummy_hmodule,
369 			      sizeof (HMODULE), &cb_needed) == 0)
370 	return;
371     }
372 
373   if (cb_needed < 1)
374     return;
375 
376   hmodules = (HMODULE *) alloca (cb_needed);
377 #ifdef __x86_64__
378   if (wow64_process)
379     {
380       if (EnumProcessModulesEx (current_process_handle, hmodules,
381 				cb_needed, &cb_needed,
382 				LIST_MODULES_32BIT) == 0)
383 	return;
384     }
385   else
386 #endif
387     {
388       if (EnumProcessModules (current_process_handle, hmodules,
389 			      cb_needed, &cb_needed) == 0)
390 	return;
391     }
392 
393   char system_dir[MAX_PATH];
394   char syswow_dir[MAX_PATH];
395   size_t system_dir_len = 0;
396   bool convert_syswow_dir = false;
397 #ifdef __x86_64__
398   if (wow64_process)
399 #endif
400     {
401       /* This fails on 32bit Windows because it has no SysWOW64 directory,
402 	 and in this case a path conversion isn't necessary.  */
403       UINT len = GetSystemWow64DirectoryA (syswow_dir, sizeof (syswow_dir));
404       if (len > 0)
405 	{
406 	  /* Check that we have passed a large enough buffer.  */
407 	  gdb_assert (len < sizeof (syswow_dir));
408 
409 	  len = GetSystemDirectoryA (system_dir, sizeof (system_dir));
410 	  /* Error check.  */
411 	  gdb_assert (len != 0);
412 	  /* Check that we have passed a large enough buffer.  */
413 	  gdb_assert (len < sizeof (system_dir));
414 
415 	  strcat (system_dir, "\\");
416 	  strcat (syswow_dir, "\\");
417 	  system_dir_len = strlen (system_dir);
418 
419 	  convert_syswow_dir = true;
420 	}
421 
422     }
423   for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++)
424     {
425       MODULEINFO mi;
426 #ifdef __USEWIDE
427       wchar_t dll_name[MAX_PATH];
428       char dll_name_mb[MAX_PATH];
429 #else
430       char dll_name[MAX_PATH];
431 #endif
432       const char *name;
433       if (GetModuleInformation (current_process_handle, hmodules[i],
434 				&mi, sizeof (mi)) == 0)
435 	continue;
436 
437       if (GetModuleFileNameEx (current_process_handle, hmodules[i],
438 			       dll_name, sizeof (dll_name)) == 0)
439 	continue;
440 #ifdef __USEWIDE
441       wcstombs (dll_name_mb, dll_name, MAX_PATH);
442       name = dll_name_mb;
443 #else
444       name = dll_name;
445 #endif
446       /* Convert the DLL path of 32bit processes returned by
447 	 GetModuleFileNameEx from the 64bit system directory to the
448 	 32bit syswow64 directory if necessary.  */
449       std::string syswow_dll_path;
450       if (convert_syswow_dir
451 	  && strncasecmp (name, system_dir, system_dir_len) == 0
452 	  && strchr (name + system_dir_len, '\\') == nullptr)
453 	{
454 	  syswow_dll_path = syswow_dir;
455 	  syswow_dll_path += name + system_dir_len;
456 	  name = syswow_dll_path.c_str();
457 	}
458 
459       /* Record the DLL if either LOAD_ADDR is NULL or the address
460 	 at which the DLL was loaded is equal to LOAD_ADDR.  */
461       if (!(load_addr != nullptr && mi.lpBaseOfDll != load_addr))
462 	{
463 	  handle_load_dll (name, mi.lpBaseOfDll);
464 	  if (load_addr != nullptr)
465 	    return;
466 	}
467     }
468 }
469 
470 /* See nat/windows-nat.h.  */
471 
472 void
dll_loaded_event()473 dll_loaded_event ()
474 {
475   gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT);
476 
477   LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
478   const char *dll_name;
479 
480   /* Try getting the DLL name via the lpImageName field of the event.
481      Note that Microsoft documents this fields as strictly optional,
482      in the sense that it might be NULL.  And the first DLL event in
483      particular is explicitly documented as "likely not pass[ed]"
484      (source: MSDN LOAD_DLL_DEBUG_INFO structure).  */
485   dll_name = get_image_name (current_process_handle,
486 			     event->lpImageName, event->fUnicode);
487   /* If the DLL name could not be gleaned via lpImageName, try harder
488      by enumerating all the DLLs loaded into the inferior, looking for
489      one that is loaded at base address = lpBaseOfDll. */
490   if (dll_name != nullptr)
491     handle_load_dll (dll_name, event->lpBaseOfDll);
492   else if (event->lpBaseOfDll != nullptr)
493     windows_add_dll (event->lpBaseOfDll);
494 }
495 
496 /* See nat/windows-nat.h.  */
497 
498 void
windows_add_all_dlls()499 windows_add_all_dlls ()
500 {
501   windows_add_dll (nullptr);
502 }
503 
504 /* See nat/windows-nat.h.  */
505 
506 bool
matching_pending_stop(bool debug_events)507 matching_pending_stop (bool debug_events)
508 {
509   /* If there are pending stops, and we might plausibly hit one of
510      them, we don't want to actually continue the inferior -- we just
511      want to report the stop.  In this case, we just pretend to
512      continue.  See the comment by the definition of "pending_stops"
513      for details on why this is needed.  */
514   for (const auto &item : pending_stops)
515     {
516       if (desired_stop_thread_id == -1
517 	  || desired_stop_thread_id == item.thread_id)
518 	{
519 	  DEBUG_EVENTS ("pending stop anticipated, desired=0x%x, item=0x%x",
520 			desired_stop_thread_id, item.thread_id);
521 	  return true;
522 	}
523     }
524 
525   return false;
526 }
527 
528 /* See nat/windows-nat.h.  */
529 
530 gdb::optional<pending_stop>
fetch_pending_stop(bool debug_events)531 fetch_pending_stop (bool debug_events)
532 {
533   gdb::optional<pending_stop> result;
534   for (auto iter = pending_stops.begin ();
535        iter != pending_stops.end ();
536        ++iter)
537     {
538       if (desired_stop_thread_id == -1
539 	  || desired_stop_thread_id == iter->thread_id)
540 	{
541 	  result = *iter;
542 	  current_event = iter->event;
543 
544 	  DEBUG_EVENTS ("pending stop found in 0x%x (desired=0x%x)",
545 			iter->thread_id, desired_stop_thread_id);
546 
547 	  pending_stops.erase (iter);
548 	  break;
549 	}
550     }
551 
552   return result;
553 }
554 
555 /* See nat/windows-nat.h.  */
556 
557 BOOL
continue_last_debug_event(DWORD continue_status,bool debug_events)558 continue_last_debug_event (DWORD continue_status, bool debug_events)
559 {
560   DEBUG_EVENTS ("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s)",
561 		(unsigned) last_wait_event.dwProcessId,
562 		(unsigned) last_wait_event.dwThreadId,
563 		continue_status == DBG_CONTINUE ?
564 		"DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED");
565 
566   return ContinueDebugEvent (last_wait_event.dwProcessId,
567 			     last_wait_event.dwThreadId,
568 			     continue_status);
569 }
570 
571 /* See nat/windows-nat.h.  */
572 
573 BOOL
wait_for_debug_event(DEBUG_EVENT * event,DWORD timeout)574 wait_for_debug_event (DEBUG_EVENT *event, DWORD timeout)
575 {
576   BOOL result = WaitForDebugEvent (event, timeout);
577   if (result)
578     last_wait_event = *event;
579   return result;
580 }
581 
582 /* Define dummy functions which always return error for the rare cases where
583    these functions could not be found.  */
584 template<typename... T>
585 BOOL WINAPI
bad(T...args)586 bad (T... args)
587 {
588   return FALSE;
589 }
590 
591 template<typename... T>
592 DWORD WINAPI
bad(T...args)593 bad (T... args)
594 {
595   return 0;
596 }
597 
598 static BOOL WINAPI
bad_GetCurrentConsoleFont(HANDLE w,BOOL bMaxWindow,CONSOLE_FONT_INFO * f)599 bad_GetCurrentConsoleFont (HANDLE w, BOOL bMaxWindow, CONSOLE_FONT_INFO *f)
600 {
601   f->nFont = 0;
602   return 1;
603 }
604 
605 static COORD WINAPI
bad_GetConsoleFontSize(HANDLE w,DWORD nFont)606 bad_GetConsoleFontSize (HANDLE w, DWORD nFont)
607 {
608   COORD size;
609   size.X = 8;
610   size.Y = 12;
611   return size;
612 }
613 
614 /* See windows-nat.h.  */
615 
616 bool
initialize_loadable()617 initialize_loadable ()
618 {
619   bool result = true;
620   HMODULE hm = NULL;
621 
622 #define GPA(m, func)					\
623   func = (func ## _ftype *) GetProcAddress (m, #func)
624 
625   hm = LoadLibrary (TEXT ("kernel32.dll"));
626   if (hm)
627     {
628       GPA (hm, DebugActiveProcessStop);
629       GPA (hm, DebugBreakProcess);
630       GPA (hm, DebugSetProcessKillOnExit);
631       GPA (hm, GetConsoleFontSize);
632       GPA (hm, DebugActiveProcessStop);
633       GPA (hm, GetCurrentConsoleFont);
634 #ifdef __x86_64__
635       GPA (hm, Wow64SuspendThread);
636       GPA (hm, Wow64GetThreadContext);
637       GPA (hm, Wow64SetThreadContext);
638       GPA (hm, Wow64GetThreadSelectorEntry);
639 #endif
640       GPA (hm, GenerateConsoleCtrlEvent);
641     }
642 
643   /* Set variables to dummy versions of these processes if the function
644      wasn't found in kernel32.dll.  */
645   if (!DebugBreakProcess)
646     DebugBreakProcess = bad;
647   if (!DebugActiveProcessStop || !DebugSetProcessKillOnExit)
648     {
649       DebugActiveProcessStop = bad;
650       DebugSetProcessKillOnExit = bad;
651     }
652   if (!GetConsoleFontSize)
653     GetConsoleFontSize = bad_GetConsoleFontSize;
654   if (!GetCurrentConsoleFont)
655     GetCurrentConsoleFont = bad_GetCurrentConsoleFont;
656 
657   /* Load optional functions used for retrieving filename information
658      associated with the currently debugged process or its dlls.  */
659   hm = LoadLibrary (TEXT ("psapi.dll"));
660   if (hm)
661     {
662       GPA (hm, EnumProcessModules);
663 #ifdef __x86_64__
664       GPA (hm, EnumProcessModulesEx);
665 #endif
666       GPA (hm, GetModuleInformation);
667       GPA (hm, GetModuleFileNameExA);
668       GPA (hm, GetModuleFileNameExW);
669     }
670 
671   if (!EnumProcessModules || !GetModuleInformation
672       || !GetModuleFileNameExA || !GetModuleFileNameExW)
673     {
674       /* Set variables to dummy versions of these processes if the function
675 	 wasn't found in psapi.dll.  */
676       EnumProcessModules = bad;
677       GetModuleInformation = bad;
678       GetModuleFileNameExA = bad;
679       GetModuleFileNameExW = bad;
680 
681       result = false;
682     }
683 
684   hm = LoadLibrary (TEXT ("advapi32.dll"));
685   if (hm)
686     {
687       GPA (hm, OpenProcessToken);
688       GPA (hm, LookupPrivilegeValueA);
689       GPA (hm, AdjustTokenPrivileges);
690       /* Only need to set one of these since if OpenProcessToken fails nothing
691 	 else is needed.  */
692       if (!OpenProcessToken || !LookupPrivilegeValueA
693 	  || !AdjustTokenPrivileges)
694 	OpenProcessToken = bad;
695     }
696 
697 #undef GPA
698 
699   return result;
700 }
701 
702 }
703