OSDN Git Service

Add support for the Linux NPTL (New POSIX Thread Library) thread
[pf3gnuchains/pf3gnuchains3x.git] / rda / unix / server.c
1 /* server-main.c
2
3    Copyright 2000, 2001, 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 <stdio.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <ctype.h>
38 #include <termios.h>
39
40 #include "gdbsocket.h"
41 #include "gdbloop.h"
42 #include "gdbserv.h"
43 #include "server.h"
44
45 /* Signal a request to terminate main loop. */
46 int server_quit_p = 0;
47
48 /* FIXME -- move to header file.  */
49 struct gdbserv_target *linux_attach (struct gdbserv* serv, void* data);
50
51 /* We have an empty SIGCHLD handler in order to make sure that
52    the timed, but blocking call to select will be interrupted
53    by SIGCHLD signals.  */
54
55 static void
56 chld_handler (int sig)
57 {
58 }
59
60 static struct termios save_termios;
61
62 static void
63 close_device (int infd, int outfd)
64 {
65   if (isatty (infd))
66     {
67       tcsetattr (infd, TCSAFLUSH, &save_termios);
68     }
69   close (infd);
70   close (outfd);
71 }
72
73 /* Put a tty into "raw" mode.  Mostly taken from Stevens' book, "Advanced
74    Programming in the UNIX Environment.  */
75 static int
76 tty_raw (int fd, speed_t speed)
77 {
78   struct termios buf;
79
80   /* Don't do anything for non-tty devices.  */
81   if (!isatty (fd))
82     return 0;
83
84   if (tcgetattr (fd, &save_termios) < 0)
85     return -1;
86
87   buf = save_termios;
88
89   /* Set the following local modes: echo off, canonical mode off, extended
90      input processing off, signal chars off.  */
91   buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
92
93   /* Set the following input modes: no SIGINT on BREAK, CR-to-NL off, input
94      parity check off, don't strip 7th bit on input, output flow control
95      off.  */
96   buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
97
98   /* Set the following control modes: clear size bits, parity checking off.  */
99   buf.c_cflag &= ~(CSIZE | PARENB); 
100
101   /* Enable 8 bits/char.  */
102   buf.c_cflag |= CS8;
103
104   /* Turn output processing off.  */
105   buf.c_oflag &= ~(OPOST);
106
107   /* Case B: 1 byte at a time, no timer */
108   buf.c_cc[VMIN] = 1;
109   buf.c_cc[VTIME] = 0;
110
111   if (speed != B0)
112     {
113       cfsetispeed (&buf, speed);
114       cfsetospeed (&buf, speed);
115     }
116
117   if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
118     return -1;
119   return 0;
120 }
121
122 /* Table of serial port speed values.  */
123 static struct
124   {
125     long speed;         /* speed value as an integer */
126     speed_t bspeed;     /* speed value as one of the termios.h constants
127                            suitable for passing to cfsetispeed() or
128                            cfsetospeed().  */
129   }
130 speed_table[] = {
131   { 50, B50 },
132   { 75, B75 },
133   { 110, B110 },
134   { 134, B134 },
135   { 150, B150 },
136   { 200, B200 },
137   { 300, B300 },
138   { 600, B600 },
139   { 1200, B1200 },
140   { 1800, B1800 },
141   { 2400, B2400 },
142   { 4800, B4800 },
143   { 9600, B9600 },
144   { 19200, B19200 },
145   { 38400, B38400 }
146 #ifdef B57600 
147   ,{ 57600, B57600 }
148 #endif
149 #ifdef B115200
150   ,{ 115200, B115200 }
151 #endif
152 #ifdef B230400
153   ,{ 230400, B230400 }
154 #endif
155 #ifdef B460800
156   ,{ 460800, B460800 }
157 #endif
158 #ifdef B500000
159   ,{ 500000, B500000 }
160 #endif
161 #ifdef B576000
162   ,{ 576000, B576000 }
163 #endif
164 #ifdef B921600
165   ,{ 921600, B921600 }
166 #endif
167 #ifdef B2000000
168   ,{ 1000000, B1000000 }
169 #endif
170 #ifdef B1152000
171   ,{ 1152000, B1152000 }
172 #endif
173 #ifdef B1500000
174   ,{ 1500000, B1500000 }
175 #endif
176 #ifdef B2000000
177   ,{ 2000000, B2000000 }
178 #endif
179 #ifdef B2500000
180   ,{ 2500000, B2500000 }
181 #endif
182 #ifdef B3000000
183   ,{ 3000000, B3000000 }
184 #endif
185 #ifdef B3500000
186   ,{ 3500000, B3500000 }
187 #endif
188 #ifdef B4000000
189   ,{ 4000000, B4000000 }
190 #endif
191 };
192
193 /* Print error for erroneous -s switch and exit.  */
194 static void
195 invalid_speed (char *str)
196 {
197   int i;
198   int ll;
199
200   fprintf (stderr, "Error: Invalid -s switch \"%s\".\n", str);
201   ll = fprintf (stderr, "Valid speeds are:");
202   
203   for (i = 0; i < sizeof (speed_table) / sizeof (speed_table[0]); i++)
204     {
205       char str[20];
206       int cnt;
207       cnt = snprintf (str, sizeof (str), "%ld", speed_table[i].speed);
208       if (cnt + ll + 1 > 80)
209         {
210           fprintf (stderr, "\n");
211           ll = 0;
212         }
213       else
214         {
215           fprintf (stderr, " ");
216           ll++;
217         }
218       fprintf (stderr, "%s", str);
219       ll += cnt;
220     }
221   fprintf (stderr, "\n");
222   exit (1);
223 }
224
225 /* Attempt to parse a speed and return the speed value.  */
226 static speed_t
227 parse_speed (char *str)
228 {
229   int i;
230   long speed;
231   char *endptr;
232
233   speed = strtol (str, &endptr, 10);
234   if (speed == 0 || *endptr != '\0')
235     {
236       invalid_speed (str);
237       /* won't return */
238     }
239
240   for (i = 0; i < sizeof (speed_table) / sizeof (speed_table[0]); i++)
241     if (speed_table[i].speed == speed)
242       return speed_table[i].bspeed;
243
244   /* Speed not found.  Error out.  */
245   invalid_speed (str);
246   return 0;     /* won't actually return */
247 }
248
249 /* Print a usage message and exit.  */
250 static void
251 usage (char *progname)
252 {
253   /* Remove any leading slashes from the executable name.  */
254   if (strrchr (progname, '/'))
255     progname = strrchr (progname, '/') + 1;
256
257   fprintf (stderr,
258     "Usage: %s [-v] tcp-port-num executable-file [arguments ...]\n"
259     "   or: %s -a [-v] tcp-port-num process-id\n"
260     "   or: %s [-v] [-s speed] device-name executable-file [arguments ...]\n"
261     "   or: %s -a [-v] [-s speed] device-name process-id\n"
262     "   or: %s -h\n"
263     "Start the Red Hat debug agent for use with a remote debugger.\n"
264     "Options and arguments:\n"
265     "  -a               Attach to already running process.\n"
266     "  -h               Print this usage message.\n"
267     "  -s speed         Set speed (e.g. 115200) at which device \"device-name\"\n"
268     "                   will communicate with remote debugger.\n"
269     "  -v               Increase verbosity.  One -v flag enables informational\n"
270     "                   messages.  Two -v flags turn on internal debugging\n"
271     "                   messages.\n"
272     "  arguments ...    Command line arguments with which to start program\n"
273     "                   being debugged.\n"
274     "  device-name      Name of serial device over which RDA will communicate\n"
275     "                   with remote debugger.\n"
276     "  executable-file  Name of program to debug.\n"
277     "  process-id       Process ID (PID) of process to attach to.\n"
278     "  tcp-port-num     Port number to which debugger connects for purpose\n"
279     "                   of communicating with the debug agent using the GDB\n"
280     "                   remote protocol.\n",
281     progname, progname, progname, progname, progname);
282   exit (1);
283 }
284
285 int
286 main (int argc, char **argv)
287 {
288   int portno = 0;
289   char *endptr;
290   int verbose = 0;
291   int attach = 0;
292   int optidx;
293   int infd = 0, outfd = 0;
294   struct child_process *process;
295   char *devicename = "";
296   speed_t speed = B0;
297
298   /* Parse options.  */
299   for (optidx = 1; optidx < argc; optidx++)
300     {
301       if (argv[optidx][0] == '-' && argv[optidx][1] != '\0')
302         {
303           switch (argv[optidx][1])
304             {
305               case 'a':
306                 attach = 1;
307                 break;
308               case 'h':
309                 usage (argv[0]);
310                 /* not reached */
311                 break;
312               case 's':
313                 optidx++;
314                 if (optidx >= argc)
315                   usage(argv[0]);
316                 speed = parse_speed (argv[optidx]);
317                 break;
318               case 'v':
319                 verbose++;
320                 break;
321               default:
322                 usage (argv[0]);
323                 /* not reached */
324                 break;
325             }
326         }
327       else
328         break;
329     }
330
331   if (argc - optidx < 2)
332     usage (argv[0]);
333
334   if (isdigit (*argv[optidx]))
335     {
336       errno = 0;
337       portno = strtol (argv[optidx], &endptr, 10);
338       if (errno != 0 || portno == 0)
339         usage (argv[0]);
340     }
341   else if (strcmp (argv[optidx], "-") == 0)
342     {
343       infd = STDIN_FILENO;
344       outfd = STDOUT_FILENO;
345       devicename = "stdin/stdout";
346     }
347   else
348     {
349       devicename = argv[optidx];
350       infd = open (devicename, O_RDWR);
351       if (infd < 0)
352         {
353           fprintf (stderr, "Error opening device %s: %s\n", devicename,
354                    strerror (errno));
355           exit (1);
356         }
357       outfd = infd;
358     }
359
360   process = malloc (sizeof (struct child_process));
361   memset (process, 0, sizeof (struct child_process));
362   if (attach)
363     {
364       process->pid = strtol (argv[optidx + 1], &endptr, 10);
365       if (errno != 0 || endptr == argv[optidx] || process->pid <= 0)
366         usage (argv[0]);
367     }
368   else
369     {
370       process->argv       = &argv[optidx + 1];
371       process->executable =  argv[optidx + 1];
372     }
373
374   if (verbose > 1)
375     process->debug_backend = 1;
376   if (verbose)
377     process->debug_informational = 1;
378
379   signal (SIGCHLD, chld_handler);
380
381 #if defined(__SIGRTMIN) && defined(__SIGRTMAX)
382   {
383     int sig;
384     /* Ignore realtime signals.  We do this so as to not terminate
385        RDA if we inadvertently receive one of these signals.  The
386        realtime signals are used for thread support, and, for some
387        reason, some environments send these signals to RDA as well
388        as the application.  (And some don't.)  */
389     for (sig = __SIGRTMIN; sig <= __SIGRTMAX; sig++)
390       signal (sig, SIG_IGN);
391   }
392 #endif
393
394   if (portno != 0)
395     {
396       if (gdbsocket_startup (portno, gdbserver.attach, process) < 0)
397         {
398           fprintf (stderr, "Error listening on port %d: %s\n",
399                    portno, strerror (errno));
400           return 2;
401         }
402       if (process->debug_informational)
403         fprintf (stderr, "Started listening socket on port %d.\n", portno);
404     }
405   else
406     {
407       tty_raw (infd, speed);
408       if (process->debug_informational)
409         fprintf (stderr, "Waiting for input on %s.\n", devicename);
410       gdbsocket_reopen (infd, outfd, close_device, gdbserver.attach, process);
411     }
412
413   /* Poll for socket traffic. */
414   while (! server_quit_p)
415     {
416       gdbloop_poll (1 /* second */);
417       if (! server_quit_p)
418         {
419           if (gdbserver.check_child_state (process))
420             {
421               switch (process->stop_status) {
422               case 'T':
423                 gdbserver.fromtarget_break (process);
424                 break;
425               case 'X':
426                 gdbserver.fromtarget_terminate (process);
427                 server_quit_p = 1;              /* See below.  */
428                 break;
429               case 'W':
430                 gdbserver.fromtarget_exit (process);
431                 /* If we're connected to a serial port which is not
432                    observing the modem control signals (e.g. "stty
433                    clocal"), then we'll never notice that the port has
434                    been closed.  For this reason, when we notice that
435                    the target has exited or terminated, we need to set
436                    ``server_quit_p'' explicitly.  */
437                 server_quit_p = 1;
438                 break;
439               }
440             }
441         }
442     }
443   gdbsocket_shutdown ();
444   if (process->debug_informational)
445     fprintf (stderr, "Shut down sockets.\n");
446
447   return 0;
448 }