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

4.104.114.84.95
Last change on this file since c92fb641 was 981b99f, checked in by Joel Sherrill <joel.sherrill@…>, on 08/10/99 at 16:41:44

Patch from Eric Valette <valette@…> and Emmanuel Raguet
<raguet@…>:

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