source: rtems/c/src/librdbg/src/servtgt.c @ e37d7196

4.104.114.84.95
Last change on this file since e37d7196 was 40cf43ea, checked in by Joel Sherrill <joel.sherrill@…>, on 02/01/02 at 17:00:01
  • So many patches have been posted recently on the mailing list and because we were unable to find correct solution to compile on various linux distros (due to rpcgen incompatibilities), and because the coding style of rdbg was rather inconsistant among various pieces of code, I decided to:

1) make some cleaning regarding global coding style (using

indent + manual edits),

2) incorporate/review the paches send by various people

(S. Holford, T. Strauman),

3) Fix the bug due to varying rpcgen code generation

in remdeb_svc.c,

4) Remove some dead code,
5) Apply a patches enabling to call enterRdbg imediately

after rdbg initialization is done,

NB : the paches is huge but it is mainly due to coding styke chnages.
Only few lines of codes have been really changed and they do not impact
rdbg functionnality (AFAIKT).

  • include/rdbg/servrpc.h, include/rdbg/i386/rdbg_f.h, include/rdbg/m68k/rdbg_f.h, include/rdbg/powerpc/rdbg_f.h, src/_servtgt.c, src/awk.svc, src/excep.c, src/ptrace.c, src/rdbg.c, src/remdeb.x, src/servbkpt.c, src/servcon.c, src/servrpc.c, src/servtgt.c, src/servtsp.c, src/servutil.c, src/i386/excep_f.c, src/i386/rdbg_f.c, src/i386/any/Makefile.am, src/i386/any/remdeb.h, src/i386/any/remdeb_svc.c, src/i386/any/remdeb_xdr.c, src/m68k/excep_f.c, src/m68k/rdbg_f.c, src/m68k/any/Makefile.am, src/m68k/any/remdeb.h, src/m68k/any/remdeb_svc.c, src/m68k/any/remdeb_xdr.c, src/powerpc/excep_f.c, src/powerpc/rdbg_f.c, src/powerpc/new_exception_processing/Makefile.am, src/powerpc/new_exception_processing/remdeb.h, src/powerpc/new_exception_processing/remdeb_svc.c, src/powerpc/new_exception_processing/remdeb_xdr.c: Modified.
  • Property mode set to 100644
