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