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