File size: 17.3 KB
Line 
1/*
2 **************************************************************************
3 *
4 *  Component:  RDB servers
5 *  Module:     servtgt.c
6 *
7 * $Id$
8 *
9 **************************************************************************
10 */
11
12#include <string.h>
13#include <sys/errno.h>
14#include <rdbg/rdbg.h>
15#include <rdbg/servrpc.h>
16#include <sys/socket.h>
17#include <assert.h>
18
19#ifdef DDEBUG
20#define Ptrace  TgtDbgPtrace
21#else
22#define Ptrace  TgtRealPtrace
23#endif
24
25/*
26 * TgtBreakRestoreOrig - Restore original instruction at "addr"
27 * just before single-stepping it.
28 */
29
30  int
31TgtBreakRestoreOrig (int pid, void *addr, void *addr2)
32            /*
33             * Process identifier
34             */
35            /*
36             * Breakpoint address
37             */
38            /*
39             * Original instruction or bkpt number
40             */
41{
42  int ret;
43  int l;
44
45  l = (long) Ptrace (RPT_PEEKTEXT, pid, addr, 0, NULL); /* assume ok */
46  ret = ORG_BREAK (l, (UINT32) addr2);  /* reconstruct old instr */
47  ret = Ptrace (RPT_POKETEXT, pid, addr, ret, NULL);    /* poke back old */
48  return ret;
49}
50
51/*
52 *
53 *  TgtBreakCancelStep - Restore the breakpoint at "addr" if the single-step
54 *  has failed at the ptrace level.
55 */
56
57#define BKPT0(plst)     ((BASE_BREAK*)(plst)->break_list)
58
59  void
60TgtBreakCancelStep (PID_LIST * plst)
61{
62  assert (plst->break_list);
63  assert (BKPT0 (plst)->clr_step);
64
65  if (plst->break_list && BKPT0 (plst)->clr_step) {
66    int idx = BKPT0 (plst)->last_break;
67    int data;
68
69    data = Ptrace (RPT_PEEKTEXT, plst->pid,
70                   (char *) plst->break_list[idx].ee_loc, 0, NULL);
71    assert (!IS_BREAK (data));
72    Ptrace (RPT_POKETEXT, plst->pid,
73            (char *) plst->break_list[idx].ee_loc,
74            (int) SET_BREAK (data), NULL);
75  }
76}
77
78/*
79 * TgtCreateNew - add a new process into the process management lists.
80 */
81
82  void
83TgtCreateNew (PID pid, int conn, INT32 child, char *name, Boolean spawn)
84{
85  int idx;
86
87  for (idx = 0; idx < pid_list_cnt; idx++)
88    if (!pid_list[idx].pid)
89      break;                    /* find empty */
90
91  if (idx >= pid_list_cnt) {    /* no empties, add more */
92    PID_LIST *tmp_pid_list = pid_list;
93
94    pid_list_cnt += PID_LIST_INC;
95    pid_list = (PID_LIST *) Realloc (pid_list,  /* get new or extend */
96                                     pid_list_cnt * sizeof (PID_LIST));
97    if (!pid_list) {            /* out of memory */
98      pid_list_cnt -= PID_LIST_INC;
99      if (pid_list_cnt) {       /* realloc failed - malloc again */
100        pid_list = tmp_pid_list;
101        /*
102         * above relies on old pointer being valid after failed realloc
103         */
104      }
105      return;                   /* failed */
106    }
107    /*
108     * now clear newly added space
109     */
110    memset (pid_list + pid_list_cnt - PID_LIST_INC, 0,
111            PID_LIST_INC * sizeof (PID_LIST));
112    idx = pid_list_cnt - PID_LIST_INC;
113  } else                        /* clear entry we found */
114    memset (&pid_list[idx], 0, sizeof (PID_LIST));
115
116  /*
117   * now fill in empty entry
118   */
119  pid_list[idx].pid = pid;
120  pid_list[idx].running = 1;    /* we have not called wait yet */
121  pid_list[idx].primary_conn = (UCHAR) conn;    /* primary owner */
122  if (conn != -1) {             /* found caller */
123    pid_list[idx].owners = 1;
124    PIDMAP_SET (conn, idx);     /* mask in */
125  }
126  pid_list[idx].thread = (UINT32) - 1;  /* no thread for now */
127  pid_list[idx].last_start = LAST_START;    /* handle MiX bug */
128
129  pid_list[idx].name = name ? (char *) StrDup (name) : (char *) NULL;
130
131}
132
133/*
134 * TgtNotifyWaitChange - send event to clients indicating child changed state.
135 */
136
137  void
138TgtNotifyWaitChange (PID pid, int status, Boolean exclude)
139{
140  int conn, idx;
141
142  idx = FindPidEntry (pid);     /* locate the pid that changed */
143  if (idx < 0) {
144    DPRINTF (("TgtNotifyWaitChange: pid %d not in our list\n", (int) pid));
145    return;                     /* not in our list */
146  }
147  pid_list[idx].running = 0;    /* not running */
148  pid_list[idx].state = status; /* save status of stop/term */
149  if (!pid_list[idx].owners && !STS_SIGNALLED (status))
150    TgtDelete (&pid_list[idx], -1, 0);  /* terminated and no owners */
151  else {                        /* normal cases */
152    for (conn = 0; conn < conn_list_cnt; conn++) {  /* now find all interested clients */
153      if (!conn_list[conn].in_use   /* free entry */
154          || !PIDMAP_TEST (conn, idx))
155        continue;               /* not using this pid */
156      if (conn == exclude)
157        continue;               /* do not do this one */
158      TspSendWaitChange (conn, BMSG_WAIT, 1, pid, 0, False);    /* notify of change */
159    }
160  }
161}
162
163/*
164 *  TgtNotifyAll - send a message to all clients interested in process.
165 */
166
167  void
168TgtNotifyAll (int pid_idx, BACK_MSG msg, UINT16 spec,
169              UINT32 context, int exclude, Boolean force)
170{
171  int conn;
172
173  DPRINTF (("TgtNotifyAll: msg %d (%s) for pid_idx=%d (%d,%d)\n",
174            msg, BmsgNames[msg], pid_idx, exclude, force));
175  for (conn = 0; conn < conn_list_cnt; conn++)
176    if (conn_list[conn].in_use  /* not free */
177        && PIDMAP_TEST (conn, pid_idx)) {
178      if (conn != exclude)
179        TspSendWaitChange (conn, msg, spec, pid_list[pid_idx].pid, context,
180                           force);
181    }
182}
183
184/*
185 * TgtDelete - mark process as now uncontrolled.
186 *
187 *  Notes:
188 *     - this function removes a process from the process list.
189 *     - the notify argument indicates a message to send if needed.
190 */
191
192  void
193TgtDelete (PID_LIST * plst, int conn_idx, BACK_MSG notify)
194{
195  int idx = plst - pid_list, cnt, conn;
196
197  /*
198   * found
199   */
200  cnt = pid_list[idx].owners;
201  if (cnt) {                    /* some connections to break */
202    for (conn = 0; cnt && conn < conn_list_cnt; conn++)
203      if (conn_list[conn].in_use    /* not free */
204          && PIDMAP_TEST (conn, idx)) { /* found one that uses it */
205        PIDMAP_CLEAR (conn, idx);
206        if (notify && conn != conn_idx)
207          TspSendWaitChange (conn, notify, 0, plst->pid, 0, True);
208        if (!--cnt)
209          break;
210      }
211  }
212  if (pid_list[idx].name)
213    Free (pid_list[idx].name);  /* free string name back */
214  /*
215   * Free breakpoint list
216   */
217  if (pid_list[idx].break_list != NULL) {
218    Free (pid_list[idx].break_list);
219  }
220  pid_list[idx].pid = 0;        /* gone */
221}
222
223/*
224 * TgtKillAndDelete - kill or detach process and remove entry.
225 */
226
227  int
228TgtKillAndDelete (PID_LIST * plst, struct svc_req *rqstp, Boolean term)
229{
230  ptrace_in pin;                /* used for ptrace call */
231  ptrace_out *pout;
232
233  /*
234   * Remove breakpoints
235   */
236  if (plst->break_alloc > 0) {
237    pin.pid = plst->pid;
238    pin.addr.req = RPT_CLRBREAK;
239    pin.data = 0;               /* clear all */
240    pin.flags = PTRFLG_NON_OWNER;
241    pout = RPCGENSRVNAME (ptrace_2_svc) (&pin, rqstp);
242    if (pout->result < 0) {
243      DPRINTF (("TgtKillAndDelete: RPT_CLRBREAK failed %d\n", getErrno ()));
244      return -1;
245    }
246  }
247
248  if (term) {                   /* kill */
249    pin.addr.ptrace_addr_data_in_u.address = 0;
250    pin.data = -1;              /* Don't want notification from slave */
251    pin.addr.req = RPT_KILL;
252  } else {                      /* detach */
253    pin.addr.ptrace_addr_data_in_u.address = 1;
254    pin.data = 0;
255    pin.addr.req = RPT_DETACH;
256  }
257  pin.pid = plst->pid;
258  pin.flags = PTRFLG_FREE | PTRFLG_NON_OWNER;
259
260  DPRINTF (("TgtKillAndDelete: ptrace_2_svc (%s (%d), %d)\n",
261            PtraceName (pin.addr.req), pin.addr.req, pin.pid));
262
263  pout = RPCGENSRVNAME (ptrace_2_svc) (&pin, rqstp);    /* start it */
264  if (pout->errNo == ESRCH && plst->pid)
265    TgtDelete (plst, -1, BMSG_KILLED);  /* only entry remains */
266  return 0;
267}
268
269/*
270 * TgtDetachCon - detach a connection's ownership of a process.
271 */
272
273  void
274TgtDetachCon (int conn_idx, int pid_idx, Boolean delete)
275{
276  if ((unsigned) pid_idx >= pid_list_cnt || !pid_list[pid_idx].pid)
277    return;                     /* not valid */
278  if (PIDMAP_TEST (conn_idx, pid_idx)) {    /* if an owner, release control */
279    PIDMAP_CLEAR (conn_idx, pid_idx);
280
281    if (pid_list[pid_idx].owners)
282      pid_list[pid_idx].owners--;
283    if (pid_list[pid_idx].primary_conn == conn_idx)
284      pid_list[pid_idx].primary_conn = NO_PRIMARY;
285    if (delete
286        && !pid_list[pid_idx].owners && PROC_TERMINATED (pid_list + pid_idx))
287      TgtDelete (&pid_list[pid_idx], -1, 0);    /* remove entry */
288  }
289}
290
291/* -----------------------------------------------------------------------
292   TgtHandleChildChange - decide what action to take after wait() returns.
293                Used in the master only.
294   ----------------------------------------------------------------------- */
295
296#ifdef DDEBUG
297static char *LastStartNames[] = {
298  "NONE", "STEP", "CONT", "RANGE",
299  "STEPOFF", "KILLED", "DETACHED"
300};
301
302  char *
303GetLastStartName (int last_start)
304{
305  static char buf[32];
306
307  strcpy (buf, LastStartNames[last_start & ~LAST_START]);
308  if (last_start & LAST_START) {
309    strcat (buf, "+START");
310  }
311  return buf;
312}
313#endif
314
315  Boolean
316TgtHandleChildChange (PID pid, int *status, int *unexp,
317                      CPU_Exception_frame * ctx)
318{                               /* return False if continue, else stop */
319  int idx, sig;
320  int bidx = 0;
321  PID_LIST *plst;
322  unsigned long PC;
323  BASE_BREAK *base = NULL;      /* break_list[0] is really BASE_BREAK */
324  int hadStepEmul;
325  int origHadStepEmul;
326  int stopWanted;
327
328  DPRINTF (("TgtHandleChildChange: pid %d status %x cap\n",
329            (int) pid, *status));
330  if (unexp)
331    *unexp = 0;                 /* initialize to ok */
332
333  /*
334   * first, find pid in question
335   */
336  idx = FindPidEntry (pid);
337  if (idx < 0) {                /* cannot locate this process */
338    DPRINTF (("TgtHandleChildChange: unknown process (%s pid)\n",
339              FindPidEntry (pid) >= 0 ? "stale" : "unknown"));
340    if (unexp)
341      *unexp = 1;               /* Unexpected change */
342    return (False);             /* unknown: ignore (used to stop and notify) */
343  }
344
345  /*
346   * found
347   */
348  plst = &pid_list[idx];        /* pointer to entry */
349  /*
350   * first we see if just stopped
351   */
352
353  /*
354   * copy ctxt
355   */
356  CtxToRegs (ctx, &(plst->regs));
357
358  stopWanted = plst->stop_wanted;
359  plst->stop_wanted = 0;        /* For the next time */
360
361  hadStepEmul = BreakClear (plst, -1, -1) > 0;
362  origHadStepEmul = hadStepEmul;    /* hadStepEmul is cleared if real bkpt met */
363
364  if (STS_SIGNALLED (*status)) {    /* stopped, not terminated */
365    sig = STS_GETSIG (*status); /* signal that stopped us */
366
367    /*
368     * now, we read the registers and see what to do next
369     */
370    if (TgtPtrace (RPT_GETREGS, pid, (void *) &plst->regs, 0, NULL) < 0) {
371      memset (&plst->regs, 0, sizeof (plst->regs));
372    }
373
374    /*
375     * Get current thread
376     */
377    plst->thread = TgtPtrace (RPT_GETTARGETTHREAD, pid, NULL, 0, NULL);
378
379    if (sig == SIGTRAP) {       /* stopped from break/step */
380      PC = plst->regs.REG_PC;
381      /*
382       * Must check PC to see whether in situations where we had
383       * step emulation we are on a breakpoint or just
384       * have returned from an emulated single-step
385       */
386      if (BreakIdentify (plst, 0 /*no adjust */ , -1 /*no thread */ ) > 0) {
387        hadStepEmul = 0;
388      }
389      plst->is_step = hadStepEmul || IS_STEP (plst->regs)
390        || plst->last_start == LAST_START;
391      DPRINTF (("TgtHandleChildChange: %s last_start %s\n", plst->is_step
392                ? "step" : "break", GetLastStartName (plst->last_start)));
393
394      if ((plst->is_step || origHadStepEmul || stopWanted)
395          && (plst->last_start == LAST_STEP
396              || plst->last_start == LAST_STEPOFF
397              || plst->last_start == LAST_RANGE)) {
398        DPRINTF (("TgtHandleChildChange: restoring stepped-off bkpt\n"));
399        BreakSteppedOff (plst);
400      }
401
402      if (plst->last_start == LAST_STEPOFF && (plst->is_step || origHadStepEmul)) { /* stepped off break and now need cont */
403        DPRINTF (("TgtHandleChildChange: auto-resuming after step-off\n"));
404        plst->last_start = LAST_CONT;   /* convert to normal cont */
405        if (!stopWanted) {
406          if (TgtPtrace (RPT_CONT, pid, (char *) 1, 0, NULL))
407            return True;        /* tell people */
408          return (False);       /* wait for change */
409        }
410        DPRINTF (("TgtHandleChildChange: stop_wanted %d in step-off\n",
411                  stopWanted));
412        *status = STS_MAKESIG (stopWanted);
413        return True;            /* Stop and notify */
414      }
415
416      base = plst->break_list ? ((BASE_BREAK *) plst->break_list) :
417        ((BASE_BREAK *) NULL);
418      /*
419       * now see if step in range
420       */
421
422      if (plst->last_start == LAST_RANGE    /* step in range */
423          && (plst->is_step || origHadStepEmul) /* not a breakpoint */
424          &&PC >= base->range_start && PC <= base->range_end) { /* still in range, keep going */
425        if (stopWanted) {
426          DPRINTF (("TgtHandleChildChange: stop_wanted %d in step-range\n",
427                    stopWanted));
428        } else {
429          DPRINTF (("TgtHandleChildChange: Reservation at %x\n",
430                    plst->regs.REG_PC));
431        }
432      }
433      if (!plst->is_step) {     /* was break */
434        bidx = BreakIdentify (plst, 1 /*adjust */ , plst->thread);
435        if (bidx == 0) {
436          DPRINTF (("TgtHandleChildChange: forwarding bkpt to kernel\n"));
437          if (unexp) {
438            *unexp = 1;
439          }
440          return False;
441        }
442        if (bidx < 0) {         /* Unwanted breakpoint, must step it off */
443          ptrace_in pin;
444          ptrace_out *out;
445          if (origHadStepEmul) {
446            DPRINTF (("TgtHandleChildChange: bkpt %x becomes step\n",
447                      plst->regs.REG_PC));
448            bidx = -bidx;
449            plst->is_step = 1;
450            base->clr_step = plst->break_list[bidx].type == BRKT_INSTR;
451            base->last_break = bidx;
452            return True;
453          }
454          if (stopWanted) {
455            DPRINTF (("TgtHandleChildChange: stop_wanted %d at bkpt %x\n",
456                      stopWanted, plst->regs.REG_PC));
457            /*
458             * The PC has already been adjusted by BreakIdentify
459             */
460            *status = STS_MAKESIG (stopWanted);
461            return True;
462          }
463          /*
464           * All the handling is done in ptrace_2_svc() so call it
465           */
466          bidx = -bidx;
467          DPRINTF (("TgtHandleChildChange: last %d (%s) restarting bkpt %d\n",
468                    plst->last_start, GetLastStartName (plst->last_start),
469                    bidx));
470          base->clr_step = 1;
471          base->last_break = bidx;  /* remember which one */
472          plst->running = 0;    /* So that ptrace is accepted */
473          pin.pid = plst->pid;
474
475          if (plst->last_start == LAST_STEP) {
476            pin.addr.req = RPT_SINGLESTEP;
477          } else {
478            pin.addr.req = RPT_CONT;
479          }
480          pin.addr.ptrace_addr_data_in_u.address = 1;
481          pin.data = 0;
482          pin.flags = PTRFLG_NON_OWNER;
483          out = RPCGENSRVNAME (ptrace_2_svc) (&pin, NULL);
484          if (out->result == 0)
485            return False;       /* Continue waiting */
486          DPRINTF (("TgtHandleChildChange: failed to restart bkpt!\n"));
487          /*
488           * If something went wrong, just stop on breakpoint
489           */
490        }
491      }
492    }
493
494    /*
495     * else sig != SIGTRAP
496     */
497    /*
498     * finally, fill in stop info in break point array base
499     */
500    if (bidx > 0) {             /* store break info */
501      /*
502       * will need to get off the break for SW breakpoints only
503       */
504      base->clr_step = plst->break_list[bidx].type == BRKT_INSTR;
505      base->last_break = bidx;  /* remember which one */
506    } else if (base) {          /* clear break info */
507      base->clr_step = False;   /* not stopped on break */
508      base->last_break = 0;
509    }
510    /*
511     * decision to notify owner based on last_start
512     */
513  } /* stopped */
514  else {                        /* terminated */
515
516    if (plst->last_start == LAST_START) {   /* spawn failed */
517      TgtNotifyAll (idx, BMSG_EXEC_FAIL, 0, 0, -1, True);
518      plst->running = False;    /* not running - dead */
519      plst->state = *status;    /* contains errno in high word */
520      return (False);
521    }
522
523    else if ((UCHAR) (plst->last_start & ~LAST_START) < (UCHAR) LAST_KILLED)
524      plst->last_start = LAST_NONE; /* doesn't matter anymore */
525    else
526      return (False);           /* killed and detach already notified */
527  }
528  return (True);                /* stop and notify */
529}
530
531#ifdef DDEBUG
532
533/*
534 * TgtDbgPtrace - debug version of ptrace.
535 */
536
537  int
538TgtDbgPtrace (int request, PID pid, char *addr, int data, void *addr2)
539{
540  int diag;
541
542  DPRINTF (("TgtDbgPtrace: entered (%s (%d), %d, %x, %d, %x)\n",
543            PtraceName (request), request, pid, (int) addr, data,
544            (int) addr2));
545
546  if (request == RPT_WRITETEXT || request == RPT_WRITEDATA) {
547    int i;
548
549    DPRINTF (("TgtDbgPtrace:"));
550    if (rdb_debug) {
551      for (i = 0; i < data && i < 16; ++i) {
552        printf (" %02x", ((char *) addr2)[i] & 0xFF);
553      }
554      printf ("\n");
555    }
556  }
557
558  diag = TgtRealPtrace (request, pid, addr, data, addr2);
559
560  DPRINTF (("TgtDbgPtrace: returned %d (%x) errno %d\n",
561            diag, diag, getErrno ()));
562
563  if (request == RPT_GETREGS || request == RPT_GETTHREADREGS
564      || request == RPT_SETREGS || request == RPT_SETTHREADREGS) {
565    /*
566     * Use DPRINTF() so as to have the id prefix
567     */
568    DPRINTF (("TgtDbgPtrace: (%s) PC = %x, SP = %x, FP = %x\n",
569              PtraceName (request),
570              ((xdr_regs *) addr)->REG_PC,
571              ((xdr_regs *) addr)->REG_SP, ((xdr_regs *) addr)->REG_FP));
572  }
573
574  return (diag);
575}
576#endif /* DDEBUG */
Note: See TracBrowser for help on using the repository browser.