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

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