source: rtems/c/src/librdbg/src/servbkpt.c @ b0e2360

4.104.114.84.95
Last change on this file since b0e2360 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: 15.8 KB
Line 
1/*
2 **********************************************************************
3 *
4 *  Component:  RDB servers
5 *  Module:     servbkpt.c
6 *
7 *  Synopsis:   Management of breakpoints
8 *
9 * $Id$
10 *
11 **********************************************************************
12 */
13
14#include <sys/errno.h>
15#include <assert.h>
16#include <rdbg/rdbg.h>
17#include <rdbg/servrpc.h>
18
19/*----- Macros -----*/
20
21#define BKPT0(plst)     ((BASE_BREAK*)(plst)->break_list)
22#define BKPT_INCR       5           /* how many bkpt slots alloc at a time */
23
24#define BKPT_OVER(plst,idx,addr,size) \
25    ((plst)->break_list[idx].ee_loc + BREAK_SIZE > (UINT32) (addr) \
26    &&  (plst)->break_list[idx].ee_loc < (UINT32) (addr) + (size))
27
28#define BKPT_SLOTS \
29        (sizeof ((xdr_break*) 0)->thread_list / \
30         sizeof ((xdr_break*) 0)->thread_list [0])
31
32    /*
33     *  BreakAlloc - alloc a breakpoint entry.
34     *
35     *  This is a generic routine to insert an entry in the
36     *  breakpoint list. It returns the number of entry just
37     *  created. It returns -1 if failed.
38     */
39
40  static int
41BreakAlloc (PID_LIST * plst, Boolean normal)
42{
43  int idx, len;
44  xdr_break *blst;
45
46  if (!normal) {                /* want 0 entry */
47    if (plst->break_list) {
48      return (0);               /* already there */
49    }
50    idx = 1;                    /* force alloc below */
51  } else {
52    for (idx = 1; idx < (int) plst->break_alloc; idx++) {
53      if (plst->break_list[idx].type == BRKT_NONE) {
54        /*
55         * got a free one
56         */
57        memset (&plst->break_list[idx], 0, sizeof (xdr_break));
58        return (idx);           /* found one */
59      }
60    }
61  }
62  /*
63   * idx is the requested entry
64   */
65
66  if (idx >= (int) plst->break_alloc) { /* need more space */
67    len = plst->break_alloc + BKPT_INCR;
68    blst = (xdr_break *) Realloc (plst->break_list, len * sizeof (xdr_break));
69    if (!blst) {
70      return (-1);              /* failed, no space */
71    }
72    plst->break_alloc = len;    /* got more */
73    plst->break_list = blst;
74
75    /*
76     * Clear new space
77     */
78    memset (blst + len - BKPT_INCR, 0, BKPT_INCR * sizeof (xdr_break));
79    idx = len - BKPT_INCR;      /* next available */
80    if (!idx) {
81      idx = 1;                  /* for normal cases */
82    }
83  }
84  return (normal ? idx : 0);    /* return it */
85}
86
87    /*
88     *  BreakSet - set a breakpoint in process
89     *
90     *  Returns the number or -1/errno.
91     */
92
93#ifdef DDEBUG
94static const char *BreakTypes[] = {
95  "NONE", "INSTR", "READ", "WRITE",
96  "ACCESS", "EXEC", "OS_CALL", "OS_SWITCH",
97  "STEPEMUL"
98};
99
100#define BN_MAX          (sizeof BreakTypes / sizeof BreakTypes[0])
101#define BREAK_NAME(t)   ((unsigned) (t) < BN_MAX ? BreakTypes[t] : "???")
102#endif
103
104  int
105BreakSet (PID_LIST * plst, int conn_idx, xdr_break * bkpt)
106{
107  int pid = plst->pid;
108  int type = bkpt->type;
109  void *addr = (void *) bkpt->ee_loc;
110  int idx;
111  int data;
112
113  DPRINTF (("BreakSet: type %d (%s) at 0x%x th %d ee_type %d len %d "
114            "pass %d curr %d list %d %d %d %d\n", type, BREAK_NAME (type),
115            (int) addr,
116            bkpt->thread_spec, bkpt->ee_type, bkpt->length, bkpt->pass_count,
117            bkpt->curr_pass, bkpt->thread_list[0], bkpt->thread_list[1],
118            bkpt->thread_list[2], bkpt->thread_list[3]));
119
120  idx = BreakAlloc (plst, True);    /* get entry */
121  if (idx < 0) {                /* no memory */
122    setErrno (ENOMEM);          /* set for safety */
123    return -1;                  /* return the error */
124  }
125
126  data = TgtPtrace (RPT_PEEKTEXT, pid, addr, 0, NULL);  /* current */
127  if (getErrno ()) {
128    return -1;                  /* failed, return the error */
129  }
130  if (IS_BREAK (data)) {        /* There is already a break here */
131    DPRINTF (("BreakSet: already have soft bkpt at %x\n", addr));
132    if (type == BRKT_STEPEMUL) {
133      ++BKPT0 (plst)->pad1;
134      return 1;                 /* Any non-error value is OK */
135    }
136    setErrno (EBUSY);
137    return -1;
138  }
139
140  TgtPtrace (RPT_POKETEXT, pid, addr, SET_BREAK (data), NULL);
141
142  if (getErrno ()) {
143    return -1;
144  }
145
146  plst->break_list[idx] = *bkpt;
147  plst->break_list[idx].ee_type = data; /* saved data */
148
149  /*
150   * Inform other owners
151   */
152  if (type != BRKT_STEPEMUL) {
153    TgtNotifyAll (plst - pid_list, BMSG_BREAK, 1 /*added */ , idx,
154                  conn_idx, False);
155  } else {
156    ++BKPT0 (plst)->pad1;
157  }
158  /*
159   * Return the number
160   */
161  setErrno (0);                 /* Just in case */
162  return idx;
163}
164
165  int
166BreakSetAt (PID_LIST * plst, int conn_idx, unsigned long addr,
167            break_type type)
168{
169  xdr_break xb;
170
171  memset (&xb, 0, sizeof xb);
172  xb.type = type;
173  xb.ee_loc = addr;
174  return BreakSet (plst, conn_idx, &xb);
175}
176
177/*----- Find a breakpoint by address -----*/
178
179  int
180BreakGetIndex (PID_LIST * plst, void *addr)
181{
182  int idx;
183  int data = -1;
184
185  if (!plst->break_alloc) {
186    setErrno (EFAULT);
187    return -1;
188  }
189  for (idx = 1; idx < (int) plst->break_alloc; idx++) {
190    if ((u_long) addr == plst->break_list[idx].ee_loc) {
191      data = idx;
192      break;
193    }
194  }
195  return data;
196}
197
198/*----- Getting information about breakpoint -----*/
199
200    /*
201     *  If data > 0, fill "bkpt" with information about breakpoint
202     *  and return the number of the next one.
203     *  If data == 0, return the count of breakpoints.
204     */
205
206  int
207BreakGet (const PID_LIST * plst, int data, xdr_break * bkpt)
208{
209  int idx;
210
211  if (!data) {                  /* just count them */
212    for (idx = 1; idx < (int) plst->break_alloc; idx++) {
213      if (plst->break_list[idx].type != BRKT_NONE) {
214        data++;
215      }
216    }
217    return data;                /* count */
218  }
219  if ((unsigned) data >= plst->break_alloc) {
220    /*
221     * out of range
222     */
223    setErrno (EFAULT);          /* closest match */
224    return -1;
225  }
226  /*
227   * get it and say which is next
228   */
229  *bkpt = plst->break_list[data];
230  for (idx = (int) data + 1; idx < (int) plst->break_alloc; idx++) {
231    if (plst->break_list[idx].type != BRKT_NONE) {
232      return idx;
233    }
234  }
235  return 0;                     /* otherwise returns 0 for no more */
236}
237
238/*----- Clearing bkpts -----*/
239
240    /*
241     *  BreakClear - clear one (if data != 0) or all breakpoints
242     *  (if data == 0). Return the number of bkpts cleared.
243     *  If (data == -1), remove step-emulation breakpoints.
244     */
245
246  int
247BreakClear (PID_LIST * plst, int conn_idx, int data)
248{
249  int pid_idx = plst - pid_list;
250  int idx;
251  int cleared = 0;
252  int clearStepEmul = 0;
253  int terminated = PROC_TERMINATED (plst);
254  int stepEmulCount = 0;
255
256  /*
257   * break handle in data
258   */
259  if (!plst->break_alloc) {     /* there are no breaks */
260    DPRINTF (("BreakClear: no bkpts defined.\n"));
261    setErrno (EFAULT);          /* closest match */
262    return -1;                  /* return error */
263  }
264  if (!data) {                  /* clear all */
265    idx = 1;
266    data = plst->break_alloc - 1;
267
268    /*
269     * Inform other owners
270     */
271    DPRINTF (("BreakClear: clearing all bkpts.\n"));
272    TgtNotifyAll (pid_idx, BMSG_BREAK, 0 /*clr */ , 0, conn_idx, False);
273
274  } else if (data == -1) {      /* clear all step-emul bkpts */
275    DPRINTF (("BreakClear: removing %d step-emul bkpts\n",
276              BKPT0 (plst)->pad1));
277
278    stepEmulCount = BKPT0 (plst)->pad1;
279    BKPT0 (plst)->pad1 = 0;
280
281    clearStepEmul = 1;
282    idx = 1;
283    data = plst->break_alloc - 1;
284  } else if ((unsigned) data >= plst->break_alloc
285             || plst->break_list[data].type == BRKT_NONE) {
286
287    /*
288     * out of range
289     */
290    DPRINTF (("BreakClear: invalid bkpt %d\n", data));
291    setErrno (EFAULT);          /* closest match */
292    return -1;                  /* return error */
293  } else {
294    idx = data;
295    /*
296     * Inform other owners
297     */
298    TgtNotifyAll (pid_idx, BMSG_BREAK, 0 /*clr */ , idx, conn_idx, False);
299    DPRINTF (("BreakClear: clearing bkpt %d\n", data));
300  }
301
302  for (; idx <= data; idx++) {  /* clear each one */
303    int type = plst->break_list[idx].type;
304
305    if (clearStepEmul && type != BRKT_STEPEMUL)
306      continue;
307
308    if (type == BRKT_INSTR || (clearStepEmul && type == BRKT_STEPEMUL)) {
309      /*
310       * just patch back
311       */
312      char *addr = (char *) plst->break_list[idx].ee_loc;
313      int val;
314
315      if (BKPT0 (plst)->clr_step && BKPT0 (plst)->last_break == idx) {
316        BKPT0 (plst)->clr_step = 0; /* not needed */
317      }
318      /*
319       * Neighboring bytes can have breakpoints too...
320       */
321      if (!terminated) {
322        setErrno (0);
323        val = TgtPtrace (RPT_PEEKTEXT, plst->pid, addr, 0, NULL);
324        if (getErrno ()) {
325          DPRINTF (("BreakClear: addr %x not readable!\n", addr));
326          setErrno (0);         /* Forget bkpt */
327        } else {
328          assert (IS_BREAK (val));
329          val = ORG_BREAK (val, (int) plst->break_list[idx].ee_type);
330          TgtPtrace (RPT_POKETEXT, plst->pid, addr, val, NULL);
331          if (getErrno ()) {
332            DPRINTF (("BreakClear: addr %x not writable!\n", addr));
333            setErrno (0);
334          }
335        }
336      }
337      ++cleared;                /* indicate cleared */
338    }
339    memset (&plst->break_list[idx], 0, sizeof (xdr_break));
340  }
341  assert (!clearStepEmul || cleared <= stepEmulCount);
342  if (stepEmulCount && cleared == 0) {
343    DPRINTF (("BreakClear: all STEPEMUL bkpts were shared\n"));
344    return 1;
345  }
346  return cleared;
347}
348
349/*----- Hiding of breakpoints -----*/
350
351    /*
352     *  PatchBreak - patch original data from break into data buffer.
353     *
354     * Notes:
355     *  - this routine patches the original data under a break into the data
356     *    buffer from a ptrace read/peek.
357     */
358
359  static void
360PatchBreak (char *buff, UINT32 bstart, int bsize, UINT32 dstart, char *dvalue)
361{
362  int size = BREAK_SIZE;        /* default size */
363
364  /*
365   * Must deal with all sorts of unalignments
366   * * (3 full overlaps, 3 unaligns)
367   */
368  if (bsize < BREAK_SIZE) {
369    /*
370     * case where buffer is smaller than data
371     */
372    memcpy (buff, dvalue + (bstart - dstart), bsize);   /* copy over */
373    return;
374  }
375  /*
376   * buffer larger than data.
377   * * we need to see where break fits in buffer and whether
378   * * we have part of it off the end. We set bstart to be the
379   * * buffer offset, dtart to be the break data offset, and
380   * * size to be the amount to copy
381   */
382  if (dstart < bstart) {
383    /*
384     * break before actual buffer
385     */
386    dstart = bstart - dstart;   /* offset in data */
387    size -= dstart;             /* amount to copy */
388    bstart = 0;                 /* offset in buffer */
389
390  } else if (dstart + size > bstart + bsize) {
391    /*
392     * off end
393     */
394    bstart += bsize;            /* end of buffer */
395    size -= (dstart + size) - bstart;
396    bstart = bsize - size;      /* come back into buffer enough */
397    dstart = 0;                 /* start of data */
398
399  } else {                      /* normal case */
400    bstart = dstart - bstart;   /* offset in buffer */
401    dstart = 0;
402  }
403  memcpy (buff + bstart, dvalue + dstart, size);
404}
405
406  void
407BreakHide (const PID_LIST * plst, void *addr, int data, void *addr2)
408{
409  int idx;
410
411  if (!plst->break_list)        /* no breaks exist, so skip this */
412    return;
413
414  /*
415   * if breakpoints, replace
416   */
417
418  for (idx = 1; idx < (int) plst->break_alloc; idx++) {
419    int type = plst->break_list[idx].type;
420
421    if (type != BRKT_INSTR && type != BRKT_STEPEMUL) {
422      continue;
423    }
424    /*
425     * break, see if overlaps
426     */
427    if (BKPT_OVER (plst, idx, addr, data)) {
428
429      /*
430       * overlaps, patch in old value
431       */
432      PatchBreak ((char *) addr2, (UINT32) addr, data,
433                  plst->break_list[idx].ee_loc,
434                  (char *) &plst->break_list[idx].ee_type);
435    }
436  }
437}
438
439/*----- Checking of breakpoint overwrites -----*/
440
441    /*
442     *  BreakOverwrite - check if memory write does not involve addresses
443     *  having software breakpoints.
444     */
445
446  int
447BreakOverwrite (const PID_LIST * plst, const char *addr, unsigned int size)
448{
449  int idx;
450
451  if (!plst->break_list) {      /* No breaks exist */
452    return 0;
453  }
454
455  for (idx = 1; idx < (int) plst->break_alloc; idx++) {
456    int type = plst->break_list[idx].type;
457
458    /*
459     * Consider only breakpoints involving modified memory
460     */
461    if (type != BRKT_INSTR && type != BRKT_STEPEMUL) {
462      continue;
463    }
464    if (BKPT_OVER (plst, idx, addr, size)) {
465      return -1;                /* overlaps */
466    }
467  }
468  return 0;
469}
470
471/*----- Execution support -----*/
472
473    /*
474     *  BreakStepRange - Start stepping in a range.
475     *
476     *  Range is saved in breakpoint 0.
477     */
478
479  int
480BreakStepRange (PID_LIST * plst, void *addr, int len)
481{
482  if (!plst->break_list) {
483    /*
484     * get list
485     */
486    if (BreakAlloc (plst, False) == -1) {   /* must not be any memory */
487      setErrno (ENOMEM);        /* to be safe */
488      return -1;                /* fails */
489    }
490  }
491  BKPT0 (plst)->range_start = (UINT32) addr;
492  BKPT0 (plst)->range_end = (UINT32) addr + (len - 1);
493  return 0;
494}
495
496    /*
497     *  If the Program Counter is changed, consider that the
498     *  current breakpoint has not been reached yet.
499     */
500
501  void
502BreakPcChanged (PID_LIST * plst)
503{
504  if (plst->break_list) {
505    /*
506     * clear break stuff
507     */
508    BKPT0 (plst)->clr_step = False;
509  }
510}
511
512    /*
513     *  BreakStepOff - prepare stepping off a breakpoint.
514     */
515
516  int
517BreakStepOff (const PID_LIST * plst, void **paddr2)
518{
519  if (plst->break_list && BKPT0 (plst)->clr_step) {
520
521    /*
522     * need clear then step off break
523     */
524    int last = BKPT0 (plst)->last_break;
525
526    /*
527     * clear break, step, then do exec
528     */
529
530    *paddr2 = (void *) plst->break_list[last].ee_type;
531
532    /*
533     * Need to clr_step after TgtPtrace() when wait() returns
534     */
535    return 1;
536  }
537  return 0;
538}
539
540    /*
541     *  BreakSteppedOff - check if just stepped off a breakpoint
542     *  and re-insert it into the code.
543     */
544
545  void
546BreakSteppedOff (PID_LIST * plst)
547{
548  if (plst->break_list && BKPT0 (plst)->clr_step) {
549    int idx = BKPT0 (plst)->last_break;
550    int data;
551
552    BKPT0 (plst)->clr_step = 0;
553
554    /*
555     *  Re-insert the breakpoint.
556     */
557    data = TgtPtrace (RPT_PEEKTEXT, plst->pid,
558                      (char *) plst->break_list[idx].ee_loc, 0, NULL);
559    assert (!IS_BREAK (data));
560    TgtPtrace (RPT_POKETEXT, plst->pid,
561               (char *) plst->break_list[idx].ee_loc,
562               (int) SET_BREAK (data), NULL);
563  }
564}
565
566    /*
567     *  Returns whether a thread matches a breakpoint.
568     */
569
570  static int
571BreakThreadMatch (xdr_break * xb, int thread)
572{
573  int slot;
574
575  if (thread < 0)
576    return 1;                   /* Break existence check only */
577
578  if (xb->thread_list[0] == 0)
579    return 1;                   /* Universal break */
580
581  for (slot = 0; slot < BKPT_SLOTS; ++slot) {
582    if (xb->thread_list[slot] == 0)
583      return 0;                 /* End of list */
584    if (xb->thread_list[slot] == thread)
585      return 1;                 /* Match */
586  }
587  return 0;                     /* No matches found */
588}
589
590  int
591BreakAdjustPC (PID_LIST * plst)
592{
593  /*
594   *  BREAK_ADJ is the value by which the Program Counter
595   *  has to be decremented after a software breakpoint
596   *  is hit. It must be defined and can be zero.
597   */
598#if BREAK_ADJ
599  /*
600   * subtract back if necessary
601   */
602  plst->regs.REG_PC -= BREAK_ADJ;   /* now write back */
603  TgtPtrace (RPT_SETREGS, plst->pid, (char *) &plst->regs, 0, NULL);
604#else
605  (void) plst;
606#endif
607  return 0;
608}
609
610/*
611 *  Identify the current breakpoint. The process just stopped.
612 */
613
614  int
615BreakIdentify (PID_LIST * plst, int adjust, int thread)
616{
617  int foreignBkpt = 0;
618  int bidx;
619
620  for (bidx = 1; bidx < (int) plst->break_alloc; bidx++) {
621    int type = plst->break_list[bidx].type;
622
623    if ((type == BRKT_INSTR || type == BRKT_STEPEMUL)
624        && plst->regs.REG_PC - BREAK_ADJ == plst->break_list[bidx].ee_loc) {    /* found matching */
625      if (!BreakThreadMatch (&plst->break_list[bidx], thread)) {
626        if (foreignBkpt == 0) {
627          foreignBkpt = bidx;
628        }
629        continue;
630      }
631      if (adjust) {
632        BreakAdjustPC (plst);
633      }
634      return bidx;
635    }
636  }
637  if (foreignBkpt) {
638    if (adjust) {
639      BreakAdjustPC (plst);
640    }
641    return -foreignBkpt;
642  }
643  return 0;
644}
Note: See TracBrowser for help on using the repository browser.