1 /* Target-vector operations for controlling win32 child processes, for GDB.
3 Free Software Foundation, Inc.
5 Contributed by Cygnus Support.
6 This file is part of GDB.
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.
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.
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. */
25 #include "frame.h" /* required by inferior.h */
32 #include <sys/types.h>
36 #include "gdb_string.h"
39 #include <sys/param.h>
40 #define CHECK(x) check (x, __FILE__,__LINE__)
41 #define DEBUG(x) if (remote_debug) printf x
44 /* Forward declaration */
45 extern struct target_ops child_ops;
47 /* The most recently read context. Inspect ContextFlags to see what
50 static CONTEXT context;
52 /* The process and thread handles for the above context. */
54 static HANDLE current_process;
55 static HANDLE current_thread;
56 static int current_process_id;
57 static int current_thread_id;
59 /* Counts of things. */
60 static int exception_count = 0;
61 static int event_count = 0;
64 static int new_console = 0;
65 static int new_group = 0;
67 /* This vector maps GDB's idea of a register's number into an address
68 in the win32 exception context vector.
70 It also contains the bit mask needed to load the register in question.
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
86 static const struct regmappings
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},
116 /* This vector maps the target's idea of an exception (extracted
117 from the DEBUG_EVENT structure) to GDB's idea. */
119 struct xlate_exception
122 enum target_signal us;
126 static const struct xlate_exception
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},
138 check (BOOL ok, const char *file, int line)
141 printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
145 child_fetch_inferior_registers (int r)
149 for (r = 0; r < NUM_REGS; r++)
150 child_fetch_inferior_registers (r);
154 supply_register (r, mappings[r].incontext);
159 child_store_inferior_registers (int r)
163 for (r = 0; r < NUM_REGS; r++)
164 child_store_inferior_registers (r);
168 read_register_gen (r, mappings[r].incontext);
173 /* Wait for child to do something. Return pid of child, or -1 in case
174 of error; store status through argument pointer OURSTATUS. */
178 handle_load_dll (char *eventp)
180 DEBUG_EVENT * event = (DEBUG_EVENT *)eventp;
184 ReadProcessMemory (current_process,
185 (DWORD) event->u.LoadDll.lpImageName,
186 (char *) &dll_name_ptr,
187 sizeof (dll_name_ptr), &done);
189 /* See if we could read the address of a string, and that the
190 address isn't null. */
192 if (done == sizeof (dll_name_ptr) && dll_name_ptr)
195 int size = event->u.LoadDll.fUnicode ? sizeof (WCHAR) : sizeof (char);
200 ReadProcessMemory (current_process,
201 dll_name_ptr + len * size,
207 while ((b[0] != 0 || b[size - 1] != 0) && done == size);
210 dll_name = alloca (len);
212 if (event->u.LoadDll.fUnicode)
214 WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR));
215 ReadProcessMemory (current_process,
218 len * sizeof (WCHAR),
221 WideCharToMultiByte (CP_ACP, 0,
222 unicode_dll_name, len,
223 dll_name, len, 0, 0);
227 ReadProcessMemory (current_process,
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. */
237 context.ContextFlags = CONTEXT_FULL;
238 GetThreadContext (current_thread, &context);
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.
244 FIXME: Is this the real reason that we need the 0x1000 ? */
247 symbol_file_add (dll_name, 0,
248 (int) event->u.LoadDll.lpBaseOfDll + 0x1000, 0, 0, 0);
250 /* We strip off the path of the dll for tidiness. */
251 if (strrchr (dll_name, '\\'))
252 dll_name = strrchr (dll_name, '\\') + 1;
254 printf_unfiltered ("%x:%s\n", event->u.LoadDll.lpBaseOfDll, dll_name);
261 handle_exception (DEBUG_EVENT * event, struct target_waitstatus *ourstatus)
265 ourstatus->kind = TARGET_WAITKIND_STOPPED;
267 for (i = 0; !done && xlate[i].us > 0; i++)
269 if (xlate[i].them == event->u.Exception.ExceptionRecord.ExceptionCode)
271 ourstatus->value.sig = xlate[i].us;
279 printf_unfiltered ("Want to know about exception code %08x\n",
280 event->u.Exception.ExceptionRecord.ExceptionCode);
281 ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
283 context.ContextFlags = CONTEXT_FULL;
284 GetThreadContext (current_thread, &context);
289 child_wait (int pid, struct target_waitstatus *ourstatus)
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. */
300 BOOL t = WaitForDebugEvent (&event, INFINITE);
302 DEBUG (("%d = WaitForDebugEvent() code=%d pid=%d tid=%d)\n",
304 event.dwDebugEventCode,
310 current_thread_id = event.dwThreadId;
311 current_process_id = event.dwProcessId;
313 switch (event.dwDebugEventCode)
315 case CREATE_THREAD_DEBUG_EVENT:
316 case EXIT_THREAD_DEBUG_EVENT:
317 case CREATE_PROCESS_DEBUG_EVENT:
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;
328 case LOAD_DLL_DEBUG_EVENT:
329 catch_errors (handle_load_dll,
331 "\n[failed reading symbols from DLL]\n",
333 registers_changed(); /* mark all regs invalid */
335 case EXCEPTION_DEBUG_EVENT:
336 handle_exception (&event, ourstatus);
337 return current_process_id;
339 printf_unfiltered ("waitfor it %d %d %d %d\n", t,
340 event.dwDebugEventCode,
345 CHECK (ContinueDebugEvent (current_process_id,
354 /* Attach to process PID, then initialize for debugging it. */
357 child_attach (args, from_tty)
364 error_no_arg ("process-id to attach");
366 current_process_id = strtoul (args, 0, 0);
368 ok = DebugActiveProcess (current_process_id);
371 error ("Can't attach to process.");
379 char *exec_file = (char *) get_exec_file (0);
382 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
383 target_pid_to_str (current_process_id));
385 printf_unfiltered ("Attaching to %s\n",
386 target_pid_to_str (current_process_id));
388 gdb_flush (gdb_stdout);
391 inferior_pid = current_process_id;
392 push_target (&child_ops);
397 child_detach (args, from_tty)
403 char *exec_file = get_exec_file (0);
406 printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
407 target_pid_to_str (inferior_pid));
408 gdb_flush (gdb_stdout);
411 unpush_target (&child_ops);
415 /* Print status information about what we're accessing. */
418 child_files_info (ignore)
419 struct target_ops *ignore;
421 printf_unfiltered ("\tUsing the running image of %s %s.\n",
422 attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
427 child_open (arg, from_tty)
431 error ("Use the \"run\" command to start a Unix child process.");
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(). */
442 child_create_inferior (exec_file, allargs, env)
447 char real_path[MAXPATHLEN];
454 PROCESS_INFORMATION pi;
455 struct target_waitstatus dummy;
462 error ("No executable specified, use `target exec'.\n");
465 memset (&si, 0, sizeof (si));
468 unix_path_to_dos_path (exec_file, real_path);
470 flags = DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS;
473 flags |= CREATE_NEW_PROCESS_GROUP;
476 flags |= CREATE_NEW_CONSOLE;
478 args = alloca (strlen (exec_file) + strlen (allargs) + 2);
480 strcpy (args, exec_file);
482 strcat (args, allargs);
485 /* get total size for env strings */
486 for (envlen = 0, i = 0; env[i] && *env[i]; i++)
487 envlen += strlen(env[i]) + 1;
489 winenv = alloca(envlen + 1); /* allocate new buffer */
491 /* copy env strings into new buffer */
492 for (temp = winenv, i = 0; env[i] && *env[i]; i++)
494 strcpy(temp, env[i]);
495 temp += strlen(temp) + 1;
497 *temp = 0; /* final nil string to terminate new env */
499 strcat (real_path, " ");
500 strcat (real_path, args);
502 ret = CreateProcess (0,
506 TRUE, /* inherit handles */
507 flags, /* start flags */
509 NULL, /* current directory */
513 error ("Error creating process %s, (error %d)\n", exec_file, GetLastError());
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);
525 init_wait_for_inferior ();
526 clear_proceed_status ();
527 target_terminal_init ();
528 target_terminal_inferior ();
530 /* Ignore the first trap */
531 child_wait (inferior_pid, &dummy);
533 proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
537 child_mourn_inferior ()
539 unpush_target (&child_ops);
540 generic_mourn_inferior ();
544 /* Send a SIGINT to the process group. This acts just like the user typed a
545 ^C on the controlling terminal. */
550 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0));
554 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
555 int write, struct target_ops *target)
560 WriteProcessMemory (current_process, memaddr, our, len, &done);
561 FlushInstructionCache (current_process, memaddr, len);
565 ReadProcessMemory (current_process, memaddr, our, len, &done);
571 child_kill_inferior (void)
573 CHECK (TerminateProcess (current_process, 0));
574 CHECK (CloseHandle (current_process));
575 CHECK (CloseHandle (current_thread));
579 child_resume (int pid, int step, enum target_signal signal)
581 DEBUG (("child_resume (%d, %d, %d);\n", pid, step, signal));
585 /* Single step by setting t bit */
586 child_fetch_inferior_registers (PS_REGNUM);
587 context.EFlags |= FLAG_TRACE_BIT;
590 if (context.ContextFlags)
592 CHECK (SetThreadContext (current_thread, &context));
593 context.ContextFlags = 0;
598 fprintf_unfiltered (gdb_stderr, "Can't send signals to the child.\n");
601 CHECK (ContinueDebugEvent (current_process_id,
607 child_prepare_to_store ()
609 /* Do nothing, since we can store individual regs */
623 struct target_ops child_ops =
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 */
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 */
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 */
663 0, /* to_sections_end */
664 OPS_MAGIC /* to_magic */
668 _initialize_inftarg ()
671 (add_set_cmd ("new-console", class_support, var_boolean,
672 (char *) &new_console,
673 "Set creation of new console when creating child process.",
678 (add_set_cmd ("new-group", class_support, var_boolean,
680 "Set creation of new group when creating child process.",
684 add_target (&child_ops);