OSDN Git Service

* server.c (main): Set ``server_quit_p'' when debugged process
[pf3gnuchains/pf3gnuchains3x.git] / rda / win32 / child_process.cc
1 /* child_process.cc
2
3    Copyright 2000, 2002 Red Hat, Inc.
4
5    This file is part of RDA, the Red Hat Debug Agent (and library).
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 even the 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    Alternative licenses for RDA may be arranged by contacting Red Hat,
23    Inc.  */
24
25 #include "config.h"
26
27 #include <limits.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #if !HAVE_WINDOWS_H
34 #error The windows.h header is required when compiling for a Win32 target.
35 #endif
36 #include <windows.h>
37 #include <sys/cygwin.h>
38
39 #include "server.h"
40
41 struct {
42   DWORD exc;
43   const char *exc_txt;
44   DWORD sig;
45 } sigmap[] = {
46   EXCEPTION_ACCESS_VIOLATION,      "EXCEPTION_ACCESS_VIOLATION",        SIGSEGV,
47   EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "EXCEPTION_ARRAY_BOUNDS_EXCEEDED",   SIGSEGV,
48   EXCEPTION_BREAKPOINT,            "EXCEPTION_BREAKPOINT",              SIGTRAP,
49   EXCEPTION_DATATYPE_MISALIGNMENT, "EXCEPTION_DATATYPE_MISALIGNMENT",   SIGBUS,
50   EXCEPTION_FLT_DENORMAL_OPERAND,  "EXCEPTION_FLT_DENORMAL_OPERAND",    SIGFPE,
51   EXCEPTION_FLT_DIVIDE_BY_ZERO,    "EXCEPTION_FLT_DIVIDE_BY_ZERO",      SIGFPE,
52   EXCEPTION_FLT_INEXACT_RESULT,    "EXCEPTION_FLT_INEXACT_RESULT",      SIGFPE,
53   EXCEPTION_FLT_INVALID_OPERATION, "EXCEPTION_FLT_INVALID_OPERATION",   SIGILL,
54   EXCEPTION_FLT_OVERFLOW,          "EXCEPTION_FLT_OVERFLOW",            SIGFPE,
55   EXCEPTION_FLT_STACK_CHECK,       "EXCEPTION_FLT_STACK_CHECK",         SIGFPE,
56   EXCEPTION_FLT_UNDERFLOW,         "EXCEPTION_FLT_UNDERFLOW",           SIGFPE,
57   EXCEPTION_ILLEGAL_INSTRUCTION,   "EXCEPTION_ILLEGAL_INSTRUCTION",     SIGILL,
58   EXCEPTION_IN_PAGE_ERROR,         "EXCEPTION_IN_PAGE_ERROR",           SIGSEGV,
59   EXCEPTION_INT_DIVIDE_BY_ZERO,    "EXCEPTION_INT_DIVIDE_BY_ZERO",      SIGFPE,
60   EXCEPTION_INT_OVERFLOW,          "EXCEPTION_INT_OVERFLOW",            SIGFPE,
61   EXCEPTION_INVALID_DISPOSITION,   "EXCEPTION_INVALID_DISPOSITION",     SIGILL,
62   EXCEPTION_NONCONTINUABLE_EXCEPTION,
63                                    "EXCEPTION_NONCONTINUABLE_EXCEPTION",SIGILL,
64   EXCEPTION_PRIV_INSTRUCTION,      "EXCEPTION_PRIV_INSTRUCTION",        SIGILL,
65   EXCEPTION_SINGLE_STEP,           "EXCEPTION_SINGLE_STEP",             SIGTRAP,
66   EXCEPTION_STACK_OVERFLOW,        "EXCEPTION_STACK_OVERFLOW",          SIGSEGV,
67   DBG_CONTROL_C,                   "DBG_CONTROL_C",                     SIGINT,
68   0,                               "Unknown exception",                 SIGUSR1
69 };
70
71 /* Debug output method similar to fprintf. */
72 void
73 child_process::debug (const char *format, ...)
74 {
75   if (!debug_backend)
76     return;
77   
78   va_list ap;
79
80   va_start (ap, format);
81   vfprintf (stderr, format, ap);
82   va_end (ap);
83 }
84
85 void
86 child_process::handle_exception (DEBUG_EVENT &ev)
87 {
88   DWORD exc_code = ev.u.Exception.ExceptionRecord.ExceptionCode;
89   DWORD exc_flag = ev.u.Exception.ExceptionRecord.ExceptionFlags;
90
91   int i;
92   for (i = 0; sigmap[i].exc && sigmap[i].exc != exc_code; ++i)
93     ;
94
95   debug ("Win32: Got exception 0x%08x = \"%s\", mapped to signal %d\n",
96                   exc_code, sigmap[i].exc_txt, sigmap[i].sig);
97
98   if (exc_flag == EXCEPTION_NONCONTINUABLE)
99     set_term (sigmap[i].sig);
100   else
101     set_break (sigmap[i].sig);
102 }
103
104 /* fetch registers vector. */
105 void
106 child_process::fetch_regs ()
107 {
108   if (!suspend_cnt)
109     {
110       HANDLE thread_hdl = threads[cur_thread_id];
111       suspend_cnt = SuspendThread (thread_hdl) + 1;
112       context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
113       GetThreadContext (thread_hdl, &context);
114     }
115 }
116
117 void
118 child_process::store_regs ()
119 {
120   SetThreadContext (threads[cur_thread_id], &context);
121 }
122
123 BOOL
124 child_process::resume_program (BOOL step)
125 {
126   fetch_regs ();
127
128   if (step)
129     context.EFlags |= FLAG_TRACE_BIT;
130
131   store_regs ();
132
133   if (ContinueDebugEvent (cur_process_id,
134                           cur_thread_id,
135                           stop_signal () && stop_signal () != SIGTRAP
136                           ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE))
137     {
138       int i;
139
140       for (i = 0; i < suspend_cnt; ++i)
141         ResumeThread (threads[cur_thread_id]);
142       suspend_cnt = 0;
143       set_running ();
144       return TRUE;
145     }
146   return FALSE;
147 }
148
149 void
150 child_process::load_dll_event (DEBUG_EVENT &ev)
151 {
152   void *ptr;
153   char buf[512];
154   DWORD processed = 0;
155
156   if (!debug ())
157     return;
158
159   if (ev.dwProcessId == process_id
160       && ev.u.LoadDll.lpImageName
161       && ReadProcessMemory (process_hdl, ev.u.LoadDll.lpImageName,
162                             &ptr, sizeof ptr, &processed)
163       && ptr
164       && ReadProcessMemory (process_hdl, ptr, 
165                             buf, sizeof buf, &processed))
166     {
167       buf[511] = '\0';
168       char *name = buf;
169       if (ev.u.LoadDll.fUnicode)
170         {
171           name = (char *) alloca (256);
172           WideCharToMultiByte (CP_ACP, 0, (const WCHAR *) buf, -1,
173                                name, 256, NULL, NULL);
174         }
175       debug ("Win32: Load DLL \"%s\"\n", name);
176     }
177   else
178     debug ("Win32: Load DLL\n");
179 }
180
181 BOOL
182 child_process::create_child ()
183 {
184   char real_path[PATH_MAX];
185   char *winenv;
186   char *temp;
187   int envlen;
188   int len, i;
189   STARTUPINFO si;
190   PROCESS_INFORMATION pi;
191   BOOL ret;
192   DWORD flags;
193   char *args;
194
195   memset (&si, 0, sizeof (si));
196   si.cb = sizeof (si);
197
198   cygwin_conv_to_win32_path (executable, real_path);
199
200   flags = DEBUG_ONLY_THIS_PROCESS;
201
202   if (new_group)
203     flags |= CREATE_NEW_PROCESS_GROUP;
204
205   if (new_console)
206     flags |= CREATE_NEW_CONSOLE;
207
208   len = strlen (real_path);
209   for (i = 1; i < argc; ++i)
210     len += strlen (argv[i]) + 1;
211   
212   args = (char *) alloca (len + 2);
213
214   strcpy (args, real_path);
215
216   for (i = 1; i < argc; ++i)
217     {
218       strcat (args, " ");
219       strcat (args, argv[i]);
220     }
221
222   SetConsoleCtrlHandler (NULL, 0);
223   ret = CreateProcess (0,
224                        args,    /* command line */
225                        NULL,    /* Security */
226                        NULL,    /* thread */
227                        TRUE,    /* inherit handles */
228                        flags,   /* start flags */
229                        NULL,
230                        NULL,    /* current directory */
231                        &si,
232                        &pi);
233   if (!ret)
234     return FALSE;
235
236   process_id = pi.dwProcessId;
237
238   return TRUE;
239 }
240
241 int
242 child_process::check_state ()
243 {
244   static DEBUG_EVENT ev;
245
246 #if 0
247   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
248 #endif
249
250   if (!WaitForDebugEvent (&ev, 1000))
251     return 0;
252
253   /* found an event */
254
255   cur_process_id = ev.dwProcessId;
256   cur_thread_id = ev.dwThreadId;
257
258   fetch_regs ();
259
260   switch (ev.dwDebugEventCode)
261     {
262     case CREATE_PROCESS_DEBUG_EVENT:
263       if (ev.dwProcessId != process_id)
264         {
265           debug ("Win32: Inferior process created\n");
266           set_break (SIGTRAP);
267           return 1;
268         }
269       else
270         debug ("Win32: A child process was created\n");
271       process_hdl = ev.u.CreateProcessInfo.hProcess;
272       threads += ev;
273       break;
274
275     case CREATE_THREAD_DEBUG_EVENT:
276       debug ("Win32: Create Thread\n");
277       if (ev.dwProcessId == process_id)
278         threads += ev;
279       break;
280
281     case LOAD_DLL_DEBUG_EVENT:
282       load_dll_event (ev);
283       break;
284
285     case UNLOAD_DLL_DEBUG_EVENT:
286       debug ("Win32: Unload DLL\n");
287       break;
288
289     case OUTPUT_DEBUG_STRING_EVENT:
290       debug ("Win32: OutputDebugString\n");
291       if (ev.dwProcessId == process_id
292           && win32_output_debug_string (this, ev))
293         return 1;
294       break;
295
296     case EXIT_PROCESS_DEBUG_EVENT:
297       if (ev.dwProcessId == process_id)
298         {
299           debug ("Win32: Inferior exited with retcode = %d\n",
300                           ev.u.ExitProcess.dwExitCode);
301           set_exit (ev.u.ExitProcess.dwExitCode);
302           return 1;
303         }
304       else
305         debug ("Win32: Some child exited with retcode = %d\n",
306                         ev.u.ExitProcess.dwExitCode);
307       break;
308
309     case EXIT_THREAD_DEBUG_EVENT:
310       debug ("Win32: Thread exited with retcode = %d\n",
311                ev.u.ExitThread.dwExitCode);
312       threads -= ev;
313       /* What to return??? */
314       break;
315
316     case EXCEPTION_DEBUG_EVENT:
317       handle_exception (ev);
318       return 1;
319     }
320
321   if (!resume_program (FALSE))
322     {
323       set_term (SIGILL);
324       return 1;
325     }
326   return 0;
327 }
328
329 void
330 child_process::fromtarget_break ()
331 {
332   debug ("Win32: from_target break\n");
333   gdbserv_fromtarget_break (serv, stop_signal ());
334 }
335
336 void
337 child_process::fromtarget_exit ()
338 {
339   debug ("Win32: from_target exit\n");
340   gdbserv_fromtarget_exit (serv, exit_code ());
341 }
342
343 void
344 child_process::fromtarget_terminate ()
345 {
346   debug ("Win32: from_target terminate\n");
347   gdbserv_fromtarget_terminate (serv, term_signal ());
348 }
349