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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [librdbg/] [src/] [servbkpt.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1026 ivang
/*
2
 **********************************************************************
3
 *
4
 *  Component:  RDB servers
5
 *  Module:     servbkpt.c
6
 *
7
 *  Synopsis:   Management of breakpoints
8
 *
9
 * servbkpt.c,v 1.3 2002/02/01 17:00:01 joel 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
     *  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
41
BreakAlloc (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
94
static 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
105
BreakSet (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
166
BreakSetAt (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
180
BreakGetIndex (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
207
BreakGet (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
247
BreakClear (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
360
PatchBreak (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
407
BreakHide (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
447
BreakOverwrite (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
480
BreakStepRange (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
502
BreakPcChanged (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
517
BreakStepOff (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
546
BreakSteppedOff (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
571
BreakThreadMatch (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
591
BreakAdjustPC (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
615
BreakIdentify (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
}

powered by: WebSVN 2.1.0

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