OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [librdbg/] [src/] [servbkpt.c] - Blame information for rev 228

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
2
 **********************************************************************
3
 *
4
 *  Component:  RDB servers
5
 *  Module:     servbkpt.c
6
 *
7
 *  Synopsis:   Management of breakpoints
8
 *
9
 * $Id: servbkpt.c,v 1.2 2001-09-27 12:02:01 chris Exp $
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
42
BreakAlloc (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
89
static 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
100
BreakSet (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
157
BreakSetAt (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
170
BreakGetIndex(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
197
BreakGet (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
233
BreakClear (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
333
PatchBreak (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
372
BreakHide (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
406
BreakOverwrite (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
437
BreakStepRange (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
457
BreakPcChanged (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
470
BreakStepOff (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
493
BreakSteppedOff (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
519
BreakThreadMatch (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
 
535
int
536
BreakAdjustPC (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
559
BreakIdentify (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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.