source: rtems/c/src/lib/librdbg/servtgt.c @ 196094eb

4.104.114.84.95
Last change on this file since 196094eb was 4721cf1, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 3, 1998 at 11:54:14 PM

Patch from Emmanuel Raguet <raguet@…> to add remote debug server
and RPC support to RTEMS. Thanks. :) Email follows:

Hello,

For Xmas, here is the Remote Debugger on RTEMS !

Here are 2 patches for the Remote Debugger on RTEMS for pc386 from Linux
host :

  • one for RTEMS it self,
  • one for GDB-4.17.

1/ RTEMS patch
--------------

This patch adds 2 libraries :

  • a simplified SUN RPC library
  • the Remote Debugger library

The configuration command is the following :
../rtems4/configure --target=i386-rtemself --enable-rtemsbsp=pc386
--enable-rdbg

The SUN RPC library is built only if networking is set.
The RDBG library is built if networking and enable-rdbg are set.

The function used to initialize the debugger is :

rtems_rdbg_initialize ();

A special function has been created to force a task to be
in a "debug" state : enterRdbg().
The use of this function is not mandatory.

2/ GDB-4.17 patch
-----------------

This patch create a new RTEMS target for GDB-4.17.

The configuration command is the following :
./configure --enable-shared --target=i386RTEMS

To connect to a target, use :

target rtems [your_site_address]

Then, attach the target using : attach 1

And... Debug ;)

You can obtain the original GDB-4.17 on
ftp://ftp.debian.org/debian/dists/stable/main/source/devel/gdb_4.17.orig.tar.gz

This has been tested from a Debian 2.0.1 linux host.

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