]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/win32-nat.c
* mdebugread.c (mylookup_symbol): enum namespace becomes
[thirdparty/binutils-gdb.git] / gdb / win32-nat.c
1 /* Target-vector operations for controlling win32 child processes, for GDB.
2 Copyright 1995
3 Free Software Foundation, Inc.
4
5 Contributed by Cygnus Support.
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
10 the Free Software Foundation; either version 2 of the License, or
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 eve nthe 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
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 /* by Steve Chamberlain, sac@cygnus.com */
23
24 #include "defs.h"
25 #include "frame.h" /* required by inferior.h */
26 #include "inferior.h"
27 #include "target.h"
28 #include "wait.h"
29 #include "gdbcore.h"
30 #include "command.h"
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <windows.h>
35 #include "buildsym.h"
36 #include "gdb_string.h"
37 #include "thread.h"
38 #include "gdbcmd.h"
39 #include <sys/param.h>
40 #define CHECK(x) check (x, __FILE__,__LINE__)
41 #define DEBUG(x) if (remote_debug) printf x
42
43
44 /* Forward declaration */
45 extern struct target_ops child_ops;
46
47 /* The most recently read context. Inspect ContextFlags to see what
48 bits are valid. */
49
50 static CONTEXT context;
51
52 /* The process and thread handles for the above context. */
53
54 static HANDLE current_process;
55 static HANDLE current_thread;
56 static int current_process_id;
57 static int current_thread_id;
58
59 /* Counts of things. */
60 static int exception_count = 0;
61 static int event_count = 0;
62
63 /* User options. */
64 static int new_console = 0;
65 static int new_group = 0;
66
67 /* This vector maps GDB's idea of a register's number into an address
68 in the win32 exception context vector.
69
70 It also contains the bit mask needed to load the register in question.
71
72 One day we could read a reg, we could inspect the context we
73 already have loaded, if it doesn't have the bit set that we need,
74 we read that set of registers in using GetThreadContext. If the
75 context already contains what we need, we just unpack it. Then to
76 write a register, first we have to ensure that the context contains
77 the other regs of the group, and then we copy the info in and set
78 out bit. */
79
80 struct regmappings
81 {
82 char *incontext;
83 int mask;
84 };
85
86 static const struct regmappings
87 mappings[] =
88 {
89 {(char *) &context.Eax, CONTEXT_INTEGER},
90 {(char *) &context.Ecx, CONTEXT_INTEGER},
91 {(char *) &context.Edx, CONTEXT_INTEGER},
92 {(char *) &context.Ebx, CONTEXT_INTEGER},
93 {(char *) &context.Esp, CONTEXT_CONTROL},
94 {(char *) &context.Ebp, CONTEXT_CONTROL},
95 {(char *) &context.Esi, CONTEXT_INTEGER},
96 {(char *) &context.Edi, CONTEXT_INTEGER},
97 {(char *) &context.Eip, CONTEXT_CONTROL},
98 {(char *) &context.EFlags, CONTEXT_CONTROL},
99 {(char *) &context.SegCs, CONTEXT_SEGMENTS},
100 {(char *) &context.SegSs, CONTEXT_SEGMENTS},
101 {(char *) &context.SegDs, CONTEXT_SEGMENTS},
102 {(char *) &context.SegEs, CONTEXT_SEGMENTS},
103 {(char *) &context.SegFs, CONTEXT_SEGMENTS},
104 {(char *) &context.SegGs, CONTEXT_SEGMENTS},
105 {&context.FloatSave.RegisterArea[0 * 10], CONTEXT_FLOATING_POINT},
106 {&context.FloatSave.RegisterArea[1 * 10], CONTEXT_FLOATING_POINT},
107 {&context.FloatSave.RegisterArea[2 * 10], CONTEXT_FLOATING_POINT},
108 {&context.FloatSave.RegisterArea[3 * 10], CONTEXT_FLOATING_POINT},
109 {&context.FloatSave.RegisterArea[4 * 10], CONTEXT_FLOATING_POINT},
110 {&context.FloatSave.RegisterArea[5 * 10], CONTEXT_FLOATING_POINT},
111 {&context.FloatSave.RegisterArea[6 * 10], CONTEXT_FLOATING_POINT},
112 {&context.FloatSave.RegisterArea[7 * 10], CONTEXT_FLOATING_POINT},
113 };
114
115
116 /* This vector maps the target's idea of an exception (extracted
117 from the DEBUG_EVENT structure) to GDB's idea. */
118
119 struct xlate_exception
120 {
121 int them;
122 enum target_signal us;
123 };
124
125
126 static const struct xlate_exception
127 xlate[] =
128 {
129 {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV},
130 {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV},
131 {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
132 {DBG_CONTROL_C, TARGET_SIGNAL_INT},
133 {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
134 {-1, -1}};
135
136
137 static void
138 check (BOOL ok, const char *file, int line)
139 {
140 if (!ok)
141 printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
142 }
143
144 static void
145 child_fetch_inferior_registers (int r)
146 {
147 if (r < 0)
148 {
149 for (r = 0; r < NUM_REGS; r++)
150 child_fetch_inferior_registers (r);
151 }
152 else
153 {
154 supply_register (r, mappings[r].incontext);
155 }
156 }
157
158 static void
159 child_store_inferior_registers (int r)
160 {
161 if (r < 0)
162 {
163 for (r = 0; r < NUM_REGS; r++)
164 child_store_inferior_registers (r);
165 }
166 else
167 {
168 read_register_gen (r, mappings[r].incontext);
169 }
170 }
171
172
173 /* Wait for child to do something. Return pid of child, or -1 in case
174 of error; store status through argument pointer OURSTATUS. */
175
176
177 static int
178 handle_load_dll (char *eventp)
179 {
180 DEBUG_EVENT * event = (DEBUG_EVENT *)eventp;
181 DWORD dll_name_ptr;
182 DWORD done;
183
184 ReadProcessMemory (current_process,
185 (DWORD) event->u.LoadDll.lpImageName,
186 (char *) &dll_name_ptr,
187 sizeof (dll_name_ptr), &done);
188
189 /* See if we could read the address of a string, and that the
190 address isn't null. */
191
192 if (done == sizeof (dll_name_ptr) && dll_name_ptr)
193 {
194 char *dll_name;
195 int size = event->u.LoadDll.fUnicode ? sizeof (WCHAR) : sizeof (char);
196 int len = 0;
197 char b[2];
198 do
199 {
200 ReadProcessMemory (current_process,
201 dll_name_ptr + len * size,
202 &b,
203 size,
204 &done);
205 len++;
206 }
207 while ((b[0] != 0 || b[size - 1] != 0) && done == size);
208
209
210 dll_name = alloca (len);
211
212 if (event->u.LoadDll.fUnicode)
213 {
214 WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR));
215 ReadProcessMemory (current_process,
216 dll_name_ptr,
217 unicode_dll_name,
218 len * sizeof (WCHAR),
219 &done);
220
221 WideCharToMultiByte (CP_ACP, 0,
222 unicode_dll_name, len,
223 dll_name, len, 0, 0);
224 }
225 else
226 {
227 ReadProcessMemory (current_process,
228 dll_name_ptr,
229 dll_name,
230 len,
231 &done);
232 }
233
234 /* FIXME!! It would be nice to define one symbol which pointed to the
235 front of the dll if we can't find any symbols. */
236
237 context.ContextFlags = CONTEXT_FULL;
238 GetThreadContext (current_thread, &context);
239
240 /* The symbols in a dll are offset by 0x1000, which is the
241 the offset from 0 of the first byte in an image - because
242 of the file header and the section alignment.
243
244 FIXME: Is this the real reason that we need the 0x1000 ? */
245
246
247 symbol_file_add (dll_name, 0,
248 (int) event->u.LoadDll.lpBaseOfDll + 0x1000, 0, 0, 0);
249
250 /* We strip off the path of the dll for tidiness. */
251 if (strrchr (dll_name, '\\'))
252 dll_name = strrchr (dll_name, '\\') + 1;
253
254 printf_unfiltered ("%x:%s\n", event->u.LoadDll.lpBaseOfDll, dll_name);
255 }
256 return 1;
257 }
258
259
260 static void
261 handle_exception (DEBUG_EVENT * event, struct target_waitstatus *ourstatus)
262 {
263 int i;
264 int done = 0;
265 ourstatus->kind = TARGET_WAITKIND_STOPPED;
266
267 for (i = 0; !done && xlate[i].us > 0; i++)
268 {
269 if (xlate[i].them == event->u.Exception.ExceptionRecord.ExceptionCode)
270 {
271 ourstatus->value.sig = xlate[i].us;
272 done = 1;
273 break;
274 }
275 }
276
277 if (!done)
278 {
279 printf_unfiltered ("Want to know about exception code %08x\n",
280 event->u.Exception.ExceptionRecord.ExceptionCode);
281 ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
282 }
283 context.ContextFlags = CONTEXT_FULL;
284 GetThreadContext (current_thread, &context);
285 exception_count++;
286 }
287
288 static int
289 child_wait (int pid, struct target_waitstatus *ourstatus)
290 {
291 /* We loop when we get a non-standard exception rather than return
292 with a SPURIOUS because resume can try and step or modify things,
293 which needs a current_thread. But some of these exceptions mark
294 the birth or death of threads, which mean that the current thread
295 isn't necessarily what you think it is. */
296
297 while (1)
298 {
299 DEBUG_EVENT event;
300 BOOL t = WaitForDebugEvent (&event, INFINITE);
301
302 DEBUG (("%d = WaitForDebugEvent() code=%d pid=%d tid=%d)\n",
303 t,
304 event.dwDebugEventCode,
305 event.dwProcessId,
306 event.dwThreadId));
307
308 event_count++;
309
310 current_thread_id = event.dwThreadId;
311 current_process_id = event.dwProcessId;
312
313 switch (event.dwDebugEventCode)
314 {
315 case CREATE_THREAD_DEBUG_EVENT:
316 case EXIT_THREAD_DEBUG_EVENT:
317 case CREATE_PROCESS_DEBUG_EVENT:
318 break;
319
320 case EXIT_PROCESS_DEBUG_EVENT:
321 ourstatus->kind = TARGET_WAITKIND_EXITED;
322 ourstatus->value.integer = event.u.ExitProcess.dwExitCode;
323 CloseHandle (current_process);
324 CloseHandle (current_thread);
325 return current_process_id;
326 break;
327
328 case LOAD_DLL_DEBUG_EVENT:
329 catch_errors (handle_load_dll,
330 (char*) &event,
331 "\n[failed reading symbols from DLL]\n",
332 RETURN_MASK_ALL);
333 registers_changed(); /* mark all regs invalid */
334 break;
335 case EXCEPTION_DEBUG_EVENT:
336 handle_exception (&event, ourstatus);
337 return current_process_id;
338 default:
339 printf_unfiltered ("waitfor it %d %d %d %d\n", t,
340 event.dwDebugEventCode,
341 event.dwProcessId,
342 event.dwThreadId);
343 break;
344 }
345 CHECK (ContinueDebugEvent (current_process_id,
346 current_thread_id,
347 DBG_CONTINUE));
348 }
349 }
350
351
352
353
354 /* Attach to process PID, then initialize for debugging it. */
355
356 static void
357 child_attach (args, from_tty)
358 char *args;
359 int from_tty;
360 {
361 BOOL ok;
362
363 if (!args)
364 error_no_arg ("process-id to attach");
365
366 current_process_id = strtoul (args, 0, 0);
367
368 ok = DebugActiveProcess (current_process_id);
369
370 if (!ok)
371 error ("Can't attach to process.");
372
373
374 exception_count = 0;
375 event_count = 0;
376
377 if (from_tty)
378 {
379 char *exec_file = (char *) get_exec_file (0);
380
381 if (exec_file)
382 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
383 target_pid_to_str (current_process_id));
384 else
385 printf_unfiltered ("Attaching to %s\n",
386 target_pid_to_str (current_process_id));
387
388 gdb_flush (gdb_stdout);
389 }
390
391 inferior_pid = current_process_id;
392 push_target (&child_ops);
393 }
394
395
396 static void
397 child_detach (args, from_tty)
398 char *args;
399 int from_tty;
400 {
401 if (from_tty)
402 {
403 char *exec_file = get_exec_file (0);
404 if (exec_file == 0)
405 exec_file = "";
406 printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
407 target_pid_to_str (inferior_pid));
408 gdb_flush (gdb_stdout);
409 }
410 inferior_pid = 0;
411 unpush_target (&child_ops);
412 }
413
414
415 /* Print status information about what we're accessing. */
416
417 static void
418 child_files_info (ignore)
419 struct target_ops *ignore;
420 {
421 printf_unfiltered ("\tUsing the running image of %s %s.\n",
422 attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
423 }
424
425 /* ARGSUSED */
426 static void
427 child_open (arg, from_tty)
428 char *arg;
429 int from_tty;
430 {
431 error ("Use the \"run\" command to start a Unix child process.");
432 }
433
434
435 /* Start an inferior win32 child process and sets inferior_pid to its pid.
436 EXEC_FILE is the file to run.
437 ALLARGS is a string containing the arguments to the program.
438 ENV is the environment vector to pass. Errors reported with error(). */
439
440
441 static void
442 child_create_inferior (exec_file, allargs, env)
443 char *exec_file;
444 char *allargs;
445 char **env;
446 {
447 char real_path[MAXPATHLEN];
448 char *winenv;
449 char *temp;
450 int envlen;
451 int i;
452
453 STARTUPINFO si;
454 PROCESS_INFORMATION pi;
455 struct target_waitstatus dummy;
456 BOOL ret;
457 DWORD flags;
458 char *args;
459
460 if (!exec_file)
461 {
462 error ("No executable specified, use `target exec'.\n");
463 }
464
465 memset (&si, 0, sizeof (si));
466 si.cb = sizeof (si);
467
468 unix_path_to_dos_path (exec_file, real_path);
469
470 flags = DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS;
471
472 if (new_group)
473 flags |= CREATE_NEW_PROCESS_GROUP;
474
475 if (new_console)
476 flags |= CREATE_NEW_CONSOLE;
477
478 args = alloca (strlen (exec_file) + strlen (allargs) + 2);
479
480 strcpy (args, exec_file);
481 strcat (args, " ");
482 strcat (args, allargs);
483
484
485 /* get total size for env strings */
486 for (envlen = 0, i = 0; env[i] && *env[i]; i++)
487 envlen += strlen(env[i]) + 1;
488
489 winenv = alloca(envlen + 1); /* allocate new buffer */
490
491 /* copy env strings into new buffer */
492 for (temp = winenv, i = 0; env[i] && *env[i]; i++)
493 {
494 strcpy(temp, env[i]);
495 temp += strlen(temp) + 1;
496 }
497 *temp = 0; /* final nil string to terminate new env */
498
499 strcat (real_path, " ");
500 strcat (real_path, args);
501
502 ret = CreateProcess (0,
503 real_path,
504 NULL, /* Security */
505 NULL, /* thread */
506 TRUE, /* inherit handles */
507 flags, /* start flags */
508 winenv,
509 NULL, /* current directory */
510 &si,
511 &pi);
512 if (!ret)
513 error ("Error creating process %s, (error %d)\n", exec_file, GetLastError());
514
515 exception_count = 0;
516 event_count = 0;
517
518 inferior_pid = pi.dwProcessId;
519 current_process = pi.hProcess;
520 current_thread = pi.hThread;
521 current_process_id = pi.dwProcessId;
522 current_thread_id = pi.dwThreadId;
523 push_target (&child_ops);
524 init_thread_list ();
525 init_wait_for_inferior ();
526 clear_proceed_status ();
527 target_terminal_init ();
528 target_terminal_inferior ();
529
530 /* Ignore the first trap */
531 child_wait (inferior_pid, &dummy);
532
533 proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
534 }
535
536 static void
537 child_mourn_inferior ()
538 {
539 unpush_target (&child_ops);
540 generic_mourn_inferior ();
541 }
542
543
544 /* Send a SIGINT to the process group. This acts just like the user typed a
545 ^C on the controlling terminal. */
546
547 void
548 child_stop ()
549 {
550 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0));
551 }
552
553 int
554 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
555 int write, struct target_ops *target)
556 {
557 DWORD done;
558 if (write)
559 {
560 WriteProcessMemory (current_process, memaddr, our, len, &done);
561 FlushInstructionCache (current_process, memaddr, len);
562 }
563 else
564 {
565 ReadProcessMemory (current_process, memaddr, our, len, &done);
566 }
567 return done;
568 }
569
570 void
571 child_kill_inferior (void)
572 {
573 CHECK (TerminateProcess (current_process, 0));
574 CHECK (CloseHandle (current_process));
575 CHECK (CloseHandle (current_thread));
576 }
577
578 void
579 child_resume (int pid, int step, enum target_signal signal)
580 {
581 DEBUG (("child_resume (%d, %d, %d);\n", pid, step, signal));
582
583 if (step)
584 {
585 /* Single step by setting t bit */
586 child_fetch_inferior_registers (PS_REGNUM);
587 context.EFlags |= FLAG_TRACE_BIT;
588 }
589
590 if (context.ContextFlags)
591 {
592 CHECK (SetThreadContext (current_thread, &context));
593 context.ContextFlags = 0;
594 }
595
596 if (signal)
597 {
598 fprintf_unfiltered (gdb_stderr, "Can't send signals to the child.\n");
599 }
600
601 CHECK (ContinueDebugEvent (current_process_id,
602 current_thread_id,
603 DBG_CONTINUE));
604 }
605
606 static void
607 child_prepare_to_store ()
608 {
609 /* Do nothing, since we can store individual regs */
610 }
611
612 static int
613 child_can_run ()
614 {
615 return 1;
616 }
617
618 static void
619 child_close ()
620 {
621
622 }
623 struct target_ops child_ops =
624 {
625 "child", /* to_shortname */
626 "Win32 child process", /* to_longname */
627 "Win32 child process (started by the \"run\" command).", /* to_doc */
628 child_open, /* to_open */
629 child_close, /* to_close */
630 child_attach, /* to_attach */
631 child_detach, /* to_detach */
632 child_resume, /* to_resume */
633 child_wait, /* to_wait */
634 child_fetch_inferior_registers,/* to_fetch_registers */
635 child_store_inferior_registers,/* to_store_registers */
636 child_prepare_to_store, /* to_child_prepare_to_store */
637 child_xfer_memory, /* to_xfer_memory */
638 child_files_info, /* to_files_info */
639 memory_insert_breakpoint, /* to_insert_breakpoint */
640 memory_remove_breakpoint, /* to_remove_breakpoint */
641 terminal_init_inferior, /* to_terminal_init */
642 terminal_inferior, /* to_terminal_inferior */
643 terminal_ours_for_output, /* to_terminal_ours_for_output */
644 terminal_ours, /* to_terminal_ours */
645 child_terminal_info, /* to_terminal_info */
646 child_kill_inferior, /* to_kill */
647 0, /* to_load */
648 0, /* to_lookup_symbol */
649 child_create_inferior, /* to_create_inferior */
650 child_mourn_inferior, /* to_mourn_inferior */
651 child_can_run, /* to_can_run */
652 0, /* to_notice_signals */
653 0, /* to_thread_alive */
654 child_stop, /* to_stop */
655 process_stratum, /* to_stratum */
656 0, /* to_next */
657 1, /* to_has_all_memory */
658 1, /* to_has_memory */
659 1, /* to_has_stack */
660 1, /* to_has_registers */
661 1, /* to_has_execution */
662 0, /* to_sections */
663 0, /* to_sections_end */
664 OPS_MAGIC /* to_magic */
665 };
666
667 void
668 _initialize_inftarg ()
669 {
670 add_show_from_set
671 (add_set_cmd ("new-console", class_support, var_boolean,
672 (char *) &new_console,
673 "Set creation of new console when creating child process.",
674 &setlist),
675 &showlist);
676
677 add_show_from_set
678 (add_set_cmd ("new-group", class_support, var_boolean,
679 (char *) &new_group,
680 "Set creation of new group when creating child process.",
681 &setlist),
682 &showlist);
683
684 add_target (&child_ops);
685 }