* win32-nat.c: Perform various gcc warning cleanups.
[deliverable/binutils-gdb.git] / gdb / win32-nat.c
1 /* Target-vector operations for controlling win32 child processes, for GDB.
2 Copyright 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions, A Red Hat Company.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
21 */
22
23 /* by Steve Chamberlain, sac@cygnus.com */
24
25 /* We assume we're being built with and will be used for cygwin. */
26
27 #include "defs.h"
28 #include "frame.h" /* required by inferior.h */
29 #include "inferior.h"
30 #include "target.h"
31 #include "gdbcore.h"
32 #include "command.h"
33 #include <signal.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <windows.h>
38 #include <imagehlp.h>
39 #include <sys/cygwin.h>
40
41 #include "buildsym.h"
42 #include "symfile.h"
43 #include "objfiles.h"
44 #include "gdb_string.h"
45 #include "gdbthread.h"
46 #include "gdbcmd.h"
47 #include <sys/param.h>
48 #include <unistd.h>
49
50 /* The ui's event loop. */
51 extern int (*ui_loop_hook) (int signo);
52
53 /* If we're not using the old Cygwin header file set, define the
54 following which never should have been in the generic Win32 API
55 headers in the first place since they were our own invention... */
56 #ifndef _GNU_H_WINDOWS_H
57 enum
58 {
59 FLAG_TRACE_BIT = 0x100,
60 CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
61 };
62 #endif
63
64 /* The string sent by cygwin when it processes a signal.
65 FIXME: This should be in a cygwin include file. */
66 #define CYGWIN_SIGNAL_STRING "cygwin: signal"
67
68 #define CHECK(x) check (x, __FILE__,__LINE__)
69 #define DEBUG_EXEC(x) if (debug_exec) printf x
70 #define DEBUG_EVENTS(x) if (debug_events) printf x
71 #define DEBUG_MEM(x) if (debug_memory) printf x
72 #define DEBUG_EXCEPT(x) if (debug_exceptions) printf x
73
74 /* Forward declaration */
75 extern struct target_ops child_ops;
76
77 static void child_stop (void);
78 static int win32_child_thread_alive (int);
79 void child_kill_inferior (void);
80
81 static int last_sig = 0; /* Set if a signal was received from the
82 debugged process */
83 /* Thread information structure used to track information that is
84 not available in gdb's thread structure. */
85 typedef struct thread_info_struct
86 {
87 struct thread_info_struct *next;
88 DWORD id;
89 HANDLE h;
90 char *name;
91 int suspend_count;
92 CONTEXT context;
93 STACKFRAME sf;
94 } thread_info;
95
96 static thread_info thread_head;
97
98 /* The process and thread handles for the above context. */
99
100 static DEBUG_EVENT current_event; /* The current debug event from
101 WaitForDebugEvent */
102 static HANDLE current_process_handle; /* Currently executing process */
103 static thread_info *current_thread; /* Info on currently selected thread */
104 static DWORD main_thread_id; /* Thread ID of the main thread */
105
106 /* Counts of things. */
107 static int exception_count = 0;
108 static int event_count = 0;
109
110 /* User options. */
111 static int new_console = 0;
112 static int new_group = 1;
113 static int debug_exec = 0; /* show execution */
114 static int debug_events = 0; /* show events from kernel */
115 static int debug_memory = 0; /* show target memory accesses */
116 static int debug_exceptions = 0; /* show target exceptions */
117
118 /* This vector maps GDB's idea of a register's number into an address
119 in the win32 exception context vector.
120
121 It also contains the bit mask needed to load the register in question.
122
123 One day we could read a reg, we could inspect the context we
124 already have loaded, if it doesn't have the bit set that we need,
125 we read that set of registers in using GetThreadContext. If the
126 context already contains what we need, we just unpack it. Then to
127 write a register, first we have to ensure that the context contains
128 the other regs of the group, and then we copy the info in and set
129 out bit. */
130
131 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
132 static const int mappings[] =
133 {
134 context_offset (Eax),
135 context_offset (Ecx),
136 context_offset (Edx),
137 context_offset (Ebx),
138 context_offset (Esp),
139 context_offset (Ebp),
140 context_offset (Esi),
141 context_offset (Edi),
142 context_offset (Eip),
143 context_offset (EFlags),
144 context_offset (SegCs),
145 context_offset (SegSs),
146 context_offset (SegDs),
147 context_offset (SegEs),
148 context_offset (SegFs),
149 context_offset (SegGs),
150 context_offset (FloatSave.RegisterArea[0 * 10]),
151 context_offset (FloatSave.RegisterArea[1 * 10]),
152 context_offset (FloatSave.RegisterArea[2 * 10]),
153 context_offset (FloatSave.RegisterArea[3 * 10]),
154 context_offset (FloatSave.RegisterArea[4 * 10]),
155 context_offset (FloatSave.RegisterArea[5 * 10]),
156 context_offset (FloatSave.RegisterArea[6 * 10]),
157 context_offset (FloatSave.RegisterArea[7 * 10]),
158 context_offset (FloatSave.ControlWord),
159 context_offset (FloatSave.StatusWord),
160 context_offset (FloatSave.TagWord),
161 context_offset (FloatSave.ErrorSelector),
162 context_offset (FloatSave.ErrorOffset),
163 context_offset (FloatSave.DataSelector),
164 context_offset (FloatSave.DataOffset),
165 context_offset (FloatSave.ErrorSelector)
166 };
167
168 #undef context_offset
169
170 /* This vector maps the target's idea of an exception (extracted
171 from the DEBUG_EVENT structure) to GDB's idea. */
172
173 struct xlate_exception
174 {
175 int them;
176 enum target_signal us;
177 };
178
179 static const struct xlate_exception
180 xlate[] =
181 {
182 {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV},
183 {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV},
184 {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
185 {DBG_CONTROL_C, TARGET_SIGNAL_INT},
186 {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
187 {-1, -1}};
188
189 /* Find a thread record given a thread id.
190 If get_context then also retrieve the context for this
191 thread. */
192 static thread_info *
193 thread_rec (DWORD id, int get_context)
194 {
195 thread_info *th;
196
197 for (th = &thread_head; (th = th->next) != NULL;)
198 if (th->id == id)
199 {
200 if (!th->suspend_count && get_context)
201 {
202 if (get_context > 0 && id != current_event.dwThreadId)
203 th->suspend_count = SuspendThread (th->h) + 1;
204 else if (get_context < 0)
205 th->suspend_count = -1;
206
207 th->context.ContextFlags = CONTEXT_DEBUGGER;
208 GetThreadContext (th->h, &th->context);
209 }
210 return th;
211 }
212
213 return NULL;
214 }
215
216 /* Add a thread to the thread list */
217 static thread_info *
218 child_add_thread (DWORD id, HANDLE h)
219 {
220 thread_info *th;
221
222 if ((th = thread_rec (id, FALSE)))
223 return th;
224
225 th = (thread_info *) xmalloc (sizeof (*th));
226 memset (th, 0, sizeof (*th));
227 th->id = id;
228 th->h = h;
229 th->next = thread_head.next;
230 thread_head.next = th;
231 add_thread (id);
232 return th;
233 }
234
235 /* Clear out any old thread list and reintialize it to a
236 pristine state. */
237 static void
238 child_init_thread_list (void)
239 {
240 thread_info *th = &thread_head;
241
242 DEBUG_EVENTS (("gdb: child_init_thread_list\n"));
243 init_thread_list ();
244 while (th->next != NULL)
245 {
246 thread_info *here = th->next;
247 th->next = here->next;
248 (void) CloseHandle (here->h);
249 free (here);
250 }
251 }
252
253 /* Delete a thread from the list of threads */
254 static void
255 child_delete_thread (DWORD id)
256 {
257 thread_info *th;
258
259 if (info_verbose)
260 printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id));
261 delete_thread (id);
262
263 for (th = &thread_head;
264 th->next != NULL && th->next->id != id;
265 th = th->next)
266 continue;
267
268 if (th->next != NULL)
269 {
270 thread_info *here = th->next;
271 th->next = here->next;
272 CloseHandle (here->h);
273 free (here);
274 }
275 }
276
277 static void
278 check (BOOL ok, const char *file, int line)
279 {
280 if (!ok)
281 printf_filtered ("error return %s:%d was %lu\n", file, line, GetLastError ());
282 }
283
284 static void
285 do_child_fetch_inferior_registers (int r)
286 {
287 char *context_offset = ((char *) &current_thread->context) + mappings[r];
288 long l;
289 if (r == FCS_REGNUM)
290 {
291 l = *((long *)context_offset) & 0xffff;
292 supply_register (r, (char *) &l);
293 }
294 else if (r == FOP_REGNUM)
295 {
296 l = (*((long *)context_offset) >> 16) & ((1 << 11) - 1);
297 supply_register (r, (char *) &l);
298 }
299 else if (r >= 0)
300 supply_register (r, context_offset);
301 else
302 {
303 for (r = 0; r < NUM_REGS; r++)
304 do_child_fetch_inferior_registers (r);
305 }
306 }
307
308 static void
309 child_fetch_inferior_registers (int r)
310 {
311 current_thread = thread_rec (inferior_pid, TRUE);
312 do_child_fetch_inferior_registers (r);
313 }
314
315 static void
316 do_child_store_inferior_registers (int r)
317 {
318 if (r >= 0)
319 read_register_gen (r, ((char *) &current_thread->context) + mappings[r]);
320 else
321 {
322 for (r = 0; r < NUM_REGS; r++)
323 do_child_store_inferior_registers (r);
324 }
325 }
326
327 /* Store a new register value into the current thread context */
328 static void
329 child_store_inferior_registers (int r)
330 {
331 current_thread = thread_rec (inferior_pid, TRUE);
332 do_child_store_inferior_registers (r);
333 }
334
335 #include <psapi.h>
336 static int psapi_loaded = 0;
337 static HMODULE psapi_module_handle = NULL;
338 static BOOL WINAPI (*psapi_EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD)= NULL;
339 static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, DWORD)= NULL;
340 static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, DWORD)= NULL;
341
342 int psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
343 {
344 DWORD len;
345 MODULEINFO mi;
346 int i;
347 HMODULE dh_buf [ 1 ];
348 HMODULE* DllHandle = dh_buf;
349 DWORD cbNeeded;
350 BOOL ok;
351
352 if (!psapi_loaded ||
353 psapi_EnumProcessModules == NULL ||
354 psapi_GetModuleInformation == NULL ||
355 psapi_GetModuleFileNameExA == NULL)
356 {
357 if (psapi_loaded)goto failed;
358 psapi_loaded = 1;
359 psapi_module_handle = LoadLibrary ("psapi.dll");
360 if (!psapi_module_handle)
361 {
362 /* printf_unfiltered ("error loading psapi.dll: %u", GetLastError ());*/
363 goto failed;
364 }
365 psapi_EnumProcessModules = GetProcAddress (psapi_module_handle, "EnumProcessModules" );
366 psapi_GetModuleInformation = GetProcAddress (psapi_module_handle, "GetModuleInformation");
367 psapi_GetModuleFileNameExA = (void *) GetProcAddress (psapi_module_handle,
368 "GetModuleFileNameExA");
369 if (psapi_EnumProcessModules == NULL ||
370 psapi_GetModuleInformation == NULL ||
371 psapi_GetModuleFileNameExA == NULL)
372 goto failed;
373 }
374
375 cbNeeded = 0;
376 ok = (*psapi_EnumProcessModules) (current_process_handle,
377 DllHandle,
378 sizeof (HMODULE),
379 &cbNeeded);
380
381 if (!ok || !cbNeeded)
382 goto failed;
383
384 DllHandle = (HMODULE*) alloca (cbNeeded);
385 if (!DllHandle)
386 goto failed;
387
388 ok = (*psapi_EnumProcessModules) (current_process_handle,
389 DllHandle,
390 cbNeeded,
391 &cbNeeded);
392 if (!ok)
393 goto failed;
394
395 for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++)
396 {
397 if (!(*psapi_GetModuleInformation) (current_process_handle,
398 DllHandle [i],
399 &mi,
400 sizeof (mi)))
401 error ("Can't get module info");
402
403 len = (*psapi_GetModuleFileNameExA) (current_process_handle,
404 DllHandle [i],
405 dll_name_ret,
406 MAX_PATH);
407 if (len == 0)
408 error ("Error getting dll name: %u\n", GetLastError ());
409
410 if ((DWORD) (mi.lpBaseOfDll) == BaseAddress)
411 return 1;
412 }
413
414 failed:
415 dll_name_ret[0] = '\0';
416 return 0;
417 }
418
419 /* Encapsulate the information required in a call to
420 symbol_file_add_args */
421 struct safe_symbol_file_add_args
422 {
423 char *name;
424 int from_tty;
425 struct section_addr_info *addrs;
426 int mainline;
427 int flags;
428 struct ui_file *err, *out;
429 struct objfile *ret;
430 };
431
432 /* Call symbol_file_add with stderr redirected. We don't care if there
433 are errors. */
434 static int
435 safe_symbol_file_add_stub (void *argv)
436 {
437 #define p ((struct safe_symbol_file_add_args *)argv)
438 p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags);
439 return !!p->ret;
440 #undef p
441 }
442
443 /* Restore gdb's stderr after calling symbol_file_add */
444 static void
445 safe_symbol_file_add_cleanup (void *p)
446 {
447 # define sp ((struct safe_symbol_file_add_args *)p)
448 gdb_flush (gdb_stderr);
449 gdb_flush (gdb_stdout);
450 ui_file_delete (gdb_stderr);
451 ui_file_delete (gdb_stdout);
452 gdb_stderr = sp->err;
453 gdb_stdout = sp->out;
454 # undef sp
455 }
456
457 /* symbol_file_add wrapper that prevents errors from being displayed. */
458 static struct objfile *
459 safe_symbol_file_add (char *name, int from_tty,
460 struct section_addr_info *addrs,
461 int mainline, int flags)
462
463 {
464 struct safe_symbol_file_add_args p;
465 struct cleanup *cleanup;
466
467 cleanup = make_cleanup (safe_symbol_file_add_cleanup, &p);
468
469 p.err = gdb_stderr;
470 p.out = gdb_stdout;
471 gdb_flush (gdb_stderr);
472 gdb_flush (gdb_stdout);
473 gdb_stderr = ui_file_new ();
474 gdb_stdout = ui_file_new ();
475 p.name = name;
476 p.from_tty = from_tty;
477 p.addrs = addrs;
478 p.mainline = mainline;
479 p.flags = flags;
480 catch_errors (safe_symbol_file_add_stub, &p, "", RETURN_MASK_ERROR);
481
482 do_cleanups (cleanup);
483 return p.ret;
484 }
485
486 /* Maintain a linked list of "so" information. */
487 struct so_stuff
488 {
489 struct so_stuff *next, **last;
490 DWORD load_addr;
491 char name[0];
492 } solib_start, *solib_end;
493
494 /* Remember the maximum DLL length for printing in info dll command. */
495 int max_dll_name_len;
496
497 /* Wait for child to do something. Return pid of child, or -1 in case
498 of error; store status through argument pointer OURSTATUS. */
499 static int
500 handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
501 {
502 LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
503 DWORD dll_name_ptr;
504 DWORD done;
505 char dll_buf[MAX_PATH + 1];
506 struct so_stuff *so;
507 char *dll_name = NULL;
508 int len;
509 char *p;
510
511 dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
512
513 if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
514 dll_buf[0] = dll_buf[sizeof(dll_buf) - 1] = '\0';
515
516 dll_name = dll_buf;
517
518 /* Attempt to read the name of the dll that was detected.
519 This is documented to work only when actively debugging
520 a program. It will not work for attached processes. */
521 if (dll_name == NULL || *dll_name == '\0')
522 {
523 DWORD size = event->fUnicode ? sizeof (WCHAR) : sizeof (char);
524 int len = 0;
525 char b[2];
526
527 ReadProcessMemory (current_process_handle,
528 (LPCVOID) event->lpImageName,
529 (char *) &dll_name_ptr,
530 sizeof (dll_name_ptr), &done);
531
532 /* See if we could read the address of a string, and that the
533 address isn't null. */
534
535 if (done != sizeof (dll_name_ptr) || !dll_name_ptr)
536 return 1;
537
538 do
539 {
540 ReadProcessMemory (current_process_handle,
541 (LPCVOID) (dll_name_ptr + len * size),
542 &b,
543 size,
544 &done);
545 len++;
546 }
547 while ((b[0] != 0 || b[size - 1] != 0) && done == size);
548
549 dll_name = alloca (len);
550
551 if (event->fUnicode)
552 {
553 WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR));
554 ReadProcessMemory (current_process_handle,
555 (LPCVOID) dll_name_ptr,
556 unicode_dll_name,
557 len * sizeof (WCHAR),
558 &done);
559
560 WideCharToMultiByte (CP_ACP, 0,
561 unicode_dll_name, len,
562 dll_name, len, 0, 0);
563 }
564 else
565 {
566 ReadProcessMemory (current_process_handle,
567 (LPCVOID) dll_name_ptr,
568 dll_name,
569 len,
570 &done);
571 }
572 }
573
574 if (!dll_name)
575 return 1;
576
577 (void) strlwr (dll_name);
578
579 while ((p = strchr (dll_name, '\\')))
580 *p = '/';
581
582 so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (dll_name) + 8 + 2);
583 so->load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
584 strcpy (so->name, dll_name);
585
586 solib_end->next = so;
587 solib_end = so;
588 so->next = NULL;
589
590 len = strlen (dll_name);
591 if (len > max_dll_name_len)
592 max_dll_name_len = len;
593
594 return 1;
595 }
596
597 /* Return name of last loaded DLL. */
598 char *
599 child_solib_loaded_library_pathname (int pid ATTRIBUTE_UNUSED)
600 {
601 return !solib_end || !solib_end->name[0]? NULL : solib_end->name;
602 }
603
604 /* Clear list of loaded DLLs. */
605 void
606 child_clear_solibs (void)
607 {
608 struct so_stuff *so, *so1 = solib_start.next;
609
610 while ((so = so1) != NULL)
611 {
612 so1 = so->next;
613 free (so);
614 }
615
616 solib_start.next = NULL;
617 solib_end = &solib_start;
618 max_dll_name_len = sizeof ("DLL Name") - 1;
619 }
620
621 /* Add DLL symbol information. */
622 void
623 child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED, struct target_ops *t ATTRIBUTE_UNUSED)
624 {
625 struct section_addr_info section_addrs;
626
627 /* The symbols in a dll are offset by 0x1000, which is the
628 the offset from 0 of the first byte in an image - because
629 of the file header and the section alignment. */
630
631 if (!solib_end || !solib_end->name[0])
632 return;
633
634 memset (&section_addrs, 0, sizeof (section_addrs));
635 section_addrs.other[0].name = ".text";
636 section_addrs.other[0].addr = solib_end->load_addr;
637 safe_symbol_file_add (solib_end->name, 0, &section_addrs, 0, OBJF_SHARED);
638
639 return;
640 }
641
642 /* Load DLL symbol info. */
643 void
644 dll_symbol_command (char *args, int from_tty ATTRIBUTE_UNUSED)
645 {
646 dont_repeat ();
647
648 if (args == NULL)
649 error ("dll-symbols requires a file name");
650
651 safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
652 }
653
654 /* List currently loaded DLLs. */
655 void
656 info_dll_command (char *ignore ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED)
657 {
658 struct so_stuff *so = &solib_start;
659
660 if (!so->next)
661 return;
662
663 printf ("%*s Load Address\n", -max_dll_name_len, "DLL Name");
664 while ((so = so->next) != NULL)
665 printf_filtered ("%*s %08lx\n", -max_dll_name_len, so->name, so->load_addr);
666
667 return;
668 }
669
670 /* Handle DEBUG_STRING output from child process.
671 Cygwin prepends its messages with a "cygwin:". Interpret this as
672 a Cygwin signal. Otherwise just print the string as a warning. */
673 static int
674 handle_output_debug_string (struct target_waitstatus *ourstatus)
675 {
676 char *s;
677 int gotasig = FALSE;
678
679 if (!target_read_string
680 ((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0)
681 || !s || !*s)
682 return gotasig;
683
684 if (strncmp (s, CYGWIN_SIGNAL_STRING, sizeof (CYGWIN_SIGNAL_STRING) - 1) != 0)
685 {
686 if (strncmp (s, "cYg", 3) != 0)
687 warning ("%s", s);
688 }
689 else
690 {
691 char *p;
692 int sig = strtol (s + sizeof (CYGWIN_SIGNAL_STRING) - 1, &p, 0);
693 gotasig = target_signal_from_host (sig);
694 ourstatus->value.sig = gotasig;
695 if (gotasig)
696 ourstatus->kind = TARGET_WAITKIND_STOPPED;
697 }
698
699 free (s);
700 return gotasig;
701 }
702
703 static int
704 handle_exception (struct target_waitstatus *ourstatus)
705 {
706 thread_info *th;
707 DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
708
709 ourstatus->kind = TARGET_WAITKIND_STOPPED;
710
711 /* Record the context of the current thread */
712 th = thread_rec (current_event.dwThreadId, -1);
713
714 switch (code)
715 {
716 case EXCEPTION_ACCESS_VIOLATION:
717 DEBUG_EXCEPT (("gdb: Target exception ACCESS_VIOLATION at 0x%08lx\n",
718 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
719 ourstatus->value.sig = TARGET_SIGNAL_SEGV;
720 last_sig = SIGSEGV;
721 break;
722 case STATUS_FLOAT_UNDERFLOW:
723 case STATUS_FLOAT_DIVIDE_BY_ZERO:
724 case STATUS_FLOAT_OVERFLOW:
725 case STATUS_INTEGER_DIVIDE_BY_ZERO:
726 DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08lx\n",
727 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
728 ourstatus->value.sig = TARGET_SIGNAL_FPE;
729 last_sig = SIGFPE;
730 break;
731 case STATUS_STACK_OVERFLOW:
732 DEBUG_EXCEPT (("gdb: Target exception STACK_OVERFLOW at 0x%08lx\n",
733 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
734 ourstatus->value.sig = TARGET_SIGNAL_SEGV;
735 break;
736 case EXCEPTION_BREAKPOINT:
737 DEBUG_EXCEPT (("gdb: Target exception BREAKPOINT at 0x%08lx\n",
738 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
739 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
740 break;
741 case DBG_CONTROL_C:
742 DEBUG_EXCEPT (("gdb: Target exception CONTROL_C at 0x%08lx\n",
743 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
744 ourstatus->value.sig = TARGET_SIGNAL_INT;
745 last_sig = SIGINT; /* FIXME - should check pass state */
746 break;
747 case EXCEPTION_SINGLE_STEP:
748 DEBUG_EXCEPT (("gdb: Target exception SINGLE_STEP at 0x%08lx\n",
749 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
750 ourstatus->value.sig = TARGET_SIGNAL_TRAP;
751 break;
752 case EXCEPTION_ILLEGAL_INSTRUCTION:
753 DEBUG_EXCEPT (("gdb: Target exception SINGLE_ILL at 0x%08lx\n",
754 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress));
755 ourstatus->value.sig = TARGET_SIGNAL_ILL;
756 last_sig = SIGILL;
757 break;
758 default:
759 printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
760 current_event.u.Exception.ExceptionRecord.ExceptionCode,
761 (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
762 ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
763 break;
764 }
765 exception_count++;
766 return 1;
767 }
768
769 /* Resume all artificially suspended threads if we are continuing
770 execution */
771 static BOOL
772 child_continue (DWORD continue_status, int id)
773 {
774 int i;
775 thread_info *th;
776 BOOL res;
777
778 DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, DBG_CONTINUE);\n",
779 current_event.dwProcessId, current_event.dwThreadId));
780 res = ContinueDebugEvent (current_event.dwProcessId,
781 current_event.dwThreadId,
782 continue_status);
783 continue_status = 0;
784 if (res)
785 for (th = &thread_head; (th = th->next) != NULL;)
786 if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
787 {
788 for (i = 0; i < th->suspend_count; i++)
789 (void) ResumeThread (th->h);
790 th->suspend_count = 0;
791 }
792
793 return res;
794 }
795
796 /* Get the next event from the child. Return 1 if the event requires
797 handling by WFI (or whatever).
798 */
799 static int
800 get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus)
801 {
802 BOOL debug_event;
803 DWORD continue_status, event_code;
804 thread_info *th = NULL;
805 static thread_info dummy_thread_info;
806 int retval = 0;
807
808 last_sig = 0;
809
810 if (!(debug_event = WaitForDebugEvent (&current_event, 1000)))
811 goto out;
812
813 event_count++;
814 continue_status = DBG_CONTINUE;
815
816 event_code = current_event.dwDebugEventCode;
817 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
818
819 switch (event_code)
820 {
821 case CREATE_THREAD_DEBUG_EVENT:
822 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
823 (unsigned) current_event.dwProcessId,
824 (unsigned) current_event.dwThreadId,
825 "CREATE_THREAD_DEBUG_EVENT"));
826 /* Record the existence of this thread */
827 th = child_add_thread (current_event.dwThreadId,
828 current_event.u.CreateThread.hThread);
829 if (info_verbose)
830 printf_unfiltered ("[New %s]\n",
831 target_pid_to_str (current_event.dwThreadId));
832 retval = current_event.dwThreadId;
833 break;
834
835 case EXIT_THREAD_DEBUG_EVENT:
836 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
837 (unsigned) current_event.dwProcessId,
838 (unsigned) current_event.dwThreadId,
839 "EXIT_THREAD_DEBUG_EVENT"));
840 child_delete_thread (current_event.dwThreadId);
841 th = &dummy_thread_info;
842 break;
843
844 case CREATE_PROCESS_DEBUG_EVENT:
845 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
846 (unsigned) current_event.dwProcessId,
847 (unsigned) current_event.dwThreadId,
848 "CREATE_PROCESS_DEBUG_EVENT"));
849 current_process_handle = current_event.u.CreateProcessInfo.hProcess;
850
851 main_thread_id = current_event.dwThreadId;
852 /* Add the main thread */
853 #if 0
854 th = child_add_thread (current_event.dwProcessId,
855 current_event.u.CreateProcessInfo.hProcess);
856 #endif
857 th = child_add_thread (main_thread_id,
858 current_event.u.CreateProcessInfo.hThread);
859 retval = ourstatus->value.related_pid = current_event.dwThreadId;
860 break;
861
862 case EXIT_PROCESS_DEBUG_EVENT:
863 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
864 (unsigned) current_event.dwProcessId,
865 (unsigned) current_event.dwThreadId,
866 "EXIT_PROCESS_DEBUG_EVENT"));
867 ourstatus->kind = TARGET_WAITKIND_EXITED;
868 ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
869 CloseHandle (current_process_handle);
870 retval = main_thread_id;
871 break;
872
873 case LOAD_DLL_DEBUG_EVENT:
874 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
875 (unsigned) current_event.dwProcessId,
876 (unsigned) current_event.dwThreadId,
877 "LOAD_DLL_DEBUG_EVENT"));
878 catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
879 registers_changed (); /* mark all regs invalid */
880 ourstatus->kind = TARGET_WAITKIND_LOADED;
881 ourstatus->value.integer = 0;
882 retval = main_thread_id;
883 break;
884
885 case UNLOAD_DLL_DEBUG_EVENT:
886 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
887 (unsigned) current_event.dwProcessId,
888 (unsigned) current_event.dwThreadId,
889 "UNLOAD_DLL_DEBUG_EVENT"));
890 break; /* FIXME: don't know what to do here */
891
892 case EXCEPTION_DEBUG_EVENT:
893 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
894 (unsigned) current_event.dwProcessId,
895 (unsigned) current_event.dwThreadId,
896 "EXCEPTION_DEBUG_EVENT"));
897 handle_exception (ourstatus);
898 retval = current_event.dwThreadId;
899 break;
900
901 case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
902 DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n",
903 (unsigned) current_event.dwProcessId,
904 (unsigned) current_event.dwThreadId,
905 "OUTPUT_DEBUG_STRING_EVENT"));
906 if (handle_output_debug_string ( ourstatus))
907 retval = main_thread_id;
908 break;
909
910 default:
911 printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n",
912 (DWORD) current_event.dwProcessId,
913 (DWORD) current_event.dwThreadId);
914 printf_unfiltered (" unknown event code %ld\n",
915 current_event.dwDebugEventCode);
916 break;
917 }
918
919 if (!retval)
920 CHECK (child_continue (continue_status, -1));
921 else
922 {
923 current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
924 inferior_pid = retval;
925 }
926
927 out:
928 return retval;
929 }
930
931 /* Wait for interesting events to occur in the target process. */
932 static int
933 child_wait (int pid, struct target_waitstatus *ourstatus)
934 {
935 /* We loop when we get a non-standard exception rather than return
936 with a SPURIOUS because resume can try and step or modify things,
937 which needs a current_thread->h. But some of these exceptions mark
938 the birth or death of threads, which mean that the current thread
939 isn't necessarily what you think it is. */
940
941 while (1)
942 {
943 int retval = get_child_debug_event (pid, ourstatus);
944 if (retval)
945 return retval;
946 else
947 {
948 int detach = 0;
949
950 if (ui_loop_hook != NULL)
951 detach = ui_loop_hook (0);
952
953 if (detach)
954 child_kill_inferior ();
955 }
956 }
957 }
958
959 static void
960 do_initial_child_stuff (DWORD pid)
961 {
962 extern int stop_after_trap;
963
964 last_sig = 0;
965 event_count = 0;
966 exception_count = 0;
967 current_event.dwProcessId = pid;
968 memset (&current_event, 0, sizeof (current_event));
969 push_target (&child_ops);
970 child_init_thread_list ();
971 child_clear_solibs ();
972 clear_proceed_status ();
973 init_wait_for_inferior ();
974
975 target_terminal_init ();
976 target_terminal_inferior ();
977
978 while (1)
979 {
980 stop_after_trap = 1;
981 wait_for_inferior ();
982 if (stop_signal != TARGET_SIGNAL_TRAP)
983 resume (0, stop_signal);
984 else
985 break;
986 }
987 stop_after_trap = 0;
988 return;
989 }
990
991 /* Attach to process PID, then initialize for debugging it. */
992
993 static void
994 child_attach (char *args, int from_tty)
995 {
996 BOOL ok;
997 DWORD pid = strtoul (args, 0, 0);
998
999 if (!args)
1000 error_no_arg ("process-id to attach");
1001
1002 ok = DebugActiveProcess (pid);
1003
1004 if (!ok)
1005 error ("Can't attach to process.");
1006
1007 if (from_tty)
1008 {
1009 char *exec_file = (char *) get_exec_file (0);
1010
1011 if (exec_file)
1012 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
1013 target_pid_to_str (pid));
1014 else
1015 printf_unfiltered ("Attaching to %s\n",
1016 target_pid_to_str (pid));
1017
1018 gdb_flush (gdb_stdout);
1019 }
1020
1021 do_initial_child_stuff (pid);
1022 target_terminal_ours ();
1023 }
1024
1025 static void
1026 child_detach (char *args ATTRIBUTE_UNUSED, int from_tty)
1027 {
1028 if (from_tty)
1029 {
1030 char *exec_file = get_exec_file (0);
1031 if (exec_file == 0)
1032 exec_file = "";
1033 printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
1034 target_pid_to_str (inferior_pid));
1035 gdb_flush (gdb_stdout);
1036 }
1037 inferior_pid = 0;
1038 unpush_target (&child_ops);
1039 }
1040
1041 /* Print status information about what we're accessing. */
1042
1043 static void
1044 child_files_info (struct target_ops *ignore ATTRIBUTE_UNUSED)
1045 {
1046 printf_unfiltered ("\tUsing the running image of %s %s.\n",
1047 attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
1048 }
1049
1050 /* ARGSUSED */
1051 static void
1052 child_open (char *arg ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED)
1053 {
1054 error ("Use the \"run\" command to start a Unix child process.");
1055 }
1056
1057 /* Start an inferior win32 child process and sets inferior_pid to its pid.
1058 EXEC_FILE is the file to run.
1059 ALLARGS is a string containing the arguments to the program.
1060 ENV is the environment vector to pass. Errors reported with error(). */
1061
1062 static void
1063 child_create_inferior (char *exec_file, char *allargs, char **env)
1064 {
1065 char real_path[MAXPATHLEN];
1066 char *winenv;
1067 char *temp;
1068 int envlen;
1069 int i;
1070 STARTUPINFO si;
1071 PROCESS_INFORMATION pi;
1072 BOOL ret;
1073 DWORD flags;
1074 char *args;
1075
1076 if (!exec_file)
1077 error ("No executable specified, use `target exec'.\n");
1078
1079 memset (&si, 0, sizeof (si));
1080 si.cb = sizeof (si);
1081
1082 cygwin_conv_to_win32_path (exec_file, real_path);
1083
1084 flags = DEBUG_ONLY_THIS_PROCESS;
1085
1086 if (new_group)
1087 flags |= CREATE_NEW_PROCESS_GROUP;
1088
1089 if (new_console)
1090 flags |= CREATE_NEW_CONSOLE;
1091
1092 args = alloca (strlen (real_path) + strlen (allargs) + 2);
1093
1094 strcpy (args, real_path);
1095
1096 strcat (args, " ");
1097 strcat (args, allargs);
1098
1099 /* Prepare the environment vars for CreateProcess. */
1100 {
1101 /* This code use to assume all env vars were file names and would
1102 translate them all to win32 style. That obviously doesn't work in the
1103 general case. The current rule is that we only translate PATH.
1104 We need to handle PATH because we're about to call CreateProcess and
1105 it uses PATH to find DLL's. Fortunately PATH has a well-defined value
1106 in both posix and win32 environments. cygwin.dll will change it back
1107 to posix style if necessary. */
1108
1109 static const char *conv_path_names[] =
1110 {
1111 "PATH=",
1112 0
1113 };
1114
1115 /* CreateProcess takes the environment list as a null terminated set of
1116 strings (i.e. two nulls terminate the list). */
1117
1118 /* Get total size for env strings. */
1119 for (envlen = 0, i = 0; env[i] && *env[i]; i++)
1120 {
1121 int j, len;
1122
1123 for (j = 0; conv_path_names[j]; j++)
1124 {
1125 len = strlen (conv_path_names[j]);
1126 if (strncmp (conv_path_names[j], env[i], len) == 0)
1127 {
1128 if (cygwin_posix_path_list_p (env[i] + len))
1129 envlen += len
1130 + cygwin_posix_to_win32_path_list_buf_size (env[i] + len);
1131 else
1132 envlen += strlen (env[i]) + 1;
1133 break;
1134 }
1135 }
1136 if (conv_path_names[j] == NULL)
1137 envlen += strlen (env[i]) + 1;
1138 }
1139
1140 winenv = alloca (envlen + 1);
1141
1142 /* Copy env strings into new buffer. */
1143 for (temp = winenv, i = 0; env[i] && *env[i]; i++)
1144 {
1145 int j, len;
1146
1147 for (j = 0; conv_path_names[j]; j++)
1148 {
1149 len = strlen (conv_path_names[j]);
1150 if (strncmp (conv_path_names[j], env[i], len) == 0)
1151 {
1152 if (cygwin_posix_path_list_p (env[i] + len))
1153 {
1154 memcpy (temp, env[i], len);
1155 cygwin_posix_to_win32_path_list (env[i] + len, temp + len);
1156 }
1157 else
1158 strcpy (temp, env[i]);
1159 break;
1160 }
1161 }
1162 if (conv_path_names[j] == NULL)
1163 strcpy (temp, env[i]);
1164
1165 temp += strlen (temp) + 1;
1166 }
1167
1168 /* Final nil string to terminate new env. */
1169 *temp = 0;
1170 }
1171
1172 ret = CreateProcess (0,
1173 args, /* command line */
1174 NULL, /* Security */
1175 NULL, /* thread */
1176 TRUE, /* inherit handles */
1177 flags, /* start flags */
1178 winenv,
1179 NULL, /* current directory */
1180 &si,
1181 &pi);
1182 if (!ret)
1183 error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
1184
1185 do_initial_child_stuff (pi.dwProcessId);
1186
1187 /* child_continue (DBG_CONTINUE, -1);*/
1188 proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
1189 }
1190
1191 static void
1192 child_mourn_inferior (void)
1193 {
1194 (void) child_continue (DBG_CONTINUE, -1);
1195 unpush_target (&child_ops);
1196 generic_mourn_inferior ();
1197 }
1198
1199 /* Send a SIGINT to the process group. This acts just like the user typed a
1200 ^C on the controlling terminal. */
1201
1202 static void
1203 child_stop (void)
1204 {
1205 DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
1206 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
1207 registers_changed (); /* refresh register state */
1208 }
1209
1210 int
1211 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
1212 int write, struct target_ops *target ATTRIBUTE_UNUSED)
1213 {
1214 DWORD done;
1215 if (write)
1216 {
1217 DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n",
1218 len, (DWORD) memaddr));
1219 WriteProcessMemory (current_process_handle, (LPVOID) memaddr, our,
1220 len, &done);
1221 FlushInstructionCache (current_process_handle, (LPCVOID) memaddr, len);
1222 }
1223 else
1224 {
1225 DEBUG_MEM (("gdb: read target memory, %d bytes at 0x%08lx\n",
1226 len, (DWORD) memaddr));
1227 ReadProcessMemory (current_process_handle, (LPCVOID) memaddr, our, len,
1228 &done);
1229 }
1230 return done;
1231 }
1232
1233 void
1234 child_kill_inferior (void)
1235 {
1236 CHECK (TerminateProcess (current_process_handle, 0));
1237
1238 for (;;)
1239 {
1240 if (!child_continue (DBG_CONTINUE, -1))
1241 break;
1242 if (!WaitForDebugEvent (&current_event, INFINITE))
1243 break;
1244 if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
1245 break;
1246 }
1247
1248 CHECK (CloseHandle (current_process_handle));
1249
1250 /* this may fail in an attached process so don't check. */
1251 (void) CloseHandle (current_thread->h);
1252 target_mourn_inferior (); /* or just child_mourn_inferior? */
1253 }
1254
1255 void
1256 child_resume (int pid, int step, enum target_signal sig)
1257 {
1258 thread_info *th;
1259 DWORD continue_status = last_sig > 0 && last_sig < NSIG ?
1260 DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
1261
1262 last_sig = 0;
1263
1264 DEBUG_EXEC (("gdb: child_resume (pid=%d, step=%d, sig=%d);\n",
1265 pid, step, sig));
1266
1267 /* Get context for currently selected thread */
1268 th = thread_rec (current_event.dwThreadId, FALSE);
1269 if (th)
1270 {
1271 if (step)
1272 {
1273 /* Single step by setting t bit */
1274 child_fetch_inferior_registers (PS_REGNUM);
1275 th->context.EFlags |= FLAG_TRACE_BIT;
1276 }
1277
1278 if (th->context.ContextFlags)
1279 {
1280 CHECK (SetThreadContext (th->h, &th->context));
1281 th->context.ContextFlags = 0;
1282 }
1283 }
1284
1285 /* Allow continuing with the same signal that interrupted us.
1286 Otherwise complain. */
1287
1288 child_continue (continue_status, pid);
1289 }
1290
1291 static void
1292 child_prepare_to_store (void)
1293 {
1294 /* Do nothing, since we can store individual regs */
1295 }
1296
1297 static int
1298 child_can_run (void)
1299 {
1300 return 1;
1301 }
1302
1303 static void
1304 child_close (int x ATTRIBUTE_UNUSED)
1305 {
1306 DEBUG_EVENTS (("gdb: child_close, inferior_pid=%d\n", inferior_pid));
1307 }
1308
1309 struct target_ops child_ops;
1310
1311 static void
1312 init_child_ops (void)
1313 {
1314 child_ops.to_shortname = "child";
1315 child_ops.to_longname = "Win32 child process";
1316 child_ops.to_doc = "Win32 child process (started by the \"run\" command).";
1317 child_ops.to_open = child_open;
1318 child_ops.to_close = child_close;
1319 child_ops.to_attach = child_attach;
1320 child_ops.to_detach = child_detach;
1321 child_ops.to_resume = child_resume;
1322 child_ops.to_wait = child_wait;
1323 child_ops.to_fetch_registers = child_fetch_inferior_registers;
1324 child_ops.to_store_registers = child_store_inferior_registers;
1325 child_ops.to_prepare_to_store = child_prepare_to_store;
1326 child_ops.to_xfer_memory = child_xfer_memory;
1327 child_ops.to_files_info = child_files_info;
1328 child_ops.to_insert_breakpoint = memory_insert_breakpoint;
1329 child_ops.to_remove_breakpoint = memory_remove_breakpoint;
1330 child_ops.to_terminal_init = terminal_init_inferior;
1331 child_ops.to_terminal_inferior = terminal_inferior;
1332 child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
1333 child_ops.to_terminal_ours = terminal_ours;
1334 child_ops.to_terminal_info = child_terminal_info;
1335 child_ops.to_kill = child_kill_inferior;
1336 child_ops.to_load = 0;
1337 child_ops.to_lookup_symbol = 0;
1338 child_ops.to_create_inferior = child_create_inferior;
1339 child_ops.to_mourn_inferior = child_mourn_inferior;
1340 child_ops.to_can_run = child_can_run;
1341 child_ops.to_notice_signals = 0;
1342 child_ops.to_thread_alive = win32_child_thread_alive;
1343 child_ops.to_pid_to_str = cygwin_pid_to_str;
1344 child_ops.to_stop = child_stop;
1345 child_ops.to_stratum = process_stratum;
1346 child_ops.DONT_USE = 0;
1347 child_ops.to_has_all_memory = 1;
1348 child_ops.to_has_memory = 1;
1349 child_ops.to_has_stack = 1;
1350 child_ops.to_has_registers = 1;
1351 child_ops.to_has_execution = 1;
1352 child_ops.to_sections = 0;
1353 child_ops.to_sections_end = 0;
1354 child_ops.to_magic = OPS_MAGIC;
1355 }
1356
1357 void
1358 _initialize_inftarg (void)
1359 {
1360 init_child_ops ();
1361
1362 add_com ("dll-symbols", class_files, dll_symbol_command,
1363 "Load dll library symbols from FILE.");
1364
1365 add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
1366
1367 add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
1368 (char *) &new_console,
1369 "Set creation of new console when creating child process.",
1370 &setlist),
1371 &showlist);
1372
1373 add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
1374 (char *) &new_group,
1375 "Set creation of new group when creating child process.",
1376 &setlist),
1377 &showlist);
1378
1379 add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
1380 (char *) &debug_exec,
1381 "Set whether to display execution in child process.",
1382 &setlist),
1383 &showlist);
1384
1385 add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
1386 (char *) &debug_events,
1387 "Set whether to display kernel events in child process.",
1388 &setlist),
1389 &showlist);
1390
1391 add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
1392 (char *) &debug_memory,
1393 "Set whether to display memory accesses in child process.",
1394 &setlist),
1395 &showlist);
1396
1397 add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
1398 (char *) &debug_exceptions,
1399 "Set whether to display kernel exceptions in child process.",
1400 &setlist),
1401 &showlist);
1402
1403 add_info ("dll", info_dll_command, "Status of loaded DLLs.");
1404 add_info_alias ("sharedlibrary", "dll", 1);
1405
1406 add_target (&child_ops);
1407 }
1408
1409 /* Determine if the thread referenced by "pid" is alive
1410 by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
1411 it means that the pid has died. Otherwise it is assumed to be alive. */
1412 static int
1413 win32_child_thread_alive (int pid)
1414 {
1415 return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
1416 FALSE : TRUE;
1417 }
1418
1419 /* Convert pid to printable format. */
1420 char *
1421 cygwin_pid_to_str (int pid)
1422 {
1423 static char buf[80];
1424 if ((DWORD) pid == current_event.dwProcessId)
1425 sprintf (buf, "process %d", pid);
1426 else
1427 sprintf (buf, "thread %ld.0x%x", current_event.dwProcessId, pid);
1428 return buf;
1429 }
This page took 0.081743 seconds and 5 git commands to generate.