source: rtems/c/src/lib/librdbg/servbkpt.c @ 0bf2ff8

4.104.114.84.95
Last change on this file since 0bf2ff8 was 4721cf1, checked in by Joel Sherrill <joel.sherrill@…>, on 12/03/98 at 23:54:14

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