]> Git Repo - binutils.git/blob - gdb/remote-vx.c
> * xm-rs6000.h: define MEM_FNS_DECLARED
[binutils.git] / gdb / remote-vx.c
1 /* Memory-access and commands for remote VxWorks processes, for GDB.
2    Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3    Contributed by Wind River Systems and Cygnus Support.
4
5 This file is part of GDB.
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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #include "defs.h"
22 #include "frame.h"
23 #include "inferior.h"
24 #include "wait.h"
25 #include "target.h"
26 #include "gdbcore.h"
27 #include "command.h"
28 #include "symtab.h"
29 #include "symfile.h"            /* for struct complaint */
30
31 #include <string.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/time.h>
37 #include <sys/socket.h>
38 #define free bogon_free         /* Sun claims "int free()" not void */
39 #include <rpc/rpc.h>
40 #undef free
41 #include <sys/time.h>           /* UTek's <rpc/rpc.h> doesn't #incl this */
42 #include <netdb.h>
43 #include "vx-share/ptrace.h"
44 #include "vx-share/xdr_ptrace.h"
45 #include "vx-share/xdr_ld.h"
46 #include "vx-share/xdr_rdb.h"
47 #include "vx-share/dbgRpcLib.h"
48
49 #include <symtab.h>
50
51 extern void symbol_file_command ();
52 extern int stop_soon_quietly;           /* for wait_for_inferior */
53 extern void host_convert_to_virtual ();
54 extern void host_convert_from_virtual ();
55
56 static int net_ptrace_clnt_call ();     /* Forward decl */
57 static enum clnt_stat net_clnt_call (); /* Forward decl */
58 extern struct target_ops vx_ops, vx_run_ops;    /* Forward declaration */
59
60 /* Saved name of target host and called function for "info files".
61    Both malloc'd.  */
62
63 static char *vx_host;
64 static char *vx_running;                /* Called function */
65
66 /* Nonzero means target that is being debugged remotely has a floating
67    point processor.  */
68
69 static int target_has_fp;
70
71 /* Default error message when the network is forking up.  */
72
73 static const char rpcerr[] = "network target debugging:  rpc error";
74
75 CLIENT *pClient;         /* client used in net debugging */
76 static int ptraceSock = RPC_ANYSOCK;
77
78 enum clnt_stat net_clnt_call();
79 static void parse_args ();
80
81 static struct timeval rpcTimeout = { 10, 0 };
82
83 static char *skip_white_space ();
84 static char *find_white_space ();
85  
86 /* Tell the VxWorks target system to download a file.
87    The load addresses of the text, data, and bss segments are
88    stored in pTextAddr, pDataAddr, and *pBssAddr (respectively).
89    Returns 0 for success, -1 for failure.  */
90
91 static int
92 net_load (filename, pTextAddr, pDataAddr, pBssAddr)
93     char *filename;
94     CORE_ADDR *pTextAddr;
95     CORE_ADDR *pDataAddr;
96     CORE_ADDR *pBssAddr;
97     {
98     enum clnt_stat status;
99     struct ldfile ldstruct;
100     struct timeval load_timeout;
101  
102     bzero ((char *) &ldstruct, sizeof (ldstruct));
103
104     /* We invoke clnt_call () here directly, instead of through
105        net_clnt_call (), because we need to set a large timeout value.
106        The load on the target side can take quite a while, easily
107        more than 10 seconds.  The user can kill this call by typing
108        CTRL-C if there really is a problem with the load.  
109        
110        Do not change the tv_sec value without checking -- select() imposes
111        a limit of 10**8 on it for no good reason that I can see...  */
112
113     load_timeout.tv_sec = 99999999;   /* A large number, effectively inf. */
114     load_timeout.tv_usec = 0;
115  
116     status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile,
117                         &ldstruct, load_timeout);
118
119     if (status == RPC_SUCCESS)
120       {
121         if (*ldstruct.name == NULL)     /* load failed on VxWorks side */
122           return -1;
123         *pTextAddr = ldstruct.txt_addr;
124         *pDataAddr = ldstruct.data_addr;
125         *pBssAddr = ldstruct.bss_addr;
126         return 0;
127       }
128     else
129         return -1;
130     }
131       
132 /* returns 0 if successful, errno if RPC failed or VxWorks complains. */
133
134 static int
135 net_break (addr, procnum)
136     int addr;
137     u_long procnum;
138     {
139     enum clnt_stat status;
140     int break_status;
141     Rptrace ptrace_in;  /* XXX This is stupid.  It doesn't need to be a ptrace
142                            structure.  How about something smaller? */
143
144     bzero ((char *) &ptrace_in, sizeof (ptrace_in));
145     break_status = 0;
146
147     ptrace_in.addr = addr;
148     ptrace_in.pid = inferior_pid;
149
150     status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int,
151                             &break_status);
152
153     if (status != RPC_SUCCESS)
154         return errno;
155
156     if (break_status == -1)
157       return ENOMEM;
158     return break_status;        /* probably (FIXME) zero */
159     }
160  
161 /* returns 0 if successful, errno otherwise */
162
163 static int
164 vx_insert_breakpoint (addr)
165     int addr;
166     {
167     return net_break (addr, VX_BREAK_ADD);
168     }
169
170 /* returns 0 if successful, errno otherwise */
171
172 static int
173 vx_remove_breakpoint (addr)
174     int addr;
175     {
176     return net_break (addr, VX_BREAK_DELETE);
177     }
178
179 /* Start an inferior process and sets inferior_pid to its pid.
180    EXEC_FILE is the file to run.
181    ALLARGS is a string containing the arguments to the program.
182    ENV is the environment vector to pass.
183    Returns process id.  Errors reported with error().
184    On VxWorks, we ignore exec_file.  */
185  
186 static void
187 vx_create_inferior (exec_file, args, env)
188      char *exec_file;
189      char *args;
190      char **env;
191 {
192   enum clnt_stat status;
193   arg_array passArgs;
194   TASK_START taskStart;
195
196   bzero ((char *) &passArgs, sizeof (passArgs));
197   bzero ((char *) &taskStart, sizeof (taskStart));
198
199   /* parse arguments, put them in passArgs */
200
201   parse_args (args, &passArgs);
202
203   if (passArgs.arg_array_len == 0)
204     error ("You must specify a function name to run, and arguments if any");
205
206   status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
207                           xdr_TASK_START, &taskStart);
208
209   if ((status != RPC_SUCCESS) || (taskStart.status == -1))
210     error ("Can't create process on remote target machine");
211
212   /* Save the name of the running function */
213   vx_running = savestring (passArgs.arg_array_val[0],
214                            strlen (passArgs.arg_array_val[0]));
215
216 #ifdef CREATE_INFERIOR_HOOK
217   CREATE_INFERIOR_HOOK (pid);
218 #endif  
219
220   push_target (&vx_run_ops);
221   inferior_pid = taskStart.pid;
222
223   /* We will get a trace trap after one instruction.
224      Insert breakpoints and continue.  */
225
226   init_wait_for_inferior ();
227
228   /* Set up the "saved terminal modes" of the inferior
229      based on what modes we are starting it with.  */
230   target_terminal_init ();
231
232   /* Install inferior's terminal modes.  */
233   target_terminal_inferior ();
234
235   stop_soon_quietly = 1;
236   wait_for_inferior ();         /* Get the task spawn event */
237   stop_soon_quietly = 0;
238
239   /* insert_step_breakpoint ();  FIXME, do we need this?  */
240   proceed(-1, -1, 0);
241 }
242
243 /* Fill ARGSTRUCT in argc/argv form with the arguments from the
244    argument string ARGSTRING.  */
245
246 static void
247 parse_args (arg_string, arg_struct)
248      register char *arg_string;
249      arg_array *arg_struct;
250 {
251   register int arg_count = 0;   /* number of arguments */
252   register int arg_index = 0;
253   register char *p0;
254  
255   bzero ((char *) arg_struct, sizeof (arg_array));
256  
257   /* first count how many arguments there are */
258
259   p0 = arg_string;
260   while (*p0 != '\0')
261     {
262       if (*(p0 = skip_white_space (p0)) == '\0')
263         break;
264       p0 = find_white_space (p0);
265       arg_count++;
266     }
267
268   arg_struct->arg_array_len = arg_count;
269   arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
270                                                  * sizeof (char *));
271
272   /* now copy argument strings into arg_struct.  */
273
274   while (*(arg_string = skip_white_space (arg_string)))
275     {
276       p0 = find_white_space (arg_string);
277       arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
278                                                            p0 - arg_string);
279       arg_string = p0;
280     }
281
282   arg_struct->arg_array_val[arg_count] = NULL;
283 }
284
285 /* Advance a string pointer across whitespace and return a pointer
286    to the first non-white character.  */
287
288 static char *
289 skip_white_space (p)
290      register char *p;
291 {
292   while (*p == ' ' || *p == '\t')
293     p++;
294   return p;
295 }
296     
297 /* Search for the first unquoted whitespace character in a string.
298    Returns a pointer to the character, or to the null terminator
299    if no whitespace is found.  */
300
301 static char *
302 find_white_space (p)
303      register char *p;
304 {
305   register int c;
306
307   while ((c = *p) != ' ' && c != '\t' && c)
308     {
309       if (c == '\'' || c == '"')
310         {
311           while (*++p != c && *p)
312             {
313               if (*p == '\\')
314                 p++;
315             }
316           if (!*p)
317             break;
318         }
319       p++;
320     }
321   return p;
322 }
323     
324 /* Poll the VxWorks target system for an event related
325    to the debugged task.
326    Returns -1 if remote wait failed, task status otherwise.  */
327
328 static int
329 net_wait (pEvent)
330     RDB_EVENT *pEvent;
331 {
332     int pid;
333     enum clnt_stat status;
334
335     bzero ((char *) pEvent, sizeof (RDB_EVENT));
336
337     pid = inferior_pid;
338     status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, pEvent);
339
340     return (status == RPC_SUCCESS)? pEvent->status: -1;
341 }
342     
343 /* Suspend the remote task.
344    Returns -1 if suspend fails on target system, 0 otherwise.  */
345
346 static int
347 net_quit ()
348 {
349     int pid;
350     int quit_status;
351     enum clnt_stat status;
352
353     quit_status = 0;
354
355     /* don't let rdbTask suspend itself by passing a pid of 0 */
356
357     if ((pid = inferior_pid) == 0)
358         return -1;
359
360     status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
361                             &quit_status);
362
363     return (status == RPC_SUCCESS)? quit_status: -1;
364 }
365
366 /* Read a register or registers from the remote system.  */
367
368 static void
369 vx_read_register (regno)
370      int regno;
371 {
372   int status;
373   Rptrace ptrace_in;
374   Ptrace_return ptrace_out;
375   C_bytes in_data;
376   C_bytes out_data;
377   extern char registers[];
378
379   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
380   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
381
382   /* FIXME, eventually only get the ones we need.  */
383   registers_fetched ();
384   
385   ptrace_in.pid = inferior_pid;
386   ptrace_out.info.more_data = (caddr_t) &out_data;
387   out_data.len   = 18 * REGISTER_RAW_SIZE (0);          /* FIXME 68k hack */
388   out_data.bytes = (caddr_t) registers;
389   
390   status = net_ptrace_clnt_call (PTRACE_GETREGS, &ptrace_in, &ptrace_out);
391   if (status)
392     error (rpcerr);
393   if (ptrace_out.status == -1)
394     {
395       errno = ptrace_out.errno;
396       perror_with_name ("net_ptrace_clnt_call(PTRACE_GETREGS)");
397     }
398   
399 #ifdef I80960
400
401       bcopy ((char *) inferior_registers.r_lreg,
402              &registers[REGISTER_BYTE (R0_REGNUM)], 16 * sizeof (int));
403       bcopy ((char *) inferior_registers.r_greg,
404              &registers[REGISTER_BYTE (G0_REGNUM)], 16 * sizeof (int));
405
406       /* Don't assume that a location in registers[] is properly aligned.  */
407
408       bcopy ((char *) &inferior_registers.r_pcw,
409              &registers[REGISTER_BYTE (PCW_REGNUM)], sizeof (int));
410       bcopy ((char *) &inferior_registers.r_acw,
411              &registers[REGISTER_BYTE (ACW_REGNUM)], sizeof (int));
412       bcopy ((char *) &inferior_registers.r_lreg[2],    /* r2 (RIP) -> IP */
413              &registers[REGISTER_BYTE (IP_REGNUM)], sizeof (int));
414       bcopy ((char *) &inferior_registers.r_tcw,
415              &registers[REGISTER_BYTE (TCW_REGNUM)], sizeof (int));
416
417       /* If the target has floating point registers, fetch them.
418          Otherwise, zero the floating point register values in
419          registers[] for good measure, even though we might not
420          need to.  */
421
422       if (target_has_fp)
423         {
424           ptrace_in.pid = inferior_pid;
425           ptrace_out.info.more_data = (caddr_t) &inferior_fp_registers;
426           status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out);
427           if (status)
428             error (rpcerr);
429           if (ptrace_out.status == -1)
430             {
431               errno = ptrace_out.errno;
432               perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)");
433             }
434           
435           bcopy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
436                  REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
437         }
438       else
439         {
440           bzero ((char *) &registers[REGISTER_BYTE (FP0_REGNUM)],
441                  REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
442         }
443
444 #else  /* not 960, thus must be 68000:  FIXME!  */
445
446   if (target_has_fp)
447     {
448       ptrace_in.pid = inferior_pid;
449       ptrace_out.info.more_data = (caddr_t) &out_data;
450       out_data.len   =  8 * REGISTER_RAW_SIZE (FP0_REGNUM)      /* FIXME */
451                      + (3 * sizeof (REGISTER_TYPE));
452       out_data.bytes = (caddr_t) &registers[REGISTER_BYTE (FP0_REGNUM)];
453   
454       status = net_ptrace_clnt_call (PTRACE_GETFPREGS, &ptrace_in, &ptrace_out);
455       if (status)
456         error (rpcerr);
457       if (ptrace_out.status == -1)
458         {
459           errno = ptrace_out.errno;
460           perror_with_name ("net_ptrace_clnt_call(PTRACE_GETFPREGS)");
461         }
462     }
463   else
464     {
465       bzero (&registers[REGISTER_BYTE (FP0_REGNUM)],
466              8 * REGISTER_RAW_SIZE (FP0_REGNUM));
467       bzero (&registers[REGISTER_BYTE (FPC_REGNUM)],
468              3 * sizeof (REGISTER_TYPE));
469     }
470 #endif  /* various architectures */
471 }
472
473 /* Prepare to store registers.  Since we will store all of them,
474    read out their current values now.  */
475
476 static void
477 vx_prepare_to_store ()
478 {
479   vx_read_register (-1);
480 }
481
482
483 /* Store our register values back into the inferior.
484    If REGNO is -1, do this for all registers.
485    Otherwise, REGNO specifies which register (so we can save time).  */
486    /* FIXME, look at REGNO to save time here */
487
488 static void
489 vx_write_register (regno)
490      int regno;
491 {
492   C_bytes in_data;
493   C_bytes out_data;
494   extern char registers[];
495   int status;
496   Rptrace ptrace_in;
497   Ptrace_return ptrace_out;
498
499   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
500   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
501
502   ptrace_in.pid = inferior_pid;
503   ptrace_in.info.ttype     = DATA;
504   ptrace_in.info.more_data = (caddr_t) &in_data;
505
506   in_data.bytes = registers;
507
508 #ifdef I80960
509
510   /* FIXME */
511   bcopy (&registers[REGISTER_BYTE (R0_REGNUM)],
512          (char *) inferior_registers.r_lreg, 16 * sizeof (int));
513   bcopy (&registers[REGISTER_BYTE (G0_REGNUM)],
514          (char *) inferior_registers.r_greg, 16 * sizeof (int));
515
516   /* Don't assume that a location in registers[] is properly aligned.  */
517
518   bcopy (&registers[REGISTER_BYTE (PCW_REGNUM)],
519          (char *) &inferior_registers.r_pcw, sizeof (int));
520   bcopy (&registers[REGISTER_BYTE (ACW_REGNUM)],
521          (char *) &inferior_registers.r_acw, sizeof (int));
522   bcopy (&registers[REGISTER_BYTE (TCW_REGNUM)],
523          (char *) &inferior_registers.r_tcw, sizeof (int));
524
525 #else  /* not 960 -- assume 68k -- FIXME */
526
527   in_data.len = 18 * sizeof (REGISTER_TYPE);
528
529 #endif  /* Different register sets */
530
531   /* XXX change second param to be a proc number */
532   status = net_ptrace_clnt_call (PTRACE_SETREGS, &ptrace_in, &ptrace_out);
533   if (status)
534       error (rpcerr);
535   if (ptrace_out.status == -1)
536     {
537       errno = ptrace_out.errno;
538       perror_with_name ("net_ptrace_clnt_call(PTRACE_SETREGS)");
539     }
540
541   /* Store floating point registers if the target has them.  */
542
543   if (target_has_fp)
544     {
545       ptrace_in.pid = inferior_pid;
546       ptrace_in.info.ttype     = DATA;
547       ptrace_in.info.more_data = (caddr_t) &in_data;
548
549
550 #ifdef I80960
551
552       bcopy (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
553              sizeof inferior_fp_registers.fps_regs);
554
555 #else  /* not 960 -- assume 68k -- FIXME */
556
557       in_data.bytes = &registers[REGISTER_BYTE (FP0_REGNUM)];
558       in_data.len = (8 * REGISTER_RAW_SIZE (FP0_REGNUM)
559                       + (3 * sizeof (REGISTER_TYPE)));
560
561 #endif  /* Different register sets */
562
563       status = net_ptrace_clnt_call (PTRACE_SETFPREGS, &ptrace_in, &ptrace_out);
564       if (status)
565           error (rpcerr);
566       if (ptrace_out.status == -1)
567         {
568           errno = ptrace_out.errno;
569           perror_with_name ("net_ptrace_clnt_call(PTRACE_SETFPREGS)");
570         }
571     }
572 }
573
574 /* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
575    to debugger memory starting at MYADDR.  WRITE is true if writing to the
576    inferior.
577    Result is the number of bytes written or read (zero if error).  The
578    protocol allows us to return a negative count, indicating that we can't
579    handle the current address but can handle one N bytes further, but
580    vxworks doesn't give us that information.  */
581
582 static int
583 vx_xfer_memory (memaddr, myaddr, len, write, target)
584      CORE_ADDR memaddr;
585      char *myaddr;
586      int len;
587      int write;
588      struct target_ops *target;                 /* ignored */
589 {
590   int status;
591   Rptrace ptrace_in;
592   Ptrace_return ptrace_out;
593   C_bytes data;
594
595   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
596   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
597
598   ptrace_in.pid = inferior_pid;         /* XXX pid unnecessary for READDATA */
599   ptrace_in.addr = (int) memaddr;       /* Where from */
600   ptrace_in.data = len;                 /* How many bytes */
601
602   if (write)
603     {
604       ptrace_in.info.ttype     = DATA;
605       ptrace_in.info.more_data = (caddr_t) &data;
606
607       data.bytes = (caddr_t) myaddr;    /* Where from */
608       data.len   = len;                 /* How many bytes (again, for XDR) */
609
610       /* XXX change second param to be a proc number */
611       status = net_ptrace_clnt_call (PTRACE_WRITEDATA, &ptrace_in, &ptrace_out);
612     }
613   else
614     {
615       ptrace_out.info.more_data = (caddr_t) &data;
616       data.bytes = myaddr;              /* Where to */
617       data.len   = len;                 /* How many (again, for XDR) */
618
619       /* XXX change second param to be a proc number */
620       status = net_ptrace_clnt_call (PTRACE_READDATA, &ptrace_in, &ptrace_out);
621     }
622
623   if (status)
624       error (rpcerr);
625   if (ptrace_out.status == -1)
626     {
627       return 0;         /* No bytes moved */
628     }
629   return len;           /* Moved *all* the bytes */
630 }
631
632 static void
633 vx_files_info ()
634 {
635   printf ("\tAttached to host `%s'", vx_host);
636   printf (", which has %sfloating point", target_has_fp? "": "no ");
637   printf (".\n");
638 }
639
640 static void
641 vx_run_files_info ()
642 {
643   printf ("\tRunning %s VxWorks process %s", 
644           vx_running? "child": "attached",
645           local_hex_string(inferior_pid));
646   if (vx_running)
647     printf (", function `%s'", vx_running);
648   printf(".\n");
649 }
650
651 static void
652 vx_resume (step, siggnal)
653      int step;
654      int siggnal;
655 {
656   int status;
657   Rptrace ptrace_in;
658   Ptrace_return ptrace_out;
659
660   if (siggnal != 0 && siggnal != stop_signal)
661     error ("Cannot send signals to VxWorks processes");
662
663   bzero ((char *) &ptrace_in, sizeof (ptrace_in));
664   bzero ((char *) &ptrace_out, sizeof (ptrace_out));
665
666   ptrace_in.pid = inferior_pid;
667   ptrace_in.addr = 1;   /* Target side insists on this, or it panics.  */
668
669   /* XXX change second param to be a proc number */
670   status = net_ptrace_clnt_call (step? PTRACE_SINGLESTEP: PTRACE_CONT,
671                                  &ptrace_in, &ptrace_out);
672   if (status)
673       error (rpcerr);
674   if (ptrace_out.status == -1)
675     {
676       errno = ptrace_out.errno;
677       perror_with_name ("Resuming remote process");
678     }
679 }
680
681 static void
682 vx_mourn_inferior ()
683 {
684   pop_target ();                /* Pop back to no-child state */
685   generic_mourn_inferior ();
686 }
687
688 \f
689 /* This function allows the addition of incrementally linked object files.  */
690
691 static void
692 vx_load_command (arg_string, from_tty)
693      char* arg_string;
694      int from_tty;
695 {
696   CORE_ADDR text_addr;
697   CORE_ADDR data_addr;
698   CORE_ADDR bss_addr;
699   
700   if (arg_string == 0)
701     error ("The load command takes a file name");
702
703   arg_string = tilde_expand (arg_string);
704   make_cleanup (free, arg_string);
705
706   dont_repeat ();
707
708   QUIT;
709   immediate_quit++;
710   if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
711     error ("Load failed on target machine");
712   immediate_quit--;
713
714   /* FIXME, for now we ignore data_addr and bss_addr.  */
715   symbol_file_add (arg_string, from_tty, text_addr, 0, 0, 0);
716 }
717
718 #ifdef FIXME  /* Not ready for prime time */
719 /* Single step the target program at the source or machine level.
720    Takes an error exit if rpc fails.
721    Returns -1 if remote single-step operation fails, else 0.  */
722
723 static int
724 net_step ()
725 {
726   enum clnt_stat status;
727   int step_status;
728   SOURCE_STEP source_step;
729
730   source_step.taskId = inferior_pid;
731
732   if (step_range_end)
733     {
734       source_step.startAddr = step_range_start;
735       source_step.endAddr = step_range_end;
736     }
737   else
738     {
739       source_step.startAddr = 0;
740       source_step.endAddr = 0;
741     }
742
743   status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
744                           xdr_int, &step_status);
745
746   if (status == RPC_SUCCESS)
747     return step_status;
748   else 
749     error (rpcerr);
750 }
751 #endif
752
753 /* Emulate ptrace using RPC calls to the VxWorks target system.
754    Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise.  */
755
756 static int
757 net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut)
758     enum ptracereq request;
759     Rptrace *pPtraceIn;
760     Ptrace_return *pPtraceOut;
761 {
762   enum clnt_stat status;
763
764   status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
765                           pPtraceOut);
766
767   if (status != RPC_SUCCESS)
768       return -1;
769
770   return 0;
771 }
772
773 /* Query the target for the name of the file from which VxWorks was
774    booted.  pBootFile is the address of a pointer to the buffer to
775    receive the file name; if the pointer pointed to by pBootFile is 
776    NULL, memory for the buffer will be allocated by XDR.
777    Returns -1 if rpc failed, 0 otherwise.  */
778
779 static int
780 net_get_boot_file (pBootFile)
781      char **pBootFile;
782 {
783   enum clnt_stat status;
784
785   status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
786                           xdr_wrapstring, pBootFile);
787   return (status == RPC_SUCCESS) ? 0 : -1;
788 }
789
790 /* Fetch a list of loaded object modules from the VxWorks target.
791    Returns -1 if rpc failed, 0 otherwise
792    There's no way to check if the returned loadTable is correct.
793    VxWorks doesn't check it.  */
794
795 static int
796 net_get_symbols (pLoadTable)
797      ldtabl *pLoadTable;                /* return pointer to ldtabl here */
798 {
799   enum clnt_stat status;
800
801   bzero ((char *) pLoadTable, sizeof (struct ldtabl));
802
803   status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
804   return (status == RPC_SUCCESS) ? 0 : -1;
805 }
806
807 /* Look up a symbol in the VxWorks target's symbol table.
808    Returns status of symbol read on target side (0=success, -1=fail)
809    Returns -1 and complain()s if rpc fails.  */
810
811 struct complaint cant_contact_target =
812   {"Lost contact with VxWorks target", 0, 0};
813
814 static int
815 vx_lookup_symbol (name, pAddr)
816      char *name;                /* symbol name */
817      CORE_ADDR *pAddr;
818 {
819   enum clnt_stat status;
820   SYMBOL_ADDR symbolAddr;
821
822   *pAddr = 0;
823   bzero ((char *) &symbolAddr, sizeof (symbolAddr));
824
825   status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
826                           xdr_SYMBOL_ADDR, &symbolAddr);
827   if (status != RPC_SUCCESS) {
828       complain (&cant_contact_target, 0);
829       return -1;
830   }
831
832   *pAddr = symbolAddr.addr;
833   return symbolAddr.status;
834 }
835
836 /* Check to see if the VxWorks target has a floating point coprocessor.
837    Returns 1 if target has floating point processor, 0 otherwise.
838    Calls error() if rpc fails.  */
839
840 static int
841 net_check_for_fp ()
842 {
843   enum clnt_stat status;
844   bool_t fp = 0;        /* true if fp processor is present on target board */
845
846   status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
847   if (status != RPC_SUCCESS)
848       error (rpcerr);
849
850    return (int) fp;
851 }
852
853 /* Establish an RPC connection with the VxWorks target system.
854    Calls error () if unable to establish connection.  */
855
856 static void
857 net_connect (host)
858      char *host;
859 {
860   struct sockaddr_in destAddr;
861   struct hostent *destHost;
862
863   /* get the internet address for the given host */
864
865   if ((destHost = (struct hostent *) gethostbyname (host)) == NULL)
866       error ("Invalid hostname.  Couldn't find remote host address.");
867
868   bzero (&destAddr, sizeof (destAddr));
869
870   destAddr.sin_addr.s_addr = * (u_long *) destHost->h_addr;
871   destAddr.sin_family      = AF_INET;
872   destAddr.sin_port        = 0; /* set to actual port that remote
873                                    ptrace is listening on.  */
874
875   /* Create a tcp client transport on which to issue
876      calls to the remote ptrace server.  */
877
878   ptraceSock = RPC_ANYSOCK;
879   pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
880   /* FIXME, here is where we deal with different version numbers of the proto */
881   
882   if (pClient == NULL)
883     {
884       clnt_pcreateerror ("\tnet_connect");
885       error ("Couldn't connect to remote target.");
886     }
887 }
888 \f
889 /* Sleep for the specified number of milliseconds 
890  * (assumed to be less than 1000).
891  * If select () is interrupted, returns immediately;
892  * takes an error exit if select () fails for some other reason.
893  */
894
895 static void
896 sleep_ms (ms)
897      long ms;
898 {
899   struct timeval select_timeout;
900   int status;
901
902   select_timeout.tv_sec = 0;
903   select_timeout.tv_usec = ms * 1000;
904
905   status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &select_timeout);
906
907   if (status < 0 && errno != EINTR)
908     perror_with_name ("select");
909 }
910
911 /* Wait for control to return from inferior to debugger.
912    If inferior gets a signal, we may decide to start it up again
913    instead of returning.  That is why there is a loop in this function.
914    When this function actually returns it means the inferior
915    should be left stopped and GDB should read more commands.  */
916
917 /* For network debugging with VxWorks.
918  * VxWorks knows when tasks hit breakpoints, receive signals, exit, etc,
919  * so vx_wait() receives this information directly from
920  * VxWorks instead of trying to figure out what happenned via a wait() call.
921  */
922
923 static int
924 vx_wait (status)
925      int *status;
926 {
927   register int pid;
928   WAITTYPE w;
929   RDB_EVENT rdbEvent;
930   int quit_failed;
931
932   do
933     {
934       /* If CTRL-C is hit during this loop,
935          suspend the inferior process.  */
936
937       quit_failed = 0;
938       if (quit_flag)
939         {
940           quit_failed = (net_quit () == -1);
941           quit_flag = 0;
942         }
943
944       /* If a net_quit () or net_wait () call has failed,
945          allow the user to break the connection with the target.
946          We can't simply error () out of this loop, since the 
947          data structures representing the state of the inferior
948          are in an inconsistent state.  */
949
950       if (quit_failed || net_wait (&rdbEvent) == -1)
951         {
952           terminal_ours ();
953           if (query ("Can't %s.  Disconnect from target system? ",
954                      (quit_failed) ? "suspend remote task"
955                                    : "get status of remote task"))
956             {
957               target_mourn_inferior();
958               error ("Use the \"target\" command to reconnect.");
959             }
960           else
961             {
962               terminal_inferior ();
963               continue;
964             }
965         }
966       
967       pid = rdbEvent.taskId;
968       if (pid == 0)
969         {
970           sleep_ms (200);       /* FIXME Don't kill the network too badly */
971         }
972       else if (pid != inferior_pid)
973         fatal ("Bad pid for debugged task: %s\n", local_hex_string(pid));
974     } while (pid == 0);
975
976   /* FIXME, eventually do more then SIGTRAP on everything...  */
977   switch (rdbEvent.eventType)
978     {
979     case EVENT_EXIT:
980       WSETEXIT (w, 0);
981       /* FIXME is it possible to distinguish between a
982          XXX   normal vs abnormal exit in VxWorks? */
983       break;
984
985     case EVENT_START:           /* Task was just started. */
986       WSETSTOP (w, SIGTRAP);
987       break;
988
989     case EVENT_STOP:
990       WSETSTOP (w, SIGTRAP);
991       /* XXX was it stopped by a signal?  act accordingly */
992       break;
993
994     case EVENT_BREAK:           /* Breakpoint was hit. */
995       WSETSTOP (w, SIGTRAP);
996       break;
997
998     case EVENT_SUSPEND:         /* Task was suspended, probably by ^C. */
999       WSETSTOP (w, SIGINT);
1000       break;
1001
1002     case EVENT_BUS_ERR:         /* Task made evil nasty reference. */
1003       WSETSTOP (w, SIGBUS);
1004       break;
1005
1006     case EVENT_ZERO_DIV:        /* Division by zero */
1007       WSETSTOP (w, SIGFPE);     /* Like Unix, call it a float exception. */
1008       break;
1009
1010     case EVENT_SIGNAL:
1011       /* The target is not running Unix, and its
1012          faults/traces do not map nicely into Unix signals.
1013          Make sure they do not get confused with Unix signals
1014          by numbering them with values higher than the highest
1015          legal Unix signal.  code in the arch-dependent PRINT_RANDOM_SIGNAL
1016          routine will interpret the value for wait_for_inferior.  */
1017       WSETSTOP (w, rdbEvent.sigType + NSIG);
1018       break;
1019     } /* switch */
1020   *status = *(int *)&w;         /* Grumble union wait crap Grumble */
1021   return pid;
1022 }
1023 \f
1024 static int
1025 symbol_stub (arg)
1026      char *arg;
1027 {
1028   symbol_file_command (arg, 0);
1029   return 1;
1030 }
1031
1032 static int
1033 add_symbol_stub (arg)
1034      char *arg;
1035 {
1036   struct ldfile *pLoadFile = (struct ldfile *)arg;
1037
1038   printf("\t%s: ", pLoadFile->name);
1039   symbol_file_add (pLoadFile->name, 0, pLoadFile->txt_addr, 0, 0, 0);
1040   printf ("ok\n");
1041   return 1;
1042 }
1043 /* Target command for VxWorks target systems.
1044
1045    Used in vxgdb.  Takes the name of a remote target machine
1046    running vxWorks and connects to it to initialize remote network
1047    debugging.  */
1048
1049 static void
1050 vx_open (args, from_tty)
1051      char *args;
1052      int from_tty;
1053 {
1054   extern int close ();
1055   char *bootFile;
1056   extern char *source_path;
1057   struct ldtabl loadTable;
1058   struct ldfile *pLoadFile;
1059   int i;
1060   extern CLIENT *pClient;
1061
1062   if (!args)
1063     error_no_arg ("target machine name");
1064
1065   target_preopen (from_tty);
1066   
1067   unpush_target (&vx_ops);
1068   printf ("Attaching remote machine across net...\n");
1069   fflush (stdout);
1070
1071   /* Allow the user to kill the connect attempt by typing ^C.
1072      Wait until the call to target_has_fp () completes before
1073      disallowing an immediate quit, since even if net_connect ()
1074      is successful, the remote debug server might be hung.  */
1075
1076   immediate_quit++;
1077
1078   net_connect (args);
1079   target_has_fp = net_check_for_fp ();
1080   printf_filtered ("Connected to %s.\n", args);
1081
1082   immediate_quit--;
1083
1084   push_target (&vx_ops);
1085
1086   /* Save a copy of the target host's name.  */
1087   vx_host = savestring (args, strlen (args));
1088
1089   /* Find out the name of the file from which the target was booted
1090      and load its symbol table.  */
1091
1092   printf_filtered ("Looking in Unix path for all loaded modules:\n");
1093   bootFile = NULL;
1094   if (!net_get_boot_file (&bootFile))
1095     {
1096       if (*bootFile) {
1097         printf_filtered ("\t%s: ", bootFile);
1098         if (catch_errors (symbol_stub, bootFile,
1099                 "Error while reading symbols from boot file:\n"))
1100           puts_filtered ("ok\n");
1101       } else if (from_tty)
1102         printf ("VxWorks kernel symbols not loaded.\n");
1103     }
1104   else
1105     error ("Can't retrieve boot file name from target machine.");
1106
1107   clnt_freeres (pClient, xdr_wrapstring, &bootFile);
1108
1109   if (net_get_symbols (&loadTable) != 0)
1110     error ("Can't read loaded modules from target machine");
1111
1112   i = 0-1;
1113   while (++i < loadTable.tbl_size)
1114     {
1115       QUIT;     /* FIXME, avoids clnt_freeres below:  mem leak */
1116       pLoadFile = &loadTable.tbl_ent [i];
1117 #ifdef WRS_ORIG
1118   {
1119     register int desc;
1120     struct cleanup *old_chain;
1121     char *fullname = NULL;
1122
1123     desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
1124     if (desc < 0)
1125         perror_with_name (pLoadFile->name);
1126     old_chain = make_cleanup (close, desc);
1127     add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
1128                       pLoadFile->bss_addr);
1129     do_cleanups (old_chain);
1130   }
1131 #else
1132       /* Botches, FIXME:
1133          (1)  Searches the PATH, not the source path.
1134          (2)  data and bss are assumed to be at the usual offsets from text.  */
1135       catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0);
1136 #endif
1137     }
1138   printf_filtered ("Done.\n");
1139
1140   clnt_freeres (pClient, xdr_ldtabl, &loadTable);
1141 }
1142 \f
1143 /* attach_command --
1144    takes a task started up outside of gdb and ``attaches'' to it.
1145    This stops it cold in its tracks and allows us to start tracing it.  */
1146
1147 static void
1148 vx_attach (args, from_tty)
1149      char *args;
1150      int from_tty;
1151 {
1152   int pid;
1153   char *cptr = 0;
1154   Rptrace ptrace_in;
1155   Ptrace_return ptrace_out;
1156   int status;
1157
1158   dont_repeat();
1159
1160   if (!args)
1161     error_no_arg ("process-id to attach");
1162
1163   pid = strtol (args, &cptr, 0);
1164   if ((cptr == args) || (*cptr != '\0'))
1165     error ("Invalid process-id -- give a single number in decimal or 0xhex");
1166
1167   if (from_tty)
1168       printf ("Attaching pid %s.\n", local_hex_string(pid));
1169
1170   bzero ((char *)&ptrace_in,  sizeof (ptrace_in));
1171   bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1172   ptrace_in.pid = pid;
1173
1174   status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
1175   if (status == -1)
1176     error (rpcerr);
1177   if (ptrace_out.status == -1)
1178     {
1179       errno = ptrace_out.errno;
1180       perror_with_name ("Attaching remote process");
1181     }
1182
1183   /* It worked... */
1184   push_target (&vx_run_ops);
1185   inferior_pid = pid;
1186   vx_running = 0;
1187
1188   mark_breakpoints_out ();
1189
1190   /* Set up the "saved terminal modes" of the inferior
1191      based on what modes we are starting it with.  */
1192   target_terminal_init ();
1193
1194   /* Install inferior's terminal modes.  */
1195   target_terminal_inferior ();
1196
1197   /* We will get a task spawn event immediately.  */
1198   init_wait_for_inferior ();
1199   clear_proceed_status ();
1200   stop_soon_quietly = 1;
1201   wait_for_inferior ();
1202   stop_soon_quietly = 0;
1203   normal_stop ();
1204 }
1205
1206
1207 /* detach_command --
1208    takes a program previously attached to and detaches it.
1209    The program resumes execution and will no longer stop
1210    on signals, etc.  We better not have left any breakpoints
1211    in the program or it'll die when it hits one.  For this
1212    to work, it may be necessary for the process to have been
1213    previously attached.  It *might* work if the program was
1214    started via the normal ptrace (PTRACE_TRACEME).  */
1215
1216 static void
1217 vx_detach (args, from_tty)
1218      char *args;
1219      int from_tty;
1220 {
1221   Rptrace ptrace_in;
1222   Ptrace_return ptrace_out;
1223   int signal = 0;
1224   int status;
1225
1226   if (args)
1227     error ("Argument given to VxWorks \"detach\".");
1228
1229   if (from_tty)
1230       printf ("Detaching pid %s.\n", local_hex_string(inferior_pid));
1231
1232   if (args)             /* FIXME, should be possible to leave suspended */
1233     signal = atoi (args);
1234   
1235   bzero ((char *)&ptrace_in,  sizeof (ptrace_in));
1236   bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1237   ptrace_in.pid = inferior_pid;
1238
1239   status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
1240   if (status == -1)
1241     error (rpcerr);
1242   if (ptrace_out.status == -1)
1243     {
1244       errno = ptrace_out.errno;
1245       perror_with_name ("Detaching VxWorks process");
1246     }
1247
1248   inferior_pid = 0;
1249   pop_target ();        /* go back to non-executing VxWorks connection */
1250 }
1251
1252 /* vx_kill -- takes a running task and wipes it out.  */
1253
1254 static void
1255 vx_kill (args, from_tty)
1256      char *args;
1257      int from_tty;
1258 {
1259   Rptrace ptrace_in;
1260   Ptrace_return ptrace_out;
1261   int status;
1262
1263   if (args)
1264     error ("Argument given to VxWorks \"kill\".");
1265
1266   if (from_tty)
1267       printf ("Killing pid %s.\n", local_hex_string(inferior_pid));
1268
1269   bzero ((char *)&ptrace_in,  sizeof (ptrace_in));
1270   bzero ((char *)&ptrace_out, sizeof (ptrace_out));
1271   ptrace_in.pid = inferior_pid;
1272
1273   status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
1274   if (status == -1)
1275     error (rpcerr);
1276   if (ptrace_out.status == -1)
1277     {
1278       errno = ptrace_out.errno;
1279       perror_with_name ("Killing VxWorks process");
1280     }
1281
1282   /* If it gives good status, the process is *gone*, no events remain.  */
1283   inferior_pid = 0;
1284   pop_target ();        /* go back to non-executing VxWorks connection */
1285 }
1286
1287 /* Clean up from the VxWorks process target as it goes away.  */
1288
1289 static void
1290 vx_proc_close (quitting)
1291      int quitting;
1292 {
1293   inferior_pid = 0;             /* No longer have a process.  */
1294   if (vx_running)
1295     free (vx_running);
1296   vx_running = 0;
1297 }
1298 \f
1299 /* Make an RPC call to the VxWorks target.
1300    Returns RPC status.  */
1301
1302 static enum clnt_stat
1303 net_clnt_call (procNum, inProc, in, outProc, out)
1304     enum ptracereq procNum;
1305     xdrproc_t inProc;
1306     char *in;
1307     xdrproc_t outProc;
1308     char *out;
1309 {
1310   enum clnt_stat status;
1311   
1312   status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
1313
1314   if (status != RPC_SUCCESS)
1315       clnt_perrno (status);
1316
1317   return status;
1318 }
1319
1320 /* Clean up before losing control.  */
1321
1322 static void
1323 vx_close (quitting)
1324      int quitting;
1325 {
1326   if (pClient)
1327     clnt_destroy (pClient);     /* The net connection */
1328   pClient = 0;
1329
1330   if (vx_host)
1331     free (vx_host);             /* The hostname */
1332   vx_host = 0;
1333 }
1334
1335 /* A vxprocess target should be started via "run" not "target".  */
1336 /*ARGSUSED*/
1337 static void
1338 vx_proc_open (name, from_tty)
1339      char *name;
1340      int from_tty;
1341 {
1342   error ("Use the \"run\" command to start a VxWorks process.");
1343 }
1344
1345 /* Target ops structure for accessing memory and such over the net */
1346
1347 struct target_ops vx_ops = {
1348         "vxworks", "VxWorks target memory via RPC over TCP/IP",
1349         "Use VxWorks target memory.  \n\
1350 Specify the name of the machine to connect to.",
1351         vx_open, vx_close, vx_attach, 0, /* vx_detach, */
1352         0, 0, /* resume, wait */
1353         0, 0, /* read_reg, write_reg */
1354         0, host_convert_to_virtual, host_convert_from_virtual,  /* prep_to_store, */
1355         vx_xfer_memory, vx_files_info,
1356         0, 0, /* insert_breakpoint, remove_breakpoint */
1357         0, 0, 0, 0, 0,  /* terminal stuff */
1358         0, /* vx_kill, */
1359         vx_load_command,
1360         vx_lookup_symbol,
1361         vx_create_inferior, 0,  /* mourn_inferior */
1362         core_stratum, 0, /* next */
1363         1, 1, 0, 0, 0,  /* all mem, mem, stack, regs, exec */
1364         0, 0,                   /* Section pointers */
1365         OPS_MAGIC,              /* Always the last thing */
1366 };
1367
1368 /* Target ops structure for accessing VxWorks child processes over the net */
1369
1370 struct target_ops vx_run_ops = {
1371         "vxprocess", "VxWorks process",
1372         "VxWorks process, started by the \"run\" command.",
1373         vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */
1374         vx_resume, vx_wait,
1375         vx_read_register, vx_write_register,
1376         vx_prepare_to_store, host_convert_to_virtual, host_convert_from_virtual,
1377         vx_xfer_memory, vx_run_files_info,
1378         vx_insert_breakpoint, vx_remove_breakpoint,
1379         0, 0, 0, 0, 0,  /* terminal stuff */
1380         vx_kill,
1381         vx_load_command,
1382         vx_lookup_symbol,
1383         0, vx_mourn_inferior,
1384         process_stratum, 0, /* next */
1385         0, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
1386                         /* all_mem is off to avoid spurious msg in "i files" */
1387         0, 0,                   /* Section pointers */
1388         OPS_MAGIC,              /* Always the last thing */
1389 };
1390 /* ==> Remember when reading at end of file, there are two "ops" structs here. */
1391 \f
1392 void
1393 _initialize_vx ()
1394 {
1395   add_target (&vx_ops);
1396   add_target (&vx_run_ops);
1397 }
This page took 0.099965 seconds and 4 git commands to generate.