]>
Commit | Line | Data |
---|---|---|
b80864fb | 1 | /* Low level interface to Windows debugging, for gdbserver. |
213516ef | 2 | Copyright (C) 2006-2023 Free Software Foundation, Inc. |
b80864fb DJ |
3 | |
4 | Contributed by Leo Zayas. Based on "win32-nat.c" from GDB. | |
5 | ||
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 10 | the Free Software Foundation; either version 3 of the License, or |
b80864fb DJ |
11 | (at your option) any later version. |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
b80864fb DJ |
20 | |
21 | #include "server.h" | |
22 | #include "regcache.h" | |
198f946f | 23 | #include "gdbsupport/fileio.h" |
ed50f18f PA |
24 | #include "mem-break.h" |
25 | #include "win32-low.h" | |
623b6bdf | 26 | #include "gdbthread.h" |
799cdc37 | 27 | #include "dll.h" |
533b0600 | 28 | #include "hostio.h" |
b80864fb | 29 | #include <windows.h> |
ed50f18f | 30 | #include <winnt.h> |
b80864fb | 31 | #include <imagehlp.h> |
255e7678 | 32 | #include <tlhelp32.h> |
b80864fb | 33 | #include <psapi.h> |
b80864fb | 34 | #include <process.h> |
268a13a5 TT |
35 | #include "gdbsupport/gdb_tilde_expand.h" |
36 | #include "gdbsupport/common-inferior.h" | |
559e7e50 | 37 | #include "gdbsupport/gdb_wait.h" |
b80864fb | 38 | |
4834dad0 TT |
39 | using namespace windows_nat; |
40 | ||
801eb70f | 41 | /* See win32-low.h. */ |
20489cca | 42 | gdbserver_windows_process windows_process; |
0578e87f | 43 | |
b80864fb DJ |
44 | #ifndef USE_WIN32API |
45 | #include <sys/cygwin.h> | |
46 | #endif | |
47 | ||
10357975 PA |
48 | #define OUTMSG(X) do { printf X; fflush (stderr); } while (0) |
49 | ||
50 | #define OUTMSG2(X) \ | |
51 | do \ | |
52 | { \ | |
53 | if (debug_threads) \ | |
54 | { \ | |
55 | printf X; \ | |
56 | fflush (stderr); \ | |
57 | } \ | |
58 | } while (0) | |
ed50f18f PA |
59 | |
60 | #ifndef _T | |
61 | #define _T(x) TEXT (x) | |
62 | #endif | |
63 | ||
b80864fb DJ |
64 | int using_threads = 1; |
65 | ||
3aee8918 | 66 | const struct target_desc *win32_tdesc; |
7d186bc0 HD |
67 | #ifdef __x86_64__ |
68 | const struct target_desc *wow64_win32_tdesc; | |
69 | #endif | |
3aee8918 | 70 | |
7d186bc0 | 71 | #define NUM_REGS (the_low_target.num_regs ()) |
b80864fb | 72 | |
b80864fb DJ |
73 | /* Get the thread ID from the current selected inferior (the current |
74 | thread). */ | |
95954743 | 75 | static ptid_t |
0bfdf32f | 76 | current_thread_ptid (void) |
b80864fb | 77 | { |
80894984 | 78 | return current_ptid; |
95954743 PA |
79 | } |
80 | ||
81 | /* The current debug event from WaitForDebugEvent. */ | |
82 | static ptid_t | |
83 | debug_event_ptid (DEBUG_EVENT *event) | |
84 | { | |
fd79271b | 85 | return ptid_t (event->dwProcessId, event->dwThreadId, 0); |
b80864fb DJ |
86 | } |
87 | ||
9c6c8194 PA |
88 | /* Get the thread context of the thread associated with TH. */ |
89 | ||
90 | static void | |
e56f8ccb | 91 | win32_get_thread_context (windows_thread_info *th) |
9c6c8194 | 92 | { |
7d186bc0 | 93 | #ifdef __x86_64__ |
801eb70f | 94 | if (windows_process.wow64_process) |
7d186bc0 HD |
95 | memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT)); |
96 | else | |
97 | #endif | |
98 | memset (&th->context, 0, sizeof (CONTEXT)); | |
a2abc7de | 99 | (*the_low_target.get_thread_context) (th); |
9c6c8194 PA |
100 | } |
101 | ||
102 | /* Set the thread context of the thread associated with TH. */ | |
103 | ||
104 | static void | |
e56f8ccb | 105 | win32_set_thread_context (windows_thread_info *th) |
9c6c8194 | 106 | { |
7d186bc0 | 107 | #ifdef __x86_64__ |
801eb70f | 108 | if (windows_process.wow64_process) |
de071872 | 109 | Wow64SetThreadContext (th->h, &th->wow64_context); |
d4717483 | 110 | else |
7d186bc0 | 111 | #endif |
d4717483 | 112 | SetThreadContext (th->h, &th->context); |
9c6c8194 PA |
113 | } |
114 | ||
a2abc7de PA |
115 | /* Set the thread context of the thread associated with TH. */ |
116 | ||
117 | static void | |
e56f8ccb | 118 | win32_prepare_to_resume (windows_thread_info *th) |
b80864fb | 119 | { |
a2abc7de PA |
120 | if (the_low_target.prepare_to_resume != NULL) |
121 | (*the_low_target.prepare_to_resume) (th); | |
122 | } | |
b80864fb | 123 | |
a2abc7de | 124 | /* See win32-low.h. */ |
b80864fb | 125 | |
a2abc7de | 126 | void |
e56f8ccb | 127 | win32_require_context (windows_thread_info *th) |
a2abc7de | 128 | { |
7d186bc0 HD |
129 | DWORD context_flags; |
130 | #ifdef __x86_64__ | |
801eb70f | 131 | if (windows_process.wow64_process) |
7d186bc0 HD |
132 | context_flags = th->wow64_context.ContextFlags; |
133 | else | |
134 | #endif | |
135 | context_flags = th->context.ContextFlags; | |
136 | if (context_flags == 0) | |
b80864fb | 137 | { |
98a03287 | 138 | th->suspend (); |
9c6c8194 | 139 | win32_get_thread_context (th); |
b80864fb | 140 | } |
a2abc7de PA |
141 | } |
142 | ||
28688adf TT |
143 | /* See nat/windows-nat.h. */ |
144 | ||
145 | windows_thread_info * | |
20489cca | 146 | gdbserver_windows_process::thread_rec |
0578e87f | 147 | (ptid_t ptid, thread_disposition_type disposition) |
a2abc7de | 148 | { |
8dc7b443 | 149 | thread_info *thread = find_thread_ptid (ptid); |
a2abc7de PA |
150 | if (thread == NULL) |
151 | return NULL; | |
152 | ||
e56f8ccb | 153 | windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); |
28688adf | 154 | if (disposition != DONT_INVALIDATE_CONTEXT) |
a2abc7de | 155 | win32_require_context (th); |
b80864fb DJ |
156 | return th; |
157 | } | |
158 | ||
159 | /* Add a thread to the thread list. */ | |
e56f8ccb | 160 | static windows_thread_info * |
711e434b | 161 | child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) |
b80864fb | 162 | { |
e56f8ccb | 163 | windows_thread_info *th; |
fd79271b | 164 | ptid_t ptid = ptid_t (pid, tid, 0); |
b80864fb | 165 | |
0578e87f | 166 | if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT))) |
b80864fb DJ |
167 | return th; |
168 | ||
7d186bc0 HD |
169 | CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb; |
170 | #ifdef __x86_64__ | |
171 | /* For WOW64 processes, this is actually the pointer to the 64bit TIB, | |
172 | and the 32bit TIB is exactly 2 pages after it. */ | |
801eb70f | 173 | if (windows_process.wow64_process) |
7d186bc0 HD |
174 | base += 2 * 4096; /* page size = 4096 */ |
175 | #endif | |
176 | th = new windows_thread_info (tid, h, base); | |
b80864fb | 177 | |
95954743 | 178 | add_thread (ptid, th); |
b80864fb | 179 | |
34b34921 PA |
180 | if (the_low_target.thread_added != NULL) |
181 | (*the_low_target.thread_added) (th); | |
b80864fb DJ |
182 | |
183 | return th; | |
184 | } | |
185 | ||
186 | /* Delete a thread from the list of threads. */ | |
187 | static void | |
9c80ecd6 | 188 | delete_thread_info (thread_info *thread) |
b80864fb | 189 | { |
e56f8ccb | 190 | windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); |
b80864fb | 191 | |
c3de4d92 | 192 | remove_thread (thread); |
e9534bd2 | 193 | delete th; |
b80864fb DJ |
194 | } |
195 | ||
196 | /* Delete a thread from the list of threads. */ | |
197 | static void | |
95954743 | 198 | child_delete_thread (DWORD pid, DWORD tid) |
b80864fb | 199 | { |
b80864fb | 200 | /* If the last thread is exiting, just return. */ |
9c80ecd6 | 201 | if (all_threads.size () == 1) |
b80864fb DJ |
202 | return; |
203 | ||
8dc7b443 | 204 | thread_info *thread = find_thread_ptid (ptid_t (pid, tid)); |
b80864fb DJ |
205 | if (thread == NULL) |
206 | return; | |
207 | ||
208 | delete_thread_info (thread); | |
209 | } | |
210 | ||
aa5ca48f DE |
211 | /* These watchpoint related wrapper functions simply pass on the function call |
212 | if the low target has registered a corresponding function. */ | |
213 | ||
a2b2297a TBA |
214 | bool |
215 | win32_process_target::supports_z_point_type (char z_type) | |
802e8e6d | 216 | { |
523d4f80 TT |
217 | return (z_type == Z_PACKET_SW_BP |
218 | || (the_low_target.supports_z_point_type != NULL | |
219 | && the_low_target.supports_z_point_type (z_type))); | |
802e8e6d PA |
220 | } |
221 | ||
7e0bde70 TBA |
222 | int |
223 | win32_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr, | |
224 | int size, raw_breakpoint *bp) | |
aa5ca48f | 225 | { |
523d4f80 TT |
226 | if (type == raw_bkpt_type_sw) |
227 | return insert_memory_breakpoint (bp); | |
228 | else if (the_low_target.insert_point != NULL) | |
802e8e6d | 229 | return the_low_target.insert_point (type, addr, size, bp); |
aa5ca48f DE |
230 | else |
231 | /* Unsupported (see target.h). */ | |
232 | return 1; | |
233 | } | |
234 | ||
7e0bde70 TBA |
235 | int |
236 | win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr, | |
237 | int size, raw_breakpoint *bp) | |
aa5ca48f | 238 | { |
523d4f80 TT |
239 | if (type == raw_bkpt_type_sw) |
240 | return remove_memory_breakpoint (bp); | |
241 | else if (the_low_target.remove_point != NULL) | |
802e8e6d | 242 | return the_low_target.remove_point (type, addr, size, bp); |
aa5ca48f DE |
243 | else |
244 | /* Unsupported (see target.h). */ | |
245 | return 1; | |
246 | } | |
247 | ||
6eeb5c55 TBA |
248 | bool |
249 | win32_process_target::stopped_by_watchpoint () | |
aa5ca48f DE |
250 | { |
251 | if (the_low_target.stopped_by_watchpoint != NULL) | |
252 | return the_low_target.stopped_by_watchpoint (); | |
253 | else | |
6eeb5c55 | 254 | return false; |
aa5ca48f DE |
255 | } |
256 | ||
6eeb5c55 TBA |
257 | CORE_ADDR |
258 | win32_process_target::stopped_data_address () | |
aa5ca48f DE |
259 | { |
260 | if (the_low_target.stopped_data_address != NULL) | |
261 | return the_low_target.stopped_data_address (); | |
262 | else | |
263 | return 0; | |
264 | } | |
265 | ||
266 | ||
b80864fb DJ |
267 | /* Transfer memory from/to the debugged process. */ |
268 | static int | |
269 | child_xfer_memory (CORE_ADDR memaddr, char *our, int len, | |
5b6d1e4f | 270 | int write, process_stratum_target *target) |
b80864fb | 271 | { |
cee83bcb PM |
272 | BOOL success; |
273 | SIZE_T done = 0; | |
274 | DWORD lasterror = 0; | |
e8f0053d | 275 | uintptr_t addr = (uintptr_t) memaddr; |
b80864fb DJ |
276 | |
277 | if (write) | |
278 | { | |
0578e87f | 279 | success = WriteProcessMemory (windows_process.handle, (LPVOID) addr, |
cee83bcb PM |
280 | (LPCVOID) our, len, &done); |
281 | if (!success) | |
282 | lasterror = GetLastError (); | |
0578e87f | 283 | FlushInstructionCache (windows_process.handle, (LPCVOID) addr, len); |
b80864fb DJ |
284 | } |
285 | else | |
286 | { | |
0578e87f | 287 | success = ReadProcessMemory (windows_process.handle, (LPCVOID) addr, |
cee83bcb PM |
288 | (LPVOID) our, len, &done); |
289 | if (!success) | |
290 | lasterror = GetLastError (); | |
b80864fb | 291 | } |
cee83bcb PM |
292 | if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) |
293 | return done; | |
294 | else | |
295 | return success ? done : -1; | |
b80864fb DJ |
296 | } |
297 | ||
ed50f18f | 298 | /* Clear out any old thread list and reinitialize it to a pristine |
b80864fb DJ |
299 | state. */ |
300 | static void | |
301 | child_init_thread_list (void) | |
302 | { | |
f0045347 | 303 | for_each_thread (delete_thread_info); |
b80864fb DJ |
304 | } |
305 | ||
306 | static void | |
95954743 | 307 | do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) |
b80864fb | 308 | { |
3aee8918 PA |
309 | struct process_info *proc; |
310 | ||
0578e87f TT |
311 | windows_process.last_sig = GDB_SIGNAL_0; |
312 | windows_process.handle = proch; | |
0578e87f | 313 | windows_process.main_thread_id = 0; |
5ac588cf | 314 | |
20489cca TT |
315 | windows_process.soft_interrupt_requested = 0; |
316 | windows_process.faked_breakpoint = 0; | |
317 | windows_process.open_process_used = true; | |
5ac588cf | 318 | |
0578e87f TT |
319 | memset (&windows_process.current_event, 0, |
320 | sizeof (windows_process.current_event)); | |
b80864fb | 321 | |
7d186bc0 HD |
322 | #ifdef __x86_64__ |
323 | BOOL wow64; | |
324 | if (!IsWow64Process (proch, &wow64)) | |
325 | { | |
326 | DWORD err = GetLastError (); | |
327 | error ("Check if WOW64 process failed (error %d): %s\n", | |
328 | (int) err, strwinerror (err)); | |
329 | } | |
801eb70f | 330 | windows_process.wow64_process = wow64; |
7d186bc0 | 331 | |
801eb70f | 332 | if (windows_process.wow64_process |
de071872 TT |
333 | && (Wow64GetThreadContext == nullptr |
334 | || Wow64SetThreadContext == nullptr)) | |
7d186bc0 HD |
335 | error ("WOW64 debugging is not supported on this system.\n"); |
336 | ||
801eb70f TT |
337 | windows_process.ignore_first_breakpoint |
338 | = !attached && windows_process.wow64_process; | |
7d186bc0 HD |
339 | #endif |
340 | ||
3aee8918 | 341 | proc = add_process (pid, attached); |
7d186bc0 | 342 | #ifdef __x86_64__ |
801eb70f | 343 | if (windows_process.wow64_process) |
7d186bc0 HD |
344 | proc->tdesc = wow64_win32_tdesc; |
345 | else | |
346 | #endif | |
347 | proc->tdesc = win32_tdesc; | |
b80864fb | 348 | child_init_thread_list (); |
20489cca | 349 | windows_process.child_initialization_done = 0; |
ed50f18f PA |
350 | |
351 | if (the_low_target.initial_stuff != NULL) | |
352 | (*the_low_target.initial_stuff) (); | |
4210d83e | 353 | |
20489cca | 354 | windows_process.cached_status.set_ignore (); |
4210d83e PA |
355 | |
356 | /* Flush all currently pending debug events (thread and dll list) up | |
357 | to the initial breakpoint. */ | |
358 | while (1) | |
359 | { | |
360 | struct target_waitstatus status; | |
361 | ||
52405d85 | 362 | the_target->wait (minus_one_ptid, &status, 0); |
4210d83e PA |
363 | |
364 | /* Note win32_wait doesn't return thread events. */ | |
183be222 | 365 | if (status.kind () != TARGET_WAITKIND_LOADED) |
4210d83e | 366 | { |
20489cca | 367 | windows_process.cached_status = status; |
4210d83e PA |
368 | break; |
369 | } | |
370 | ||
371 | { | |
372 | struct thread_resume resume; | |
373 | ||
374 | resume.thread = minus_one_ptid; | |
375 | resume.kind = resume_continue; | |
376 | resume.sig = 0; | |
377 | ||
52405d85 | 378 | the_target->resume (&resume, 1); |
4210d83e PA |
379 | } |
380 | } | |
379a5e2d | 381 | |
f25b3fc3 JB |
382 | /* Now that the inferior has been started and all DLLs have been mapped, |
383 | we can iterate over all DLLs and load them in. | |
384 | ||
385 | We avoid doing it any earlier because, on certain versions of Windows, | |
386 | LOAD_DLL_DEBUG_EVENTs are sometimes not complete. In particular, | |
387 | we have seen on Windows 8.1 that the ntdll.dll load event does not | |
388 | include the DLL name, preventing us from creating an associated SO. | |
389 | A possible explanation is that ntdll.dll might be mapped before | |
390 | the SO info gets created by the Windows system -- ntdll.dll is | |
391 | the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs | |
392 | do not seem to suffer from that problem. | |
393 | ||
394 | Rather than try to work around this sort of issue, it is much | |
395 | simpler to just ignore DLL load/unload events during the startup | |
396 | phase, and then process them all in one batch now. */ | |
0578e87f | 397 | windows_process.add_all_dlls (); |
f25b3fc3 | 398 | |
20489cca | 399 | windows_process.child_initialization_done = 1; |
b80864fb DJ |
400 | } |
401 | ||
402 | /* Resume all artificially suspended threads if we are continuing | |
403 | execution. */ | |
2bee2b6c SM |
404 | static void |
405 | continue_one_thread (thread_info *thread, int thread_id) | |
b80864fb | 406 | { |
e56f8ccb | 407 | windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); |
b80864fb | 408 | |
a2abc7de | 409 | if (thread_id == -1 || thread_id == th->tid) |
b80864fb | 410 | { |
a2abc7de | 411 | win32_prepare_to_resume (th); |
34b34921 | 412 | |
a2abc7de | 413 | if (th->suspended) |
c436e841 | 414 | { |
7d186bc0 HD |
415 | DWORD *context_flags; |
416 | #ifdef __x86_64__ | |
801eb70f | 417 | if (windows_process.wow64_process) |
7d186bc0 HD |
418 | context_flags = &th->wow64_context.ContextFlags; |
419 | else | |
420 | #endif | |
421 | context_flags = &th->context.ContextFlags; | |
422 | if (*context_flags) | |
a2abc7de PA |
423 | { |
424 | win32_set_thread_context (th); | |
7d186bc0 | 425 | *context_flags = 0; |
a2abc7de PA |
426 | } |
427 | ||
98a03287 | 428 | th->resume (); |
c436e841 | 429 | } |
b80864fb | 430 | } |
b80864fb DJ |
431 | } |
432 | ||
433 | static BOOL | |
434 | child_continue (DWORD continue_status, int thread_id) | |
435 | { | |
0578e87f TT |
436 | windows_process.desired_stop_thread_id = thread_id; |
437 | if (windows_process.matching_pending_stop (debug_threads)) | |
360ad8b3 TT |
438 | return TRUE; |
439 | ||
4d5d1aaa PA |
440 | /* The inferior will only continue after the ContinueDebugEvent |
441 | call. */ | |
2bee2b6c SM |
442 | for_each_thread ([&] (thread_info *thread) |
443 | { | |
444 | continue_one_thread (thread, thread_id); | |
445 | }); | |
20489cca | 446 | windows_process.faked_breakpoint = 0; |
b80864fb | 447 | |
e758e19c | 448 | return continue_last_debug_event (continue_status, debug_threads); |
b80864fb DJ |
449 | } |
450 | ||
b80864fb DJ |
451 | /* Fetch register(s) from the current thread context. */ |
452 | static void | |
442ea881 | 453 | child_fetch_inferior_registers (struct regcache *regcache, int r) |
b80864fb DJ |
454 | { |
455 | int regno; | |
0578e87f TT |
456 | windows_thread_info *th |
457 | = windows_process.thread_rec (current_thread_ptid (), | |
458 | INVALIDATE_CONTEXT); | |
4463ce24 | 459 | if (r == -1 || r > NUM_REGS) |
442ea881 | 460 | child_fetch_inferior_registers (regcache, NUM_REGS); |
b80864fb DJ |
461 | else |
462 | for (regno = 0; regno < r; regno++) | |
442ea881 | 463 | (*the_low_target.fetch_inferior_register) (regcache, th, regno); |
b80864fb DJ |
464 | } |
465 | ||
466 | /* Store a new register value into the current thread context. We don't | |
467 | change the program's context until later, when we resume it. */ | |
468 | static void | |
442ea881 | 469 | child_store_inferior_registers (struct regcache *regcache, int r) |
b80864fb DJ |
470 | { |
471 | int regno; | |
0578e87f TT |
472 | windows_thread_info *th |
473 | = windows_process.thread_rec (current_thread_ptid (), | |
474 | INVALIDATE_CONTEXT); | |
b80864fb | 475 | if (r == -1 || r == 0 || r > NUM_REGS) |
442ea881 | 476 | child_store_inferior_registers (regcache, NUM_REGS); |
b80864fb DJ |
477 | else |
478 | for (regno = 0; regno < r; regno++) | |
442ea881 | 479 | (*the_low_target.store_inferior_register) (regcache, th, regno); |
b80864fb DJ |
480 | } |
481 | ||
aec18585 PA |
482 | static BOOL |
483 | create_process (const char *program, char *args, | |
484 | DWORD flags, PROCESS_INFORMATION *pi) | |
485 | { | |
0b73bf7f | 486 | const std::string &inferior_cwd = get_inferior_cwd (); |
aec18585 | 487 | BOOL ret; |
a9b34532 EZ |
488 | size_t argslen, proglen; |
489 | ||
490 | proglen = strlen (program) + 1; | |
491 | argslen = strlen (args) + proglen; | |
aec18585 | 492 | |
aec18585 | 493 | STARTUPINFOA si = { sizeof (STARTUPINFOA) }; |
a9b34532 EZ |
494 | char *program_and_args = (char *) alloca (argslen + 1); |
495 | ||
496 | strcpy (program_and_args, program); | |
497 | strcat (program_and_args, " "); | |
498 | strcat (program_and_args, args); | |
8fea1a81 | 499 | ret = create_process (program, /* image name */ |
a9b34532 | 500 | program_and_args, /* command line */ |
a9b34532 EZ |
501 | flags, /* start flags */ |
502 | NULL, /* environment */ | |
906994d9 | 503 | /* current directory */ |
0b73bf7f | 504 | (inferior_cwd.empty () |
906994d9 | 505 | ? NULL |
0b73bf7f | 506 | : gdb_tilde_expand (inferior_cwd.c_str ()).c_str()), |
bcb9251f | 507 | get_client_state ().disable_randomization, |
a9b34532 EZ |
508 | &si, /* start info */ |
509 | pi); /* proc info */ | |
aec18585 PA |
510 | |
511 | return ret; | |
512 | } | |
513 | ||
b80864fb | 514 | /* Start a new process. |
2090129c SDJ |
515 | PROGRAM is the program name. |
516 | PROGRAM_ARGS is the vector containing the inferior's args. | |
b80864fb DJ |
517 | Returns the new PID on success, -1 on failure. Registers the new |
518 | process with the process list. */ | |
15295543 TBA |
519 | int |
520 | win32_process_target::create_inferior (const char *program, | |
521 | const std::vector<char *> &program_args) | |
b80864fb | 522 | { |
6341380d | 523 | client_state &cs = get_client_state (); |
b80864fb | 524 | #ifndef USE_WIN32API |
d8d2a3ee | 525 | char real_path[PATH_MAX]; |
b80864fb DJ |
526 | char *orig_path, *new_path, *path_ptr; |
527 | #endif | |
b80864fb DJ |
528 | BOOL ret; |
529 | DWORD flags; | |
ed50f18f | 530 | PROCESS_INFORMATION pi; |
aec18585 | 531 | DWORD err; |
bea571eb | 532 | std::string str_program_args = construct_inferior_arguments (program_args); |
2090129c | 533 | char *args = (char *) str_program_args.c_str (); |
b80864fb | 534 | |
d97903b2 | 535 | /* win32_wait needs to know we're not attaching. */ |
20489cca | 536 | windows_process.attaching = 0; |
d97903b2 | 537 | |
b80864fb DJ |
538 | if (!program) |
539 | error ("No executable specified, specify executable to debug.\n"); | |
540 | ||
b80864fb DJ |
541 | flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; |
542 | ||
543 | #ifndef USE_WIN32API | |
544 | orig_path = NULL; | |
545 | path_ptr = getenv ("PATH"); | |
546 | if (path_ptr) | |
547 | { | |
81239425 | 548 | int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0); |
0ae534d2 JT |
549 | orig_path = (char *) alloca (strlen (path_ptr) + 1); |
550 | new_path = (char *) alloca (size); | |
b80864fb | 551 | strcpy (orig_path, path_ptr); |
81239425 | 552 | cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size); |
b80864fb | 553 | setenv ("PATH", new_path, 1); |
81239425 | 554 | } |
d8d2a3ee | 555 | cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX); |
b80864fb DJ |
556 | program = real_path; |
557 | #endif | |
558 | ||
a9b34532 | 559 | OUTMSG2 (("Command line is \"%s %s\"\n", program, args)); |
b80864fb | 560 | |
ed50f18f | 561 | #ifdef CREATE_NEW_PROCESS_GROUP |
b80864fb | 562 | flags |= CREATE_NEW_PROCESS_GROUP; |
ed50f18f | 563 | #endif |
b80864fb | 564 | |
aec18585 PA |
565 | ret = create_process (program, args, flags, &pi); |
566 | err = GetLastError (); | |
567 | if (!ret && err == ERROR_FILE_NOT_FOUND) | |
568 | { | |
c3de4d92 | 569 | char *exename = (char *) alloca (strlen (program) + 5); |
aec18585 PA |
570 | strcat (strcpy (exename, program), ".exe"); |
571 | ret = create_process (exename, args, flags, &pi); | |
572 | err = GetLastError (); | |
573 | } | |
b80864fb DJ |
574 | |
575 | #ifndef USE_WIN32API | |
576 | if (orig_path) | |
577 | setenv ("PATH", orig_path, 1); | |
578 | #endif | |
579 | ||
580 | if (!ret) | |
581 | { | |
a9b34532 | 582 | error ("Error creating process \"%s %s\", (error %d): %s\n", |
ed50f18f | 583 | program, args, (int) err, strwinerror (err)); |
b80864fb DJ |
584 | } |
585 | else | |
586 | { | |
a9b34532 | 587 | OUTMSG2 (("Process created: %s %s\n", program, (char *) args)); |
b80864fb DJ |
588 | } |
589 | ||
590 | CloseHandle (pi.hThread); | |
591 | ||
95954743 | 592 | do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0); |
b80864fb | 593 | |
7dbac825 JB |
594 | /* Wait till we are at 1st instruction in program, return new pid |
595 | (assuming success). */ | |
4eab18b5 | 596 | cs.last_ptid = wait (ptid_t (pi.dwProcessId), &cs.last_status, 0); |
7dbac825 | 597 | |
052793ad | 598 | /* Necessary for handle_v_kill. */ |
4eab18b5 | 599 | signal_pid = pi.dwProcessId; |
052793ad | 600 | |
4eab18b5 | 601 | return pi.dwProcessId; |
b80864fb DJ |
602 | } |
603 | ||
604 | /* Attach to a running process. | |
605 | PID is the process ID to attach to, specified by the user | |
606 | or a higher layer. */ | |
ef03dad8 TBA |
607 | int |
608 | win32_process_target::attach (unsigned long pid) | |
b80864fb | 609 | { |
5ca906e6 | 610 | HANDLE h; |
5ca906e6 | 611 | DWORD err; |
b80864fb | 612 | |
5ca906e6 PA |
613 | h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); |
614 | if (h != NULL) | |
1d5315fe | 615 | { |
5ca906e6 PA |
616 | if (DebugActiveProcess (pid)) |
617 | { | |
de071872 | 618 | DebugSetProcessKillOnExit (FALSE); |
5ca906e6 | 619 | |
d97903b2 | 620 | /* win32_wait needs to know we're attaching. */ |
20489cca | 621 | windows_process.attaching = 1; |
95954743 | 622 | do_initial_child_stuff (h, pid, 1); |
5ca906e6 PA |
623 | return 0; |
624 | } | |
625 | ||
626 | CloseHandle (h); | |
b80864fb DJ |
627 | } |
628 | ||
5ca906e6 PA |
629 | err = GetLastError (); |
630 | error ("Attach to process failed (error %d): %s\n", | |
631 | (int) err, strwinerror (err)); | |
b80864fb DJ |
632 | } |
633 | ||
d41b524f TT |
634 | /* See nat/windows-nat.h. */ |
635 | ||
636 | int | |
20489cca | 637 | gdbserver_windows_process::handle_output_debug_string |
0578e87f | 638 | (struct target_waitstatus *ourstatus) |
bce7165d PA |
639 | { |
640 | #define READ_BUFFER_LEN 1024 | |
641 | CORE_ADDR addr; | |
642 | char s[READ_BUFFER_LEN + 1] = { 0 }; | |
643 | DWORD nbytes = current_event.u.DebugString.nDebugStringLength; | |
644 | ||
645 | if (nbytes == 0) | |
d41b524f | 646 | return 0; |
bce7165d PA |
647 | |
648 | if (nbytes > READ_BUFFER_LEN) | |
649 | nbytes = READ_BUFFER_LEN; | |
650 | ||
651 | addr = (CORE_ADDR) (size_t) current_event.u.DebugString.lpDebugStringData; | |
652 | ||
653 | if (current_event.u.DebugString.fUnicode) | |
654 | { | |
655 | /* The event tells us how many bytes, not chars, even | |
1b3f6016 | 656 | in Unicode. */ |
bce7165d PA |
657 | WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 }; |
658 | if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0) | |
d41b524f | 659 | return 0; |
bce7165d PA |
660 | wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR)); |
661 | } | |
662 | else | |
663 | { | |
664 | if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0) | |
d41b524f | 665 | return 0; |
bce7165d PA |
666 | } |
667 | ||
61012eef | 668 | if (!startswith (s, "cYg")) |
45e2715e PA |
669 | { |
670 | if (!server_waiting) | |
671 | { | |
672 | OUTMSG2(("%s", s)); | |
d41b524f | 673 | return 0; |
45e2715e PA |
674 | } |
675 | ||
676 | monitor_output (s); | |
677 | } | |
bce7165d | 678 | #undef READ_BUFFER_LEN |
d41b524f TT |
679 | |
680 | return 0; | |
bce7165d PA |
681 | } |
682 | ||
5ac588cf PA |
683 | static void |
684 | win32_clear_inferiors (void) | |
685 | { | |
20489cca | 686 | if (windows_process.open_process_used) |
6479bf85 | 687 | { |
0578e87f | 688 | CloseHandle (windows_process.handle); |
20489cca | 689 | windows_process.open_process_used = false; |
6479bf85 | 690 | } |
5ac588cf | 691 | |
f0045347 | 692 | for_each_thread (delete_thread_info); |
0578e87f | 693 | windows_process.siginfo_er.ExceptionCode = 0; |
5ac588cf PA |
694 | clear_inferiors (); |
695 | } | |
696 | ||
a780ef4f PA |
697 | /* Implementation of target_ops::kill. */ |
698 | ||
c6885a57 TBA |
699 | int |
700 | win32_process_target::kill (process_info *process) | |
b80864fb | 701 | { |
0578e87f | 702 | TerminateProcess (windows_process.handle, 0); |
b80864fb DJ |
703 | for (;;) |
704 | { | |
705 | if (!child_continue (DBG_CONTINUE, -1)) | |
706 | break; | |
0578e87f | 707 | if (!wait_for_debug_event (&windows_process.current_event, INFINITE)) |
b80864fb | 708 | break; |
0578e87f TT |
709 | if (windows_process.current_event.dwDebugEventCode |
710 | == EXIT_PROCESS_DEBUG_EVENT) | |
b80864fb | 711 | break; |
0578e87f TT |
712 | else if (windows_process.current_event.dwDebugEventCode |
713 | == OUTPUT_DEBUG_STRING_EVENT) | |
714 | windows_process.handle_output_debug_string (nullptr); | |
b80864fb | 715 | } |
ed50f18f | 716 | |
5ac588cf | 717 | win32_clear_inferiors (); |
95954743 | 718 | |
95954743 PA |
719 | remove_process (process); |
720 | return 0; | |
b80864fb DJ |
721 | } |
722 | ||
ef2ddb33 PA |
723 | /* Implementation of target_ops::detach. */ |
724 | ||
9061c9cf TBA |
725 | int |
726 | win32_process_target::detach (process_info *process) | |
b80864fb | 727 | { |
de071872 TT |
728 | struct thread_resume resume; |
729 | resume.thread = minus_one_ptid; | |
730 | resume.kind = resume_continue; | |
731 | resume.sig = 0; | |
732 | this->resume (&resume, 1); | |
444d6139 | 733 | |
4eab18b5 | 734 | if (!DebugActiveProcessStop (process->pid)) |
5ac588cf PA |
735 | return -1; |
736 | ||
444d6139 | 737 | DebugSetProcessKillOnExit (FALSE); |
95954743 | 738 | remove_process (process); |
444d6139 | 739 | |
5ac588cf | 740 | win32_clear_inferiors (); |
444d6139 PA |
741 | return 0; |
742 | } | |
743 | ||
8adb37b9 TBA |
744 | void |
745 | win32_process_target::mourn (struct process_info *process) | |
505106cd PA |
746 | { |
747 | remove_process (process); | |
748 | } | |
749 | ||
ef2ddb33 PA |
750 | /* Implementation of target_ops::join. */ |
751 | ||
95a49a39 TBA |
752 | void |
753 | win32_process_target::join (int pid) | |
444d6139 | 754 | { |
d105de22 | 755 | HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); |
5ac588cf PA |
756 | if (h != NULL) |
757 | { | |
758 | WaitForSingleObject (h, INFINITE); | |
759 | CloseHandle (h); | |
760 | } | |
b80864fb DJ |
761 | } |
762 | ||
13d3d99b TBA |
763 | /* Return true iff the thread with thread ID TID is alive. */ |
764 | bool | |
765 | win32_process_target::thread_alive (ptid_t ptid) | |
b80864fb | 766 | { |
b80864fb DJ |
767 | /* Our thread list is reliable; don't bother to poll target |
768 | threads. */ | |
8dc7b443 | 769 | return find_thread_ptid (ptid) != NULL; |
b80864fb DJ |
770 | } |
771 | ||
772 | /* Resume the inferior process. RESUME_INFO describes how we want | |
773 | to resume. */ | |
0e4d7e35 TBA |
774 | void |
775 | win32_process_target::resume (thread_resume *resume_info, size_t n) | |
b80864fb DJ |
776 | { |
777 | DWORD tid; | |
2ea28649 | 778 | enum gdb_signal sig; |
b80864fb | 779 | int step; |
e56f8ccb | 780 | windows_thread_info *th; |
b80864fb | 781 | DWORD continue_status = DBG_CONTINUE; |
95954743 | 782 | ptid_t ptid; |
b80864fb DJ |
783 | |
784 | /* This handles the very limited set of resume packets that GDB can | |
785 | currently produce. */ | |
786 | ||
d7e15655 | 787 | if (n == 1 && resume_info[0].thread == minus_one_ptid) |
b80864fb | 788 | tid = -1; |
2bd7c093 | 789 | else if (n > 1) |
b80864fb DJ |
790 | tid = -1; |
791 | else | |
792 | /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make | |
793 | the Windows resume code do the right thing for thread switching. */ | |
0578e87f | 794 | tid = windows_process.current_event.dwThreadId; |
b80864fb | 795 | |
d7e15655 | 796 | if (resume_info[0].thread != minus_one_ptid) |
b80864fb | 797 | { |
ce7715e2 | 798 | sig = gdb_signal_from_host (resume_info[0].sig); |
bd99dc85 | 799 | step = resume_info[0].kind == resume_step; |
b80864fb DJ |
800 | } |
801 | else | |
802 | { | |
ce7715e2 | 803 | sig = GDB_SIGNAL_0; |
b80864fb DJ |
804 | step = 0; |
805 | } | |
806 | ||
a493e3e2 | 807 | if (sig != GDB_SIGNAL_0) |
b80864fb | 808 | { |
0578e87f TT |
809 | if (windows_process.current_event.dwDebugEventCode |
810 | != EXCEPTION_DEBUG_EVENT) | |
b80864fb | 811 | { |
ce7715e2 PA |
812 | OUTMSG (("Cannot continue with signal %s here.\n", |
813 | gdb_signal_to_string (sig))); | |
b80864fb | 814 | } |
0578e87f | 815 | else if (sig == windows_process.last_sig) |
b80864fb DJ |
816 | continue_status = DBG_EXCEPTION_NOT_HANDLED; |
817 | else | |
ce7715e2 | 818 | OUTMSG (("Can only continue with received signal %s.\n", |
0578e87f | 819 | gdb_signal_to_string (windows_process.last_sig))); |
b80864fb DJ |
820 | } |
821 | ||
0578e87f | 822 | windows_process.last_sig = GDB_SIGNAL_0; |
b80864fb DJ |
823 | |
824 | /* Get context for the currently selected thread. */ | |
0578e87f TT |
825 | ptid = debug_event_ptid (&windows_process.current_event); |
826 | th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT); | |
b80864fb DJ |
827 | if (th) |
828 | { | |
a2abc7de PA |
829 | win32_prepare_to_resume (th); |
830 | ||
7d186bc0 HD |
831 | DWORD *context_flags; |
832 | #ifdef __x86_64__ | |
801eb70f | 833 | if (windows_process.wow64_process) |
7d186bc0 HD |
834 | context_flags = &th->wow64_context.ContextFlags; |
835 | else | |
836 | #endif | |
837 | context_flags = &th->context.ContextFlags; | |
838 | if (*context_flags) | |
b80864fb | 839 | { |
b80864fb DJ |
840 | /* Move register values from the inferior into the thread |
841 | context structure. */ | |
842 | regcache_invalidate (); | |
843 | ||
844 | if (step) | |
ed50f18f PA |
845 | { |
846 | if (the_low_target.single_step != NULL) | |
847 | (*the_low_target.single_step) (th); | |
848 | else | |
849 | error ("Single stepping is not supported " | |
850 | "in this configuration.\n"); | |
851 | } | |
34b34921 | 852 | |
9c6c8194 | 853 | win32_set_thread_context (th); |
7d186bc0 | 854 | *context_flags = 0; |
b80864fb DJ |
855 | } |
856 | } | |
857 | ||
858 | /* Allow continuing with the same signal that interrupted us. | |
859 | Otherwise complain. */ | |
860 | ||
861 | child_continue (continue_status, tid); | |
862 | } | |
863 | ||
e228ef97 TT |
864 | /* See nat/windows-nat.h. */ |
865 | ||
866 | void | |
20489cca | 867 | gdbserver_windows_process::handle_load_dll (const char *name, LPVOID base) |
255e7678 | 868 | { |
e228ef97 TT |
869 | CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) base; |
870 | ||
255e7678 DJ |
871 | char buf[MAX_PATH + 1]; |
872 | char buf2[MAX_PATH + 1]; | |
873 | ||
255e7678 DJ |
874 | WIN32_FIND_DATAA w32_fd; |
875 | HANDLE h = FindFirstFileA (name, &w32_fd); | |
255e7678 | 876 | |
850a0f76 JB |
877 | /* The symbols in a dll are offset by 0x1000, which is the |
878 | offset from 0 of the first byte in an image - because | |
879 | of the file header and the section alignment. */ | |
880 | load_addr += 0x1000; | |
881 | ||
255e7678 DJ |
882 | if (h == INVALID_HANDLE_VALUE) |
883 | strcpy (buf, name); | |
884 | else | |
885 | { | |
886 | FindClose (h); | |
887 | strcpy (buf, name); | |
255e7678 DJ |
888 | { |
889 | char cwd[MAX_PATH + 1]; | |
890 | char *p; | |
891 | if (GetCurrentDirectoryA (MAX_PATH + 1, cwd)) | |
892 | { | |
893 | p = strrchr (buf, '\\'); | |
894 | if (p) | |
895 | p[1] = '\0'; | |
896 | SetCurrentDirectoryA (buf); | |
897 | GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p); | |
898 | SetCurrentDirectoryA (cwd); | |
899 | } | |
900 | } | |
255e7678 DJ |
901 | } |
902 | ||
cf6e3471 PA |
903 | if (strcasecmp (buf, "ntdll.dll") == 0) |
904 | { | |
905 | GetSystemDirectoryA (buf, sizeof (buf)); | |
906 | strcat (buf, "\\ntdll.dll"); | |
907 | } | |
cf6e3471 | 908 | |
255e7678 | 909 | #ifdef __CYGWIN__ |
81239425 | 910 | cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2)); |
255e7678 DJ |
911 | #else |
912 | strcpy (buf2, buf); | |
913 | #endif | |
914 | ||
915 | loaded_dll (buf2, load_addr); | |
916 | } | |
917 | ||
a816ba18 | 918 | /* See nat/windows-nat.h. */ |
f25b3fc3 | 919 | |
a816ba18 | 920 | void |
20489cca | 921 | gdbserver_windows_process::handle_unload_dll () |
255e7678 DJ |
922 | { |
923 | CORE_ADDR load_addr = | |
e8f0053d | 924 | (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; |
850a0f76 JB |
925 | |
926 | /* The symbols in a dll are offset by 0x1000, which is the | |
927 | offset from 0 of the first byte in an image - because | |
928 | of the file header and the section alignment. */ | |
255e7678 DJ |
929 | load_addr += 0x1000; |
930 | unloaded_dll (NULL, load_addr); | |
931 | } | |
932 | ||
34b34921 | 933 | static void |
9c80ecd6 | 934 | suspend_one_thread (thread_info *thread) |
4d5d1aaa | 935 | { |
e56f8ccb | 936 | windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); |
4d5d1aaa | 937 | |
98a03287 | 938 | th->suspend (); |
4d5d1aaa PA |
939 | } |
940 | ||
941 | static void | |
942 | fake_breakpoint_event (void) | |
b80864fb | 943 | { |
4d5d1aaa | 944 | OUTMSG2(("fake_breakpoint_event\n")); |
b80864fb | 945 | |
20489cca | 946 | windows_process.faked_breakpoint = 1; |
4d5d1aaa | 947 | |
0578e87f TT |
948 | memset (&windows_process.current_event, 0, |
949 | sizeof (windows_process.current_event)); | |
950 | windows_process.current_event.dwThreadId = windows_process.main_thread_id; | |
951 | windows_process.current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT; | |
952 | windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode | |
4d5d1aaa PA |
953 | = EXCEPTION_BREAKPOINT; |
954 | ||
f0045347 | 955 | for_each_thread (suspend_one_thread); |
4d5d1aaa PA |
956 | } |
957 | ||
8d30e395 TT |
958 | /* See nat/windows-nat.h. */ |
959 | ||
a010605f | 960 | bool |
20489cca | 961 | gdbserver_windows_process::handle_access_violation |
0578e87f | 962 | (const EXCEPTION_RECORD *rec) |
a010605f TT |
963 | { |
964 | return false; | |
965 | } | |
966 | ||
523d4f80 TT |
967 | /* A helper function that will, if needed, set |
968 | 'stopped_at_software_breakpoint' on the thread and adjust the | |
969 | PC. */ | |
970 | ||
971 | static void | |
972 | maybe_adjust_pc () | |
973 | { | |
974 | struct regcache *regcache = get_thread_regcache (current_thread, 1); | |
975 | child_fetch_inferior_registers (regcache, -1); | |
976 | ||
0578e87f TT |
977 | windows_thread_info *th |
978 | = windows_process.thread_rec (current_thread_ptid (), | |
979 | DONT_INVALIDATE_CONTEXT); | |
523d4f80 TT |
980 | th->stopped_at_software_breakpoint = false; |
981 | ||
0578e87f TT |
982 | if (windows_process.current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT |
983 | && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode | |
7d186bc0 | 984 | == EXCEPTION_BREAKPOINT) |
0578e87f | 985 | || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode |
7d186bc0 | 986 | == STATUS_WX86_BREAKPOINT)) |
20489cca | 987 | && windows_process.child_initialization_done) |
523d4f80 TT |
988 | { |
989 | th->stopped_at_software_breakpoint = true; | |
990 | CORE_ADDR pc = regcache_read_pc (regcache); | |
991 | CORE_ADDR sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break; | |
992 | regcache_write_pc (regcache, sw_breakpoint_pc); | |
993 | } | |
994 | } | |
995 | ||
4d5d1aaa PA |
996 | /* Get the next event from the child. */ |
997 | ||
998 | static int | |
8d30e395 TT |
999 | get_child_debug_event (DWORD *continue_status, |
1000 | struct target_waitstatus *ourstatus) | |
4d5d1aaa | 1001 | { |
95954743 PA |
1002 | ptid_t ptid; |
1003 | ||
0578e87f | 1004 | windows_process.last_sig = GDB_SIGNAL_0; |
183be222 | 1005 | ourstatus->set_spurious (); |
8d30e395 | 1006 | *continue_status = DBG_CONTINUE; |
b80864fb | 1007 | |
4d5d1aaa PA |
1008 | /* Check if GDB sent us an interrupt request. */ |
1009 | check_remote_input_interrupt_request (); | |
1010 | ||
0578e87f TT |
1011 | DEBUG_EVENT *current_event = &windows_process.current_event; |
1012 | ||
20489cca | 1013 | if (windows_process.soft_interrupt_requested) |
4d5d1aaa | 1014 | { |
20489cca | 1015 | windows_process.soft_interrupt_requested = 0; |
4d5d1aaa PA |
1016 | fake_breakpoint_event (); |
1017 | goto gotevent; | |
1018 | } | |
1019 | ||
20489cca | 1020 | windows_process.attaching = 0; |
84b300de | 1021 | { |
0578e87f TT |
1022 | gdb::optional<pending_stop> stop |
1023 | = windows_process.fetch_pending_stop (debug_threads); | |
84b300de SM |
1024 | if (stop.has_value ()) |
1025 | { | |
1026 | *ourstatus = stop->status; | |
0578e87f TT |
1027 | windows_process.current_event = stop->event; |
1028 | ptid = debug_event_ptid (&windows_process.current_event); | |
24583e45 | 1029 | switch_to_thread (find_thread_ptid (ptid)); |
84b300de SM |
1030 | return 1; |
1031 | } | |
360ad8b3 | 1032 | |
84b300de SM |
1033 | /* Keep the wait time low enough for comfortable remote |
1034 | interruption, but high enough so gdbserver doesn't become a | |
1035 | bottleneck. */ | |
0578e87f | 1036 | if (!wait_for_debug_event (&windows_process.current_event, 250)) |
84b300de SM |
1037 | { |
1038 | DWORD e = GetLastError(); | |
912cf4ba | 1039 | |
84b300de SM |
1040 | if (e == ERROR_PIPE_NOT_CONNECTED) |
1041 | { | |
33b5899f | 1042 | /* This will happen if the loader fails to successfully |
84b300de SM |
1043 | load the application, e.g., if the main executable |
1044 | tries to pull in a non-existing export from a | |
1045 | DLL. */ | |
183be222 | 1046 | ourstatus->set_exited (1); |
84b300de SM |
1047 | return 1; |
1048 | } | |
912cf4ba | 1049 | |
84b300de SM |
1050 | return 0; |
1051 | } | |
1052 | } | |
4d5d1aaa PA |
1053 | |
1054 | gotevent: | |
b80864fb | 1055 | |
0578e87f | 1056 | switch (current_event->dwDebugEventCode) |
b80864fb DJ |
1057 | { |
1058 | case CREATE_THREAD_DEBUG_EVENT: | |
1059 | OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT " | |
dfe07582 | 1060 | "for pid=%u tid=%x)\n", |
0578e87f TT |
1061 | (unsigned) current_event->dwProcessId, |
1062 | (unsigned) current_event->dwThreadId)); | |
b80864fb DJ |
1063 | |
1064 | /* Record the existence of this thread. */ | |
0578e87f TT |
1065 | child_add_thread (current_event->dwProcessId, |
1066 | current_event->dwThreadId, | |
1067 | current_event->u.CreateThread.hThread, | |
1068 | current_event->u.CreateThread.lpThreadLocalBase); | |
b80864fb DJ |
1069 | break; |
1070 | ||
1071 | case EXIT_THREAD_DEBUG_EVENT: | |
1072 | OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT " | |
dfe07582 | 1073 | "for pid=%u tid=%x\n", |
0578e87f TT |
1074 | (unsigned) current_event->dwProcessId, |
1075 | (unsigned) current_event->dwThreadId)); | |
1076 | child_delete_thread (current_event->dwProcessId, | |
1077 | current_event->dwThreadId); | |
aeeb81d1 | 1078 | |
24583e45 | 1079 | switch_to_thread (get_first_thread ()); |
aeeb81d1 | 1080 | return 1; |
b80864fb DJ |
1081 | |
1082 | case CREATE_PROCESS_DEBUG_EVENT: | |
1083 | OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT " | |
dfe07582 | 1084 | "for pid=%u tid=%x\n", |
0578e87f TT |
1085 | (unsigned) current_event->dwProcessId, |
1086 | (unsigned) current_event->dwThreadId)); | |
1087 | CloseHandle (current_event->u.CreateProcessInfo.hFile); | |
b80864fb | 1088 | |
20489cca | 1089 | if (windows_process.open_process_used) |
6479bf85 | 1090 | { |
0578e87f | 1091 | CloseHandle (windows_process.handle); |
20489cca | 1092 | windows_process.open_process_used = false; |
6479bf85 HD |
1093 | } |
1094 | ||
0578e87f TT |
1095 | windows_process.handle = current_event->u.CreateProcessInfo.hProcess; |
1096 | windows_process.main_thread_id = current_event->dwThreadId; | |
b80864fb | 1097 | |
b80864fb | 1098 | /* Add the main thread. */ |
0578e87f TT |
1099 | child_add_thread (current_event->dwProcessId, |
1100 | windows_process.main_thread_id, | |
1101 | current_event->u.CreateProcessInfo.hThread, | |
1102 | current_event->u.CreateProcessInfo.lpThreadLocalBase); | |
b80864fb DJ |
1103 | break; |
1104 | ||
1105 | case EXIT_PROCESS_DEBUG_EVENT: | |
1106 | OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT " | |
dfe07582 | 1107 | "for pid=%u tid=%x\n", |
0578e87f TT |
1108 | (unsigned) current_event->dwProcessId, |
1109 | (unsigned) current_event->dwThreadId)); | |
559e7e50 | 1110 | { |
0578e87f | 1111 | DWORD exit_status = current_event->u.ExitProcess.dwExitCode; |
559e7e50 EZ |
1112 | /* If the exit status looks like a fatal exception, but we |
1113 | don't recognize the exception's code, make the original | |
1114 | exit status value available, to avoid losing information. */ | |
1115 | int exit_signal | |
1116 | = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1; | |
1117 | if (exit_signal == -1) | |
183be222 | 1118 | ourstatus->set_exited (exit_status); |
559e7e50 | 1119 | else |
183be222 | 1120 | ourstatus->set_signalled (gdb_signal_from_host (exit_signal)); |
559e7e50 | 1121 | } |
0578e87f | 1122 | child_continue (DBG_CONTINUE, windows_process.desired_stop_thread_id); |
b80864fb DJ |
1123 | break; |
1124 | ||
1125 | case LOAD_DLL_DEBUG_EVENT: | |
1126 | OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT " | |
dfe07582 | 1127 | "for pid=%u tid=%x\n", |
0578e87f TT |
1128 | (unsigned) current_event->dwProcessId, |
1129 | (unsigned) current_event->dwThreadId)); | |
1130 | CloseHandle (current_event->u.LoadDll.hFile); | |
20489cca | 1131 | if (! windows_process.child_initialization_done) |
f25b3fc3 | 1132 | break; |
0578e87f | 1133 | windows_process.dll_loaded_event (); |
b80864fb | 1134 | |
183be222 | 1135 | ourstatus->set_loaded (); |
b80864fb DJ |
1136 | break; |
1137 | ||
1138 | case UNLOAD_DLL_DEBUG_EVENT: | |
1139 | OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT " | |
dfe07582 | 1140 | "for pid=%u tid=%x\n", |
0578e87f TT |
1141 | (unsigned) current_event->dwProcessId, |
1142 | (unsigned) current_event->dwThreadId)); | |
20489cca | 1143 | if (! windows_process.child_initialization_done) |
f25b3fc3 | 1144 | break; |
0578e87f | 1145 | windows_process.handle_unload_dll (); |
183be222 | 1146 | ourstatus->set_loaded (); |
b80864fb DJ |
1147 | break; |
1148 | ||
1149 | case EXCEPTION_DEBUG_EVENT: | |
1150 | OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " | |
dfe07582 | 1151 | "for pid=%u tid=%x\n", |
0578e87f TT |
1152 | (unsigned) current_event->dwProcessId, |
1153 | (unsigned) current_event->dwThreadId)); | |
1154 | if (windows_process.handle_exception (ourstatus, debug_threads) | |
8d30e395 TT |
1155 | == HANDLE_EXCEPTION_UNHANDLED) |
1156 | *continue_status = DBG_EXCEPTION_NOT_HANDLED; | |
b80864fb DJ |
1157 | break; |
1158 | ||
1159 | case OUTPUT_DEBUG_STRING_EVENT: | |
1160 | /* A message from the kernel (or Cygwin). */ | |
1161 | OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT " | |
dfe07582 | 1162 | "for pid=%u tid=%x\n", |
0578e87f TT |
1163 | (unsigned) current_event->dwProcessId, |
1164 | (unsigned) current_event->dwThreadId)); | |
1165 | windows_process.handle_output_debug_string (nullptr); | |
b80864fb DJ |
1166 | break; |
1167 | ||
1168 | default: | |
1169 | OUTMSG2 (("gdbserver: kernel event unknown " | |
dfe07582 | 1170 | "for pid=%u tid=%x code=%x\n", |
0578e87f TT |
1171 | (unsigned) current_event->dwProcessId, |
1172 | (unsigned) current_event->dwThreadId, | |
1173 | (unsigned) current_event->dwDebugEventCode)); | |
b80864fb DJ |
1174 | break; |
1175 | } | |
1176 | ||
0578e87f | 1177 | ptid = debug_event_ptid (&windows_process.current_event); |
360ad8b3 | 1178 | |
0578e87f TT |
1179 | if (windows_process.desired_stop_thread_id != -1 |
1180 | && windows_process.desired_stop_thread_id != ptid.lwp ()) | |
360ad8b3 TT |
1181 | { |
1182 | /* Pending stop. See the comment by the definition of | |
1183 | "pending_stops" for details on why this is needed. */ | |
1184 | OUTMSG2 (("get_windows_debug_event - " | |
e2275c6e | 1185 | "unexpected stop in 0x%lx (expecting 0x%x)\n", |
0578e87f | 1186 | ptid.lwp (), windows_process.desired_stop_thread_id)); |
360ad8b3 | 1187 | maybe_adjust_pc (); |
0578e87f TT |
1188 | windows_process.pending_stops.push_back |
1189 | ({(DWORD) ptid.lwp (), *ourstatus, *current_event}); | |
183be222 | 1190 | ourstatus->set_spurious (); |
360ad8b3 TT |
1191 | } |
1192 | else | |
24583e45 | 1193 | switch_to_thread (find_thread_ptid (ptid)); |
360ad8b3 | 1194 | |
4d5d1aaa | 1195 | return 1; |
b80864fb DJ |
1196 | } |
1197 | ||
1198 | /* Wait for the inferior process to change state. | |
1199 | STATUS will be filled in with a response code to send to GDB. | |
1200 | Returns the signal which caused the process to stop. */ | |
6532e7e3 TBA |
1201 | ptid_t |
1202 | win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus, | |
b60cea74 | 1203 | target_wait_flags options) |
b80864fb | 1204 | { |
20489cca | 1205 | if (windows_process.cached_status.kind () != TARGET_WAITKIND_IGNORE) |
4210d83e PA |
1206 | { |
1207 | /* The core always does a wait after creating the inferior, and | |
1208 | do_initial_child_stuff already ran the inferior to the | |
1209 | initial breakpoint (or an exit, if creating the process | |
1210 | fails). Report it now. */ | |
20489cca TT |
1211 | *ourstatus = windows_process.cached_status; |
1212 | windows_process.cached_status.set_ignore (); | |
0578e87f | 1213 | return debug_event_ptid (&windows_process.current_event); |
4210d83e PA |
1214 | } |
1215 | ||
b80864fb DJ |
1216 | while (1) |
1217 | { | |
8d30e395 TT |
1218 | DWORD continue_status; |
1219 | if (!get_child_debug_event (&continue_status, ourstatus)) | |
4d5d1aaa | 1220 | continue; |
b80864fb | 1221 | |
183be222 | 1222 | switch (ourstatus->kind ()) |
b80864fb | 1223 | { |
34b34921 | 1224 | case TARGET_WAITKIND_EXITED: |
b80864fb | 1225 | OUTMSG2 (("Child exited with retcode = %x\n", |
183be222 | 1226 | ourstatus->exit_status ())); |
5ac588cf | 1227 | win32_clear_inferiors (); |
0578e87f | 1228 | return ptid_t (windows_process.current_event.dwProcessId); |
34b34921 | 1229 | case TARGET_WAITKIND_STOPPED: |
559e7e50 | 1230 | case TARGET_WAITKIND_SIGNALLED: |
1b3f6016 | 1231 | case TARGET_WAITKIND_LOADED: |
523d4f80 TT |
1232 | { |
1233 | OUTMSG2 (("Child Stopped with signal = %d \n", | |
183be222 | 1234 | ourstatus->sig ())); |
523d4f80 | 1235 | maybe_adjust_pc (); |
0578e87f | 1236 | return debug_event_ptid (&windows_process.current_event); |
523d4f80 | 1237 | } |
1b3f6016 | 1238 | default: |
183be222 SM |
1239 | OUTMSG (("Ignoring unknown internal event, %d\n", |
1240 | ourstatus->kind ())); | |
1b3f6016 PA |
1241 | /* fall-through */ |
1242 | case TARGET_WAITKIND_SPURIOUS: | |
34b34921 | 1243 | /* do nothing, just continue */ |
0578e87f TT |
1244 | child_continue (continue_status, |
1245 | windows_process.desired_stop_thread_id); | |
34b34921 | 1246 | break; |
b80864fb | 1247 | } |
b80864fb DJ |
1248 | } |
1249 | } | |
1250 | ||
1251 | /* Fetch registers from the inferior process. | |
1252 | If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */ | |
a5a4d4cd TBA |
1253 | void |
1254 | win32_process_target::fetch_registers (regcache *regcache, int regno) | |
b80864fb | 1255 | { |
442ea881 | 1256 | child_fetch_inferior_registers (regcache, regno); |
b80864fb DJ |
1257 | } |
1258 | ||
1259 | /* Store registers to the inferior process. | |
1260 | If REGNO is -1, store all registers; otherwise, store at least REGNO. */ | |
a5a4d4cd TBA |
1261 | void |
1262 | win32_process_target::store_registers (regcache *regcache, int regno) | |
b80864fb | 1263 | { |
442ea881 | 1264 | child_store_inferior_registers (regcache, regno); |
b80864fb DJ |
1265 | } |
1266 | ||
1267 | /* Read memory from the inferior process. This should generally be | |
1268 | called through read_inferior_memory, which handles breakpoint shadowing. | |
1269 | Read LEN bytes at MEMADDR into a buffer at MYADDR. */ | |
e2558df3 TBA |
1270 | int |
1271 | win32_process_target::read_memory (CORE_ADDR memaddr, unsigned char *myaddr, | |
1272 | int len) | |
b80864fb | 1273 | { |
ed50f18f | 1274 | return child_xfer_memory (memaddr, (char *) myaddr, len, 0, 0) != len; |
b80864fb DJ |
1275 | } |
1276 | ||
1277 | /* Write memory to the inferior process. This should generally be | |
1278 | called through write_inferior_memory, which handles breakpoint shadowing. | |
1279 | Write LEN bytes from the buffer at MYADDR to MEMADDR. | |
1280 | Returns 0 on success and errno on failure. */ | |
e2558df3 TBA |
1281 | int |
1282 | win32_process_target::write_memory (CORE_ADDR memaddr, | |
1283 | const unsigned char *myaddr, int len) | |
b80864fb DJ |
1284 | { |
1285 | return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len; | |
1286 | } | |
1287 | ||
7390519e | 1288 | /* Send an interrupt request to the inferior process. */ |
eb497a2a TBA |
1289 | void |
1290 | win32_process_target::request_interrupt () | |
7390519e | 1291 | { |
4eab18b5 | 1292 | if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, signal_pid)) |
7390519e PA |
1293 | return; |
1294 | ||
1295 | /* GenerateConsoleCtrlEvent can fail if process id being debugged is | |
1296 | not a process group id. | |
1297 | Fallback to XP/Vista 'DebugBreakProcess', which generates a | |
1298 | breakpoint exception in the interior process. */ | |
1299 | ||
0578e87f | 1300 | if (DebugBreakProcess (windows_process.handle)) |
7390519e PA |
1301 | return; |
1302 | ||
4d5d1aaa | 1303 | /* Last resort, suspend all threads manually. */ |
20489cca | 1304 | windows_process.soft_interrupt_requested = 1; |
7390519e PA |
1305 | } |
1306 | ||
22aa6223 TBA |
1307 | bool |
1308 | win32_process_target::supports_hardware_single_step () | |
1309 | { | |
1310 | return true; | |
1311 | } | |
1312 | ||
d7abedf7 TBA |
1313 | bool |
1314 | win32_process_target::supports_qxfer_siginfo () | |
1315 | { | |
1316 | return true; | |
1317 | } | |
1318 | ||
7928d571 HD |
1319 | /* Write Windows signal info. */ |
1320 | ||
d7abedf7 TBA |
1321 | int |
1322 | win32_process_target::qxfer_siginfo (const char *annex, | |
1323 | unsigned char *readbuf, | |
1324 | unsigned const char *writebuf, | |
1325 | CORE_ADDR offset, int len) | |
7928d571 | 1326 | { |
0578e87f | 1327 | if (windows_process.siginfo_er.ExceptionCode == 0) |
7928d571 HD |
1328 | return -1; |
1329 | ||
1330 | if (readbuf == nullptr) | |
1331 | return -1; | |
1332 | ||
0578e87f TT |
1333 | char *buf = (char *) &windows_process.siginfo_er; |
1334 | size_t bufsize = sizeof (windows_process.siginfo_er); | |
7d186bc0 HD |
1335 | |
1336 | #ifdef __x86_64__ | |
1337 | EXCEPTION_RECORD32 er32; | |
801eb70f | 1338 | if (windows_process.wow64_process) |
7d186bc0 HD |
1339 | { |
1340 | buf = (char *) &er32; | |
1341 | bufsize = sizeof (er32); | |
1342 | ||
801eb70f TT |
1343 | er32.ExceptionCode = windows_process.siginfo_er.ExceptionCode; |
1344 | er32.ExceptionFlags = windows_process.siginfo_er.ExceptionFlags; | |
1345 | er32.ExceptionRecord | |
1346 | = (uintptr_t) windows_process.siginfo_er.ExceptionRecord; | |
1347 | er32.ExceptionAddress | |
1348 | = (uintptr_t) windows_process.siginfo_er.ExceptionAddress; | |
1349 | er32.NumberParameters = windows_process.siginfo_er.NumberParameters; | |
7d186bc0 HD |
1350 | int i; |
1351 | for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++) | |
801eb70f TT |
1352 | er32.ExceptionInformation[i] |
1353 | = windows_process.siginfo_er.ExceptionInformation[i]; | |
7d186bc0 HD |
1354 | } |
1355 | #endif | |
1356 | ||
1357 | if (offset > bufsize) | |
7928d571 HD |
1358 | return -1; |
1359 | ||
7d186bc0 HD |
1360 | if (offset + len > bufsize) |
1361 | len = bufsize - offset; | |
7928d571 | 1362 | |
7d186bc0 | 1363 | memcpy (readbuf, buf + offset, len); |
7928d571 HD |
1364 | |
1365 | return len; | |
1366 | } | |
1367 | ||
4e2e869c TBA |
1368 | bool |
1369 | win32_process_target::supports_get_tib_address () | |
1370 | { | |
1371 | return true; | |
1372 | } | |
1373 | ||
711e434b PM |
1374 | /* Write Windows OS Thread Information Block address. */ |
1375 | ||
4e2e869c TBA |
1376 | int |
1377 | win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr) | |
711e434b | 1378 | { |
e56f8ccb | 1379 | windows_thread_info *th; |
0578e87f | 1380 | th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT); |
711e434b PM |
1381 | if (th == NULL) |
1382 | return 0; | |
1383 | if (addr != NULL) | |
1384 | *addr = th->thread_local_base; | |
1385 | return 1; | |
1386 | } | |
1387 | ||
fb78e89c AT |
1388 | /* Implementation of the target_ops method "sw_breakpoint_from_kind". */ |
1389 | ||
d367006f TBA |
1390 | const gdb_byte * |
1391 | win32_process_target::sw_breakpoint_from_kind (int kind, int *size) | |
fb78e89c AT |
1392 | { |
1393 | *size = the_low_target.breakpoint_len; | |
1394 | return the_low_target.breakpoint; | |
1395 | } | |
1396 | ||
523d4f80 TT |
1397 | bool |
1398 | win32_process_target::stopped_by_sw_breakpoint () | |
1399 | { | |
0578e87f TT |
1400 | windows_thread_info *th |
1401 | = windows_process.thread_rec (current_thread_ptid (), | |
1402 | DONT_INVALIDATE_CONTEXT); | |
523d4f80 TT |
1403 | return th == nullptr ? false : th->stopped_at_software_breakpoint; |
1404 | } | |
1405 | ||
1406 | bool | |
1407 | win32_process_target::supports_stopped_by_sw_breakpoint () | |
1408 | { | |
1409 | return true; | |
1410 | } | |
1411 | ||
d6225aff TT |
1412 | CORE_ADDR |
1413 | win32_process_target::read_pc (struct regcache *regcache) | |
1414 | { | |
1415 | return (*the_low_target.get_pc) (regcache); | |
1416 | } | |
1417 | ||
1418 | void | |
1419 | win32_process_target::write_pc (struct regcache *regcache, CORE_ADDR pc) | |
1420 | { | |
1421 | return (*the_low_target.set_pc) (regcache, pc); | |
1422 | } | |
1423 | ||
42a59714 TT |
1424 | const char * |
1425 | win32_process_target::thread_name (ptid_t thread) | |
1426 | { | |
1427 | windows_thread_info *th | |
1428 | = windows_process.thread_rec (current_thread_ptid (), | |
1429 | DONT_INVALIDATE_CONTEXT); | |
8bbdbd69 | 1430 | return th->thread_name (); |
42a59714 TT |
1431 | } |
1432 | ||
fcab5839 TT |
1433 | const char * |
1434 | win32_process_target::pid_to_exec_file (int pid) | |
1435 | { | |
1436 | return windows_process.pid_to_exec_file (pid); | |
1437 | } | |
1438 | ||
5ef9273d TBA |
1439 | /* The win32 target ops object. */ |
1440 | ||
1441 | static win32_process_target the_win32_target; | |
1442 | ||
b80864fb DJ |
1443 | /* Initialize the Win32 backend. */ |
1444 | void | |
1445 | initialize_low (void) | |
1446 | { | |
52405d85 | 1447 | set_target_ops (&the_win32_target); |
d05b4ac3 | 1448 | the_low_target.arch_setup (); |
7d186bc0 | 1449 | |
de071872 | 1450 | initialize_loadable (); |
b80864fb | 1451 | } |