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 {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 (DEBUG_EVENT
* event
)
183 ReadProcessMemory (current_process
,
184 (DWORD
) event
->u
.LoadDll
.lpImageName
,
185 (char *) &dll_name_ptr
,
186 sizeof (dll_name_ptr
), &done
);
188 /* See if we could read the address of a string, and that the
189 address isn't null. */
191 if (done
== sizeof (dll_name_ptr
) && dll_name_ptr
)
194 int size
= event
->u
.LoadDll
.fUnicode
? sizeof (WCHAR
) : sizeof (char);
199 ReadProcessMemory (current_process
,
200 dll_name_ptr
+ len
* size
,
206 while ((b
[0] != 0 || b
[size
- 1] != 0) && done
== size
);
209 dll_name
= alloca (len
);
211 if (event
->u
.LoadDll
.fUnicode
)
213 WCHAR
*unicode_dll_name
= (WCHAR
*) alloca (len
* sizeof (WCHAR
));
214 ReadProcessMemory (current_process
,
217 len
* sizeof (WCHAR
),
220 WideCharToMultiByte (CP_ACP
, 0,
221 unicode_dll_name
, len
,
222 dll_name
, len
, 0, 0);
226 ReadProcessMemory (current_process
,
233 /* FIXME!! It would be nice to define one symbol which pointed to the
234 front of the dll if we can't find any symbols. */
236 context
.ContextFlags
= CONTEXT_FULL
;
237 GetThreadContext (current_thread
, &context
);
239 symbol_file_add (dll_name
, 0, (int) event
->u
.LoadDll
.lpBaseOfDll
, 0, 0, 0);
241 /* We strip off the path of the dll for tidiness. */
242 if (strrchr (dll_name
, '\\'))
243 dll_name
= strrchr (dll_name
, '\\') + 1;
244 printf_unfiltered ("%x:%s\n", event
->u
.LoadDll
.lpBaseOfDll
, dll_name
);
250 handle_exception (DEBUG_EVENT
* event
, struct target_waitstatus
*ourstatus
)
254 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
256 for (i
= 0; !done
&& xlate
[i
].us
> 0; i
++)
258 if (xlate
[i
].them
== event
->u
.Exception
.ExceptionRecord
.ExceptionCode
)
260 ourstatus
->value
.sig
= xlate
[i
].us
;
268 printf_unfiltered ("Want to know about exception code %08x\n",
269 event
->u
.Exception
.ExceptionRecord
.ExceptionCode
);
270 ourstatus
->value
.sig
= TARGET_SIGNAL_UNKNOWN
;
272 context
.ContextFlags
= CONTEXT_FULL
;
273 GetThreadContext (current_thread
, &context
);
278 child_wait (int pid
, struct target_waitstatus
*ourstatus
)
280 /* We loop when we get a non-standard exception rather than return
281 with a SPURIOUS because resume can try and step or modify things,
282 which needs a current_thread. But some of these exceptions mark
283 the birth or death of threads, which mean that the current thread
284 isn't necessarily what you think it is. */
289 BOOL t
= WaitForDebugEvent (&event
, INFINITE
);
291 DEBUG (("%d = WaitForDebugEvent() code=%d pid=%d tid=%d)\n",
293 event
.dwDebugEventCode
,
299 current_thread_id
= event
.dwThreadId
;
300 current_process_id
= event
.dwProcessId
;
302 switch (event
.dwDebugEventCode
)
304 case CREATE_THREAD_DEBUG_EVENT
:
305 case EXIT_THREAD_DEBUG_EVENT
:
306 case CREATE_PROCESS_DEBUG_EVENT
:
309 case EXIT_PROCESS_DEBUG_EVENT
:
310 ourstatus
->kind
= TARGET_WAITKIND_EXITED
;
311 ourstatus
->value
.integer
= event
.u
.ExitProcess
.dwExitCode
;
312 CloseHandle (current_process
);
313 CloseHandle (current_thread
);
314 return current_process_id
;
317 case LOAD_DLL_DEBUG_EVENT
:
318 handle_load_dll (&event
);
320 case EXCEPTION_DEBUG_EVENT
:
321 handle_exception (&event
, ourstatus
);
322 return current_process_id
;
324 printf_unfiltered ("waitfor it %d %d %d %d\n", t
,
325 event
.dwDebugEventCode
,
330 CHECK (ContinueDebugEvent (current_process_id
,
339 /* Attach to process PID, then initialize for debugging it. */
342 child_attach (args
, from_tty
)
349 error_no_arg ("process-id to attach");
351 current_process_id
= strtoul (args
, 0, 0);
353 ok
= DebugActiveProcess (current_process_id
);
356 error ("Can't attach to process.");
364 char *exec_file
= (char *) get_exec_file (0);
367 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file
,
368 target_pid_to_str (current_process_id
));
370 printf_unfiltered ("Attaching to %s\n",
371 target_pid_to_str (current_process_id
));
373 gdb_flush (gdb_stdout
);
376 inferior_pid
= current_process_id
;
377 push_target (&child_ops
);
382 child_detach (args
, from_tty
)
388 char *exec_file
= get_exec_file (0);
391 printf_unfiltered ("Detaching from program: %s %s\n", exec_file
,
392 target_pid_to_str (inferior_pid
));
393 gdb_flush (gdb_stdout
);
396 unpush_target (&child_ops
);
400 /* Print status information about what we're accessing. */
403 child_files_info (ignore
)
404 struct target_ops
*ignore
;
406 printf_unfiltered ("\tUsing the running image of %s %s.\n",
407 attach_flag
? "attached" : "child", target_pid_to_str (inferior_pid
));
412 child_open (arg
, from_tty
)
416 error ("Use the \"run\" command to start a Unix child process.");
420 /* Start an inferior win32 child process and sets inferior_pid to its pid.
421 EXEC_FILE is the file to run.
422 ALLARGS is a string containing the arguments to the program.
423 ENV is the environment vector to pass. Errors reported with error(). */
427 child_create_inferior (exec_file
, allargs
, env
)
434 PROCESS_INFORMATION pi
;
435 struct target_waitstatus dummy
;
442 error ("No executable specified, use `target exec'.\n");
445 memset (&si
, 0, sizeof (si
));
448 /* A realpath is always the same size, or a bit shorter than a nice path. */
449 real_path
= alloca (strlen (exec_file
) + 1);
450 path_to_real_path (exec_file
, real_path
);
452 flags
= DEBUG_ONLY_THIS_PROCESS
| DEBUG_PROCESS
;
455 flags
|= CREATE_NEW_PROCESS_GROUP
;
458 flags
|= CREATE_NEW_CONSOLE
;
460 args
= alloca (strlen (exec_file
) + strlen (allargs
) + 2);
462 strcpy (args
, exec_file
);
464 strcat (args
, allargs
);
466 ret
= CreateProcess (real_path
,
470 TRUE
, /* inherit handles */
471 flags
, /* start flags */
473 NULL
, /* current directory */
477 error ("Error creating process %s, (error %d)\n", exec_file
, GetLastError());
482 inferior_pid
= pi
.dwProcessId
;
483 current_process
= pi
.hProcess
;
484 current_thread
= pi
.hThread
;
485 current_process_id
= pi
.dwProcessId
;
486 current_thread_id
= pi
.dwThreadId
;
487 push_target (&child_ops
);
489 init_wait_for_inferior ();
490 clear_proceed_status ();
491 target_terminal_init ();
492 target_terminal_inferior ();
494 /* Ignore the first trap */
495 child_wait (inferior_pid
, &dummy
);
497 proceed ((CORE_ADDR
) - 1, TARGET_SIGNAL_0
, 0);
501 child_mourn_inferior ()
503 unpush_target (&child_ops
);
504 generic_mourn_inferior ();
508 /* Send a SIGINT to the process group. This acts just like the user typed a
509 ^C on the controlling terminal. */
514 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT
, 0));
518 child_xfer_memory (CORE_ADDR memaddr
, char *our
, int len
,
519 int write
, struct target_ops
*target
)
524 WriteProcessMemory (current_process
, memaddr
, our
, len
, &done
);
525 FlushInstructionCache (current_process
, memaddr
, len
);
529 ReadProcessMemory (current_process
, memaddr
, our
, len
, &done
);
535 child_kill_inferior (void)
537 CHECK (TerminateProcess (current_process
, 0));
538 CHECK (CloseHandle (current_process
));
539 CHECK (CloseHandle (current_thread
));
543 child_resume (int pid
, int step
, enum target_signal signal
)
545 DEBUG (("child_resume (%d, %d, %d);\n", pid
, step
, signal
));
549 /* Single step by setting t bit */
550 child_fetch_inferior_registers (PS_REGNUM
);
551 context
.EFlags
|= FLAG_TRACE_BIT
;
554 if (context
.ContextFlags
)
556 CHECK (SetThreadContext (current_thread
, &context
));
557 context
.ContextFlags
= 0;
562 fprintf_unfiltered (gdb_stderr
, "Can't send signals to the child.\n");
565 CHECK (ContinueDebugEvent (current_process_id
,
571 child_prepare_to_store ()
573 /* Do nothing, since we can store individual regs */
587 struct target_ops child_ops
=
589 "child", /* to_shortname */
590 "Win32 child process", /* to_longname */
591 "Win32 child process (started by the \"run\" command).", /* to_doc */
592 child_open
, /* to_open */
593 child_close
, /* to_close */
594 child_attach
, /* to_attach */
595 child_detach
, /* to_detach */
596 child_resume
, /* to_resume */
597 child_wait
, /* to_wait */
598 child_fetch_inferior_registers
,/* to_fetch_registers */
599 child_store_inferior_registers
,/* to_store_registers */
600 child_prepare_to_store
, /* to_child_prepare_to_store */
601 child_xfer_memory
, /* to_xfer_memory */
602 child_files_info
, /* to_files_info */
603 memory_insert_breakpoint
, /* to_insert_breakpoint */
604 memory_remove_breakpoint
, /* to_remove_breakpoint */
605 terminal_init_inferior
, /* to_terminal_init */
606 terminal_inferior
, /* to_terminal_inferior */
607 terminal_ours_for_output
, /* to_terminal_ours_for_output */
608 terminal_ours
, /* to_terminal_ours */
609 child_terminal_info
, /* to_terminal_info */
610 child_kill_inferior
, /* to_kill */
612 0, /* to_lookup_symbol */
613 child_create_inferior
, /* to_create_inferior */
614 child_mourn_inferior
, /* to_mourn_inferior */
615 child_can_run
, /* to_can_run */
616 0, /* to_notice_signals */
617 0, /* to_thread_alive */
618 child_stop
, /* to_stop */
619 process_stratum
, /* to_stratum */
621 1, /* to_has_all_memory */
622 1, /* to_has_memory */
623 1, /* to_has_stack */
624 1, /* to_has_registers */
625 1, /* to_has_execution */
627 0, /* to_sections_end */
628 OPS_MAGIC
/* to_magic */
632 _initialize_inftarg ()
635 (add_set_cmd ("new-console", class_support
, var_boolean
,
636 (char *) &new_console
,
637 "Set creation of new console when creating child process.",
642 (add_set_cmd ("new-group", class_support
, var_boolean
,
644 "Set creation of new group when creating child process.",
648 add_target (&child_ops
);