Share handle_exception
[deliverable/binutils-gdb.git] / gdb / nat / windows-nat.c
1 /* Internal interfaces for the Windows code
2 Copyright (C) 1995-2020 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 #define STATUS_WX86_BREAKPOINT 0x4000001F
24 #define STATUS_WX86_SINGLE_STEP 0x4000001E
25
26 namespace windows_nat
27 {
28
29 HANDLE current_process_handle;
30 DWORD current_process_id;
31 DWORD main_thread_id;
32 enum gdb_signal last_sig = GDB_SIGNAL_0;
33 DEBUG_EVENT current_event;
34 DEBUG_EVENT last_wait_event;
35 windows_thread_info *current_windows_thread;
36 DWORD desired_stop_thread_id = -1;
37 std::vector<pending_stop> pending_stops;
38 EXCEPTION_RECORD siginfo_er;
39
40 windows_thread_info::~windows_thread_info ()
41 {
42 CloseHandle (h);
43 }
44
45 void
46 windows_thread_info::suspend ()
47 {
48 if (suspended != 0)
49 return;
50
51 if (SuspendThread (h) == (DWORD) -1)
52 {
53 DWORD err = GetLastError ();
54
55 /* We get Access Denied (5) when trying to suspend
56 threads that Windows started on behalf of the
57 debuggee, usually when those threads are just
58 about to exit.
59 We can get Invalid Handle (6) if the main thread
60 has exited. */
61 if (err != ERROR_INVALID_HANDLE && err != ERROR_ACCESS_DENIED)
62 warning (_("SuspendThread (tid=0x%x) failed. (winerr %u)"),
63 (unsigned) tid, (unsigned) err);
64 suspended = -1;
65 }
66 else
67 suspended = 1;
68 }
69
70 void
71 windows_thread_info::resume ()
72 {
73 if (suspended > 0)
74 {
75 stopped_at_software_breakpoint = false;
76
77 if (ResumeThread (h) == (DWORD) -1)
78 {
79 DWORD err = GetLastError ();
80 warning (_("warning: ResumeThread (tid=0x%x) failed. (winerr %u)"),
81 (unsigned) tid, (unsigned) err);
82 }
83 }
84 suspended = 0;
85 }
86
87 const char *
88 get_image_name (HANDLE h, void *address, int unicode)
89 {
90 #ifdef __CYGWIN__
91 static char buf[MAX_PATH];
92 #else
93 static char buf[(2 * MAX_PATH) + 1];
94 #endif
95 DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
96 char *address_ptr;
97 int len = 0;
98 char b[2];
99 SIZE_T done;
100
101 /* Attempt to read the name of the dll that was detected.
102 This is documented to work only when actively debugging
103 a program. It will not work for attached processes. */
104 if (address == NULL)
105 return NULL;
106
107 #ifdef _WIN32_WCE
108 /* Windows CE reports the address of the image name,
109 instead of an address of a pointer into the image name. */
110 address_ptr = address;
111 #else
112 /* See if we could read the address of a string, and that the
113 address isn't null. */
114 if (!ReadProcessMemory (h, address, &address_ptr,
115 sizeof (address_ptr), &done)
116 || done != sizeof (address_ptr)
117 || !address_ptr)
118 return NULL;
119 #endif
120
121 /* Find the length of the string. */
122 while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
123 && (b[0] != 0 || b[size - 1] != 0) && done == size)
124 continue;
125
126 if (!unicode)
127 ReadProcessMemory (h, address_ptr, buf, len, &done);
128 else
129 {
130 WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
131 ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
132 &done);
133 #ifdef __CYGWIN__
134 wcstombs (buf, unicode_address, MAX_PATH);
135 #else
136 WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, sizeof buf,
137 0, 0);
138 #endif
139 }
140
141 return buf;
142 }
143
144 /* The exception thrown by a program to tell the debugger the name of
145 a thread. The exception record contains an ID of a thread and a
146 name to give it. This exception has no documented name, but MSDN
147 dubs it "MS_VC_EXCEPTION" in one code example. */
148 #define MS_VC_EXCEPTION 0x406d1388
149
150 handle_exception_result
151 handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
152 {
153 #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
154 debug_printf ("gdb: Target exception %s at %s\n", x, \
155 host_address_to_string (\
156 current_event.u.Exception.ExceptionRecord.ExceptionAddress))
157
158 EXCEPTION_RECORD *rec = &current_event.u.Exception.ExceptionRecord;
159 DWORD code = rec->ExceptionCode;
160 handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
161
162 memcpy (&siginfo_er, rec, sizeof siginfo_er);
163
164 ourstatus->kind = TARGET_WAITKIND_STOPPED;
165
166 /* Record the context of the current thread. */
167 thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
168 DONT_SUSPEND);
169
170 switch (code)
171 {
172 case EXCEPTION_ACCESS_VIOLATION:
173 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
174 ourstatus->value.sig = GDB_SIGNAL_SEGV;
175 #ifdef __CYGWIN__
176 {
177 /* See if the access violation happened within the cygwin DLL
178 itself. Cygwin uses a kind of exception handling to deal
179 with passed-in invalid addresses. gdb should not treat
180 these as real SEGVs since they will be silently handled by
181 cygwin. A real SEGV will (theoretically) be caught by
182 cygwin later in the process and will be sent as a
183 cygwin-specific-signal. So, ignore SEGVs if they show up
184 within the text segment of the DLL itself. */
185 const char *fn;
186 CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress;
187
188 if ((!cygwin_exceptions && (addr >= cygwin_load_start
189 && addr < cygwin_load_end))
190 || (find_pc_partial_function (addr, &fn, NULL, NULL)
191 && startswith (fn, "KERNEL32!IsBad")))
192 return HANDLE_EXCEPTION_UNHANDLED;
193 }
194 #endif
195 break;
196 case STATUS_STACK_OVERFLOW:
197 DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW");
198 ourstatus->value.sig = GDB_SIGNAL_SEGV;
199 break;
200 case STATUS_FLOAT_DENORMAL_OPERAND:
201 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND");
202 ourstatus->value.sig = GDB_SIGNAL_FPE;
203 break;
204 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
205 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
206 ourstatus->value.sig = GDB_SIGNAL_FPE;
207 break;
208 case STATUS_FLOAT_INEXACT_RESULT:
209 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT");
210 ourstatus->value.sig = GDB_SIGNAL_FPE;
211 break;
212 case STATUS_FLOAT_INVALID_OPERATION:
213 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION");
214 ourstatus->value.sig = GDB_SIGNAL_FPE;
215 break;
216 case STATUS_FLOAT_OVERFLOW:
217 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW");
218 ourstatus->value.sig = GDB_SIGNAL_FPE;
219 break;
220 case STATUS_FLOAT_STACK_CHECK:
221 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK");
222 ourstatus->value.sig = GDB_SIGNAL_FPE;
223 break;
224 case STATUS_FLOAT_UNDERFLOW:
225 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW");
226 ourstatus->value.sig = GDB_SIGNAL_FPE;
227 break;
228 case STATUS_FLOAT_DIVIDE_BY_ZERO:
229 DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO");
230 ourstatus->value.sig = GDB_SIGNAL_FPE;
231 break;
232 case STATUS_INTEGER_DIVIDE_BY_ZERO:
233 DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO");
234 ourstatus->value.sig = GDB_SIGNAL_FPE;
235 break;
236 case STATUS_INTEGER_OVERFLOW:
237 DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW");
238 ourstatus->value.sig = 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 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
249 ignore_first_breakpoint = false;
250 }
251 #endif
252 /* FALLTHROUGH */
253 case STATUS_WX86_BREAKPOINT:
254 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT");
255 ourstatus->value.sig = GDB_SIGNAL_TRAP;
256 #ifdef _WIN32_WCE
257 /* Remove the initial breakpoint. */
258 check_breakpoints ((CORE_ADDR) (long) current_event
259 .u.Exception.ExceptionRecord.ExceptionAddress);
260 #endif
261 break;
262 case DBG_CONTROL_C:
263 DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C");
264 ourstatus->value.sig = GDB_SIGNAL_INT;
265 break;
266 case DBG_CONTROL_BREAK:
267 DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK");
268 ourstatus->value.sig = GDB_SIGNAL_INT;
269 break;
270 case EXCEPTION_SINGLE_STEP:
271 case STATUS_WX86_SINGLE_STEP:
272 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP");
273 ourstatus->value.sig = GDB_SIGNAL_TRAP;
274 break;
275 case EXCEPTION_ILLEGAL_INSTRUCTION:
276 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION");
277 ourstatus->value.sig = GDB_SIGNAL_ILL;
278 break;
279 case EXCEPTION_PRIV_INSTRUCTION:
280 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION");
281 ourstatus->value.sig = GDB_SIGNAL_ILL;
282 break;
283 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
284 DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION");
285 ourstatus->value.sig = GDB_SIGNAL_ILL;
286 break;
287 case MS_VC_EXCEPTION:
288 DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
289 if (handle_ms_vc_exception (rec))
290 {
291 ourstatus->value.sig = GDB_SIGNAL_TRAP;
292 result = HANDLE_EXCEPTION_IGNORED;
293 break;
294 }
295 /* treat improperly formed exception as unknown */
296 /* FALLTHROUGH */
297 default:
298 /* Treat unhandled first chance exceptions specially. */
299 if (current_event.u.Exception.dwFirstChance)
300 return HANDLE_EXCEPTION_UNHANDLED;
301 debug_printf ("gdb: unknown target exception 0x%08x at %s\n",
302 (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
303 host_address_to_string (
304 current_event.u.Exception.ExceptionRecord.ExceptionAddress));
305 ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
306 break;
307 }
308
309 last_sig = ourstatus->value.sig;
310 return result;
311
312 #undef DEBUG_EXCEPTION_SIMPLE
313 }
314
315 }
This page took 0.035059 seconds and 4 git commands to generate.