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. */
22 /* by Steve Chamberlain, sac@cygnus.com */
25 #include "frame.h" /* required by inferior.h */
32 #include <sys/types.h>
36 #include "gdb_string.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 {EXCEPTION_BREAKPOINT
, TARGET_SIGNAL_TRAP
},
131 {DBG_CONTROL_C
, TARGET_SIGNAL_INT
},
132 {EXCEPTION_SINGLE_STEP
, TARGET_SIGNAL_TRAP
},
137 check (BOOL ok
, const char *file
, int line
)
140 printf_filtered ("error return %s:%d was %d\n", file
, line
, GetLastError ());
144 child_fetch_inferior_registers (int r
)
148 for (r
= 0; r
< NUM_REGS
; r
++)
149 child_fetch_inferior_registers (r
);
153 supply_register (r
, mappings
[r
].incontext
);
158 child_store_inferior_registers (int r
)
162 for (r
= 0; r
< NUM_REGS
; r
++)
163 child_store_inferior_registers (r
);
167 read_register_gen (r
, mappings
[r
].incontext
);
172 /* Wait for child to do something. Return pid of child, or -1 in case
173 of error; store status through argument pointer OURSTATUS. */
177 handle_load_dll (DEBUG_EVENT
* event
)
182 ReadProcessMemory (current_process
,
183 (DWORD
) event
->u
.LoadDll
.lpImageName
,
184 (char *) &dll_name_ptr
,
185 sizeof (dll_name_ptr
), &done
);
187 /* See if we could read the address of a string, and that the
188 address isn't null. */
190 if (done
== sizeof (dll_name_ptr
) && dll_name_ptr
)
193 int size
= event
->u
.LoadDll
.fUnicode
? sizeof (WCHAR
) : sizeof (char);
198 ReadProcessMemory (current_process
,
199 dll_name_ptr
+ len
* size
,
205 while ((b
[0] != 0 || b
[size
- 1] != 0) && done
== size
);
208 dll_name
= alloca (len
);
210 if (event
->u
.LoadDll
.fUnicode
)
212 WCHAR
*unicode_dll_name
= (WCHAR
*) alloca (len
* sizeof (WCHAR
));
213 ReadProcessMemory (current_process
,
216 len
* sizeof (WCHAR
),
219 WideCharToMultiByte (CP_ACP
, 0,
220 unicode_dll_name
, len
,
221 dll_name
, len
, 0, 0);
225 ReadProcessMemory (current_process
,
232 /* FIXME!! It would be nice to define one symbol which pointed to the
233 front of the dll if we can't find any symbols. */
235 context
.ContextFlags
= CONTEXT_FULL
;
236 GetThreadContext (current_thread
, &context
);
238 symbol_file_add (dll_name
, 0, (int) event
->u
.LoadDll
.lpBaseOfDll
, 0, 0, 0);
240 /* We strip off the path of the dll for tidiness. */
241 if (strrchr (dll_name
, '\\'))
242 dll_name
= strrchr (dll_name
, '\\') + 1;
243 printf_unfiltered ("%x:%s\n", event
->u
.LoadDll
.lpBaseOfDll
, dll_name
);
249 handle_exception (DEBUG_EVENT
* event
, struct target_waitstatus
*ourstatus
)
253 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
255 for (i
= 0; !done
&& xlate
[i
].us
> 0; i
++)
257 if (xlate
[i
].them
== event
->u
.Exception
.ExceptionRecord
.ExceptionCode
)
259 ourstatus
->value
.sig
= xlate
[i
].us
;
267 printf_unfiltered ("Want to know about exception code %08x\n",
268 event
->u
.Exception
.ExceptionRecord
.ExceptionCode
);
269 ourstatus
->value
.sig
= TARGET_SIGNAL_UNKNOWN
;
271 context
.ContextFlags
= CONTEXT_FULL
;
272 GetThreadContext (current_thread
, &context
);
277 child_wait (int pid
, struct target_waitstatus
*ourstatus
)
279 /* We loop when we get a non-standard exception rather than return
280 with a SPURIOUS because resume can try and step or modify things,
281 which needs a current_thread. But some of these exceptions mark
282 the birth or death of threads, which mean that the current thread
283 isn't necessarily what you think it is. */
288 BOOL t
= WaitForDebugEvent (&event
, INFINITE
);
290 DEBUG (("%d = WaitForDebugEvent() code=%d pid=%d tid=%d)\n",
292 event
.dwDebugEventCode
,
298 current_thread_id
= event
.dwThreadId
;
299 current_process_id
= event
.dwProcessId
;
301 switch (event
.dwDebugEventCode
)
303 case CREATE_THREAD_DEBUG_EVENT
:
304 case EXIT_THREAD_DEBUG_EVENT
:
305 case CREATE_PROCESS_DEBUG_EVENT
:
308 case EXIT_PROCESS_DEBUG_EVENT
:
309 ourstatus
->kind
= TARGET_WAITKIND_EXITED
;
310 ourstatus
->value
.integer
= event
.u
.ExitProcess
.dwExitCode
;
311 CloseHandle (current_process
);
312 CloseHandle (current_thread
);
313 return current_process_id
;
316 case LOAD_DLL_DEBUG_EVENT
:
317 handle_load_dll (&event
);
319 case EXCEPTION_DEBUG_EVENT
:
320 handle_exception (&event
, ourstatus
);
321 return current_process_id
;
323 printf_unfiltered ("waitfor it %d %d %d %d\n", t
,
324 event
.dwDebugEventCode
,
329 CHECK (ContinueDebugEvent (current_process_id
,
338 /* Attach to process PID, then initialize for debugging it. */
341 child_attach (args
, from_tty
)
348 error_no_arg ("process-id to attach");
350 current_process_id
= strtoul (args
, 0, 0);
352 ok
= DebugActiveProcess (current_process_id
);
355 error ("Can't attach to process.");
363 char *exec_file
= (char *) get_exec_file (0);
366 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file
,
367 target_pid_to_str (current_process_id
));
369 printf_unfiltered ("Attaching to %s\n",
370 target_pid_to_str (current_process_id
));
372 gdb_flush (gdb_stdout
);
375 inferior_pid
= current_process_id
;
376 push_target (&child_ops
);
381 child_detach (args
, from_tty
)
387 char *exec_file
= get_exec_file (0);
390 printf_unfiltered ("Detaching from program: %s %s\n", exec_file
,
391 target_pid_to_str (inferior_pid
));
392 gdb_flush (gdb_stdout
);
395 unpush_target (&child_ops
);
399 /* Print status information about what we're accessing. */
402 child_files_info (ignore
)
403 struct target_ops
*ignore
;
405 printf_unfiltered ("\tUsing the running image of %s %s.\n",
406 attach_flag
? "attached" : "child", target_pid_to_str (inferior_pid
));
411 child_open (arg
, from_tty
)
415 error ("Use the \"run\" command to start a Unix child process.");
418 /* Stub function which causes the inferior that runs it, to be ptrace-able
419 by its parent process. */
422 /* Start an inferior Unix child process and sets inferior_pid to its pid.
423 EXEC_FILE is the file to run.
424 ALLARGS is a string containing the arguments to the program.
425 ENV is the environment vector to pass. Errors reported with error(). */
429 child_create_inferior (exec_file
, allargs
, env
)
436 PROCESS_INFORMATION pi
;
437 struct target_waitstatus dummy
;
443 error ("No executable specified, use `target exec'.\n");
446 memset (&si
, 0, sizeof (si
));
449 /* A realpath is always the same size, or a bit shorter than a nice path. */
450 real_path
= alloca (strlen (exec_file
) + 1);
451 path_to_real_path (exec_file
, real_path
);
453 flags
= DEBUG_ONLY_THIS_PROCESS
| DEBUG_PROCESS
;
456 flags
|= CREATE_NEW_PROCESS_GROUP
;
459 flags
|= CREATE_NEW_CONSOLE
;
461 ret
= CreateProcess (real_path
,
465 TRUE
, /* inherit handles */
466 flags
, /* start flags */
468 NULL
, /* current directory */
472 error ("Error creating process %s\n", exec_file
);
477 inferior_pid
= pi
.dwProcessId
;
478 current_process
= pi
.hProcess
;
479 current_thread
= pi
.hThread
;
480 current_process_id
= pi
.dwProcessId
;
481 current_thread_id
= pi
.dwThreadId
;
482 push_target (&child_ops
);
484 init_wait_for_inferior ();
485 clear_proceed_status ();
486 target_terminal_init ();
487 target_terminal_inferior ();
489 /* Ignore the first trap */
490 child_wait (inferior_pid
, &dummy
);
492 proceed ((CORE_ADDR
) - 1, TARGET_SIGNAL_0
, 0);
496 child_mourn_inferior ()
498 unpush_target (&child_ops
);
499 generic_mourn_inferior ();
503 /* Send a SIGINT to the process group. This acts just like the user typed a
504 ^C on the controlling terminal. */
509 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT
, 0));
513 child_xfer_memory (CORE_ADDR memaddr
, char *our
, int len
, int write
, struct target_ops
*target
)
518 WriteProcessMemory (current_process
, memaddr
, our
, len
, &done
);
519 FlushInstructionCache (current_process
, memaddr
, len
);
523 ReadProcessMemory (current_process
, memaddr
, our
, len
, &done
);
529 child_kill_inferior (void)
531 CHECK (TerminateProcess (current_process
, 0));
532 CHECK (CloseHandle (current_process
));
533 CHECK (CloseHandle (current_thread
));
537 child_resume (int pid
, int step
, enum target_signal signal
)
539 DEBUG (("child_resume (%d, %d, %d);\n", pid
, step
, signal
));
543 /* Single step by setting t bit */
544 child_fetch_inferior_registers (PS_REGNUM
);
545 context
.EFlags
|= FLAG_TRACE_BIT
;
548 if (context
.ContextFlags
)
550 CHECK (SetThreadContext (current_thread
, &context
));
551 context
.ContextFlags
= 0;
556 fprintf_unfiltered (gdb_stderr
, "Can't send signals to the child.\n");
559 CHECK (ContinueDebugEvent (current_process_id
,
565 child_prepare_to_store ()
567 /* Do nothing, since we can store individual regs */
581 struct target_ops child_ops
=
583 "child", /* to_shortname */
584 "Win32 child process", /* to_longname */
585 "Win32 child process (started by the \"run\" command).", /* to_doc */
586 child_open
, /* to_open */
587 child_close
, /* to_close */
588 child_attach
, /* to_attach */
589 child_detach
, /* to_detach */
590 child_resume
, /* to_resume */
591 child_wait
, /* to_wait */
592 child_fetch_inferior_registers
,/* to_fetch_registers */
593 child_store_inferior_registers
,/* to_store_registers */
594 child_prepare_to_store
, /* to_child_prepare_to_store */
595 child_xfer_memory
, /* to_xfer_memory */
596 child_files_info
, /* to_files_info */
597 memory_insert_breakpoint
, /* to_insert_breakpoint */
598 memory_remove_breakpoint
, /* to_remove_breakpoint */
599 terminal_init_inferior
, /* to_terminal_init */
600 terminal_inferior
, /* to_terminal_inferior */
601 terminal_ours_for_output
, /* to_terminal_ours_for_output */
602 terminal_ours
, /* to_terminal_ours */
603 child_terminal_info
, /* to_terminal_info */
604 child_kill_inferior
, /* to_kill */
606 0, /* to_lookup_symbol */
607 child_create_inferior
, /* to_create_inferior */
608 child_mourn_inferior
, /* to_mourn_inferior */
609 child_can_run
, /* to_can_run */
610 0, /* to_notice_signals */
611 0, /* to_thread_alive */
612 child_stop
, /* to_stop */
613 process_stratum
, /* to_stratum */
615 1, /* to_has_all_memory */
616 1, /* to_has_memory */
617 1, /* to_has_stack */
618 1, /* to_has_registers */
619 1, /* to_has_execution */
621 0, /* to_sections_end */
622 OPS_MAGIC
/* to_magic */
626 _initialize_inftarg ()
629 (add_set_cmd ("new-console", class_support
, var_boolean
,
630 (char *) &new_console
,
631 "Set creation of new console when creating child process.",
636 (add_set_cmd ("new-group", class_support
, var_boolean
,
638 "Set creation of new group when creating child process.",
642 add_target (&child_ops
);