1 /* Internal interfaces for the Windows code
2 Copyright (C) 1995-2022 Free Software Foundation, Inc.
4 This file is part of GDB.
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.
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.
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/>. */
19 #include "gdbsupport/common-defs.h"
20 #include "nat/windows-nat.h"
21 #include "gdbsupport/common-debug.h"
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
;
33 AdjustTokenPrivileges_ftype
*AdjustTokenPrivileges
;
34 DebugActiveProcessStop_ftype
*DebugActiveProcessStop
;
35 DebugBreakProcess_ftype
*DebugBreakProcess
;
36 DebugSetProcessKillOnExit_ftype
*DebugSetProcessKillOnExit
;
37 EnumProcessModules_ftype
*EnumProcessModules
;
39 EnumProcessModulesEx_ftype
*EnumProcessModulesEx
;
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
;
49 Wow64SuspendThread_ftype
*Wow64SuspendThread
;
50 Wow64GetThreadContext_ftype
*Wow64GetThreadContext
;
51 Wow64SetThreadContext_ftype
*Wow64SetThreadContext
;
52 Wow64GetThreadSelectorEntry_ftype
*Wow64GetThreadSelectorEntry
;
54 GenerateConsoleCtrlEvent_ftype
*GenerateConsoleCtrlEvent
;
56 /* Note that 'debug_events' must be locally defined in the relevant
58 #define DEBUG_EVENTS(fmt, ...) \
59 debug_prefixed_printf_cond (debug_events, "windows events", fmt, \
63 windows_thread_info::suspend ()
68 if (SuspendThread (h
) == (DWORD
) -1)
70 DWORD err
= GetLastError ();
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
76 We can get Invalid Handle (6) if the main thread
78 if (err
!= ERROR_INVALID_HANDLE
&& err
!= ERROR_ACCESS_DENIED
)
79 warning (_("SuspendThread (tid=0x%x) failed. (winerr %u)"),
80 (unsigned) tid
, (unsigned) err
);
88 windows_thread_info::resume ()
92 stopped_at_software_breakpoint
= false;
94 if (ResumeThread (h
) == (DWORD
) -1)
96 DWORD err
= GetLastError ();
97 warning (_("warning: ResumeThread (tid=0x%x) failed. (winerr %u)"),
98 (unsigned) tid
, (unsigned) err
);
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
111 get_image_name (HANDLE h
, void *address
, int unicode
)
114 static char buf
[MAX_PATH
];
116 static char buf
[(2 * MAX_PATH
) + 1];
118 DWORD size
= unicode
? sizeof (WCHAR
) : sizeof (char);
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. */
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
)
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
)
144 ReadProcessMemory (h
, address_ptr
, buf
, len
, &done
);
147 WCHAR
*unicode_address
= (WCHAR
*) alloca (len
* sizeof (WCHAR
));
148 ReadProcessMemory (h
, address_ptr
, unicode_address
, len
* sizeof (WCHAR
),
151 wcstombs (buf
, unicode_address
, MAX_PATH
);
153 WideCharToMultiByte (CP_ACP
, 0, unicode_address
, len
, buf
, sizeof buf
,
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
167 handle_exception_result
168 windows_process_info::handle_exception (struct target_waitstatus
*ourstatus
,
169 bool debug_exceptions
)
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))
176 EXCEPTION_RECORD
*rec
= ¤t_event
.u
.Exception
.ExceptionRecord
;
177 DWORD code
= rec
->ExceptionCode
;
178 handle_exception_result result
= HANDLE_EXCEPTION_HANDLED
;
180 memcpy (&siginfo_er
, rec
, sizeof siginfo_er
);
182 /* Record the context of the current thread. */
183 thread_rec (ptid_t (current_event
.dwProcessId
, current_event
.dwThreadId
, 0),
186 last_sig
= GDB_SIGNAL_0
;
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
;
196 case STATUS_STACK_OVERFLOW
:
197 DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
198 ourstatus
->set_stopped (GDB_SIGNAL_SEGV
);
200 case STATUS_FLOAT_DENORMAL_OPERAND
:
201 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
202 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
204 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
205 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
206 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
208 case STATUS_FLOAT_INEXACT_RESULT
:
209 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
210 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
212 case STATUS_FLOAT_INVALID_OPERATION
:
213 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
214 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
216 case STATUS_FLOAT_OVERFLOW
:
217 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
218 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
220 case STATUS_FLOAT_STACK_CHECK
:
221 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
222 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
224 case STATUS_FLOAT_UNDERFLOW
:
225 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
226 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
228 case STATUS_FLOAT_DIVIDE_BY_ZERO
:
229 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
230 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
232 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
233 DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
234 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
236 case STATUS_INTEGER_OVERFLOW
:
237 DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
238 ourstatus
->set_stopped (GDB_SIGNAL_FPE
);
240 case EXCEPTION_BREAKPOINT
:
242 if (ignore_first_breakpoint
)
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;
253 else if (wow64_process
)
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
262 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT - wow64_process");
263 rec
->ExceptionCode
= DBG_CONTROL_C
;
264 ourstatus
->set_stopped (GDB_SIGNAL_INT
);
269 case STATUS_WX86_BREAKPOINT
:
270 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
271 ourstatus
->set_stopped (GDB_SIGNAL_TRAP
);
274 DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
275 ourstatus
->set_stopped (GDB_SIGNAL_INT
);
277 case DBG_CONTROL_BREAK
:
278 DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
279 ourstatus
->set_stopped (GDB_SIGNAL_INT
);
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
);
286 case EXCEPTION_ILLEGAL_INSTRUCTION
:
287 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
288 ourstatus
->set_stopped (GDB_SIGNAL_ILL
);
290 case EXCEPTION_PRIV_INSTRUCTION
:
291 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
292 ourstatus
->set_stopped (GDB_SIGNAL_ILL
);
294 case EXCEPTION_NONCONTINUABLE_EXCEPTION
:
295 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
296 ourstatus
->set_stopped (GDB_SIGNAL_ILL
);
298 case MS_VC_EXCEPTION
:
299 DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
300 if (handle_ms_vc_exception (rec
))
302 ourstatus
->set_stopped (GDB_SIGNAL_TRAP
);
303 result
= HANDLE_EXCEPTION_IGNORED
;
306 /* treat improperly formed exception as unknown */
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
);
320 if (ourstatus
->kind () == TARGET_WAITKIND_STOPPED
)
321 last_sig
= ourstatus
->sig ();
325 #undef DEBUG_EXCEPTION_SIMPLE
328 /* See nat/windows-nat.h. */
331 windows_process_info::add_dll (LPVOID load_addr
)
333 HMODULE dummy_hmodule
;
341 if (EnumProcessModulesEx (handle
, &dummy_hmodule
,
342 sizeof (HMODULE
), &cb_needed
,
343 LIST_MODULES_32BIT
) == 0)
349 if (EnumProcessModules (handle
, &dummy_hmodule
,
350 sizeof (HMODULE
), &cb_needed
) == 0)
357 hmodules
= (HMODULE
*) alloca (cb_needed
);
361 if (EnumProcessModulesEx (handle
, hmodules
,
362 cb_needed
, &cb_needed
,
363 LIST_MODULES_32BIT
) == 0)
369 if (EnumProcessModules (handle
, hmodules
,
370 cb_needed
, &cb_needed
) == 0)
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;
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
));
387 /* Check that we have passed a large enough buffer. */
388 gdb_assert (len
< sizeof (syswow_dir
));
390 len
= GetSystemDirectoryA (system_dir
, sizeof (system_dir
));
392 gdb_assert (len
!= 0);
393 /* Check that we have passed a large enough buffer. */
394 gdb_assert (len
< sizeof (system_dir
));
396 strcat (system_dir
, "\\");
397 strcat (syswow_dir
, "\\");
398 system_dir_len
= strlen (system_dir
);
400 convert_syswow_dir
= true;
404 for (i
= 1; i
< (int) (cb_needed
/ sizeof (HMODULE
)); i
++)
408 wchar_t dll_name
[MAX_PATH
];
409 char dll_name_mb
[MAX_PATH
];
411 char dll_name
[MAX_PATH
];
414 if (GetModuleInformation (handle
, hmodules
[i
],
415 &mi
, sizeof (mi
)) == 0)
418 if (GetModuleFileNameEx (handle
, hmodules
[i
],
419 dll_name
, sizeof (dll_name
)) == 0)
422 wcstombs (dll_name_mb
, dll_name
, MAX_PATH
);
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)
435 syswow_dll_path
= syswow_dir
;
436 syswow_dll_path
+= name
+ system_dir_len
;
437 name
= syswow_dll_path
.c_str();
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
))
444 handle_load_dll (name
, mi
.lpBaseOfDll
);
445 if (load_addr
!= nullptr)
451 /* See nat/windows-nat.h. */
454 windows_process_info::dll_loaded_event ()
456 gdb_assert (current_event
.dwDebugEventCode
== LOAD_DLL_DEBUG_EVENT
);
458 LOAD_DLL_DEBUG_INFO
*event
= ¤t_event
.u
.LoadDll
;
459 const char *dll_name
;
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
);
476 /* See nat/windows-nat.h. */
479 windows_process_info::add_all_dlls ()
484 /* See nat/windows-nat.h. */
487 windows_process_info::matching_pending_stop (bool debug_events
)
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
)
496 if (desired_stop_thread_id
== -1
497 || desired_stop_thread_id
== item
.thread_id
)
499 DEBUG_EVENTS ("pending stop anticipated, desired=0x%x, item=0x%x",
500 desired_stop_thread_id
, item
.thread_id
);
508 /* See nat/windows-nat.h. */
510 gdb::optional
<pending_stop
>
511 windows_process_info::fetch_pending_stop (bool debug_events
)
513 gdb::optional
<pending_stop
> result
;
514 for (auto iter
= pending_stops
.begin ();
515 iter
!= pending_stops
.end ();
518 if (desired_stop_thread_id
== -1
519 || desired_stop_thread_id
== iter
->thread_id
)
522 current_event
= iter
->event
;
524 DEBUG_EVENTS ("pending stop found in 0x%x (desired=0x%x)",
525 iter
->thread_id
, desired_stop_thread_id
);
527 pending_stops
.erase (iter
);
535 /* See nat/windows-nat.h. */
538 continue_last_debug_event (DWORD continue_status
, bool debug_events
)
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");
546 return ContinueDebugEvent (last_wait_event
.dwProcessId
,
547 last_wait_event
.dwThreadId
,
551 /* See nat/windows-nat.h. */
554 wait_for_debug_event (DEBUG_EVENT
*event
, DWORD timeout
)
556 BOOL result
= WaitForDebugEvent (event
, timeout
);
558 last_wait_event
= *event
;
562 /* Define dummy functions which always return error for the rare cases where
563 these functions could not be found. */
564 template<typename
... T
>
571 template<typename
... T
>
579 bad_GetCurrentConsoleFont (HANDLE w
, BOOL bMaxWindow
, CONSOLE_FONT_INFO
*f
)
586 bad_GetConsoleFontSize (HANDLE w
, DWORD nFont
)
594 /* See windows-nat.h. */
597 initialize_loadable ()
602 #define GPA(m, func) \
603 func = (func ## _ftype *) GetProcAddress (m, #func)
605 hm
= LoadLibrary (TEXT ("kernel32.dll"));
608 GPA (hm
, DebugActiveProcessStop
);
609 GPA (hm
, DebugBreakProcess
);
610 GPA (hm
, DebugSetProcessKillOnExit
);
611 GPA (hm
, GetConsoleFontSize
);
612 GPA (hm
, DebugActiveProcessStop
);
613 GPA (hm
, GetCurrentConsoleFont
);
615 GPA (hm
, Wow64SuspendThread
);
616 GPA (hm
, Wow64GetThreadContext
);
617 GPA (hm
, Wow64SetThreadContext
);
618 GPA (hm
, Wow64GetThreadSelectorEntry
);
620 GPA (hm
, GenerateConsoleCtrlEvent
);
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
)
629 DebugActiveProcessStop
= bad
;
630 DebugSetProcessKillOnExit
= bad
;
632 if (!GetConsoleFontSize
)
633 GetConsoleFontSize
= bad_GetConsoleFontSize
;
634 if (!GetCurrentConsoleFont
)
635 GetCurrentConsoleFont
= bad_GetCurrentConsoleFont
;
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"));
642 GPA (hm
, EnumProcessModules
);
644 GPA (hm
, EnumProcessModulesEx
);
646 GPA (hm
, GetModuleInformation
);
647 GPA (hm
, GetModuleFileNameExA
);
648 GPA (hm
, GetModuleFileNameExW
);
651 if (!EnumProcessModules
|| !GetModuleInformation
652 || !GetModuleFileNameExA
|| !GetModuleFileNameExW
)
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
;
664 hm
= LoadLibrary (TEXT ("advapi32.dll"));
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
672 if (!OpenProcessToken
|| !LookupPrivilegeValueA
673 || !AdjustTokenPrivileges
)
674 OpenProcessToken
= bad
;