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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [ax-general.c] - Blame information for rev 1774

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

Line No. Rev Author Line
1 578 markom
/* Functions for manipulating expressions designed to be executed on the agent
2
   Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
3
 
4
   This file is part of GDB.
5
 
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 2 of the License, or
9
   (at your option) any later version.
10
 
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
 
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 59 Temple Place - Suite 330,
19
   Boston, MA 02111-1307, USA.  */
20
 
21
/* Despite what the above comment says about this file being part of
22
   GDB, we would like to keep these functions free of GDB
23
   dependencies, since we want to be able to use them in contexts
24
   outside of GDB (test suites, the stub, etc.)  */
25
 
26
#include "defs.h"
27
#include "ax.h"
28
 
29
#include "value.h"
30
 
31
static void grow_expr (struct agent_expr *x, int n);
32
 
33
static void append_const (struct agent_expr *x, LONGEST val, int n);
34
 
35
static LONGEST read_const (struct agent_expr *x, int o, int n);
36
 
37
static void generic_ext (struct agent_expr *x, enum agent_op op, int n);
38
 
39
/* Functions for building expressions.  */
40
 
41
/* Allocate a new, empty agent expression.  */
42
struct agent_expr *
43
new_agent_expr (CORE_ADDR scope)
44
{
45
  struct agent_expr *x = xmalloc (sizeof (*x));
46
  x->len = 0;
47
  x->size = 1;                  /* Change this to a larger value once
48
                                   reallocation code is tested.  */
49
  x->buf = xmalloc (x->size);
50
  x->scope = scope;
51
 
52
  return x;
53
}
54
 
55
/* Free a agent expression.  */
56
void
57
free_agent_expr (struct agent_expr *x)
58
{
59
  xfree (x->buf);
60
  xfree (x);
61
}
62
 
63
static void
64
do_free_agent_expr_cleanup (void *x)
65
{
66
  free_agent_expr (x);
67
}
68
 
69
struct cleanup *
70
make_cleanup_free_agent_expr (struct agent_expr *x)
71
{
72
  return make_cleanup (do_free_agent_expr_cleanup, x);
73
}
74
 
75
 
76
/* Make sure that X has room for at least N more bytes.  This doesn't
77
   affect the length, just the allocated size.  */
78
static void
79
grow_expr (struct agent_expr *x, int n)
80
{
81
  if (x->len + n > x->size)
82
    {
83
      x->size *= 2;
84
      if (x->size < x->len + n)
85
        x->size = x->len + n + 10;
86
      x->buf = xrealloc (x->buf, x->size);
87
    }
88
}
89
 
90
 
91
/* Append the low N bytes of VAL as an N-byte integer to the
92
   expression X, in big-endian order.  */
93
static void
94
append_const (struct agent_expr *x, LONGEST val, int n)
95
{
96
  int i;
97
 
98
  grow_expr (x, n);
99
  for (i = n - 1; i >= 0; i--)
100
    {
101
      x->buf[x->len + i] = val & 0xff;
102
      val >>= 8;
103
    }
104
  x->len += n;
105
}
106
 
107
 
108
/* Extract an N-byte big-endian unsigned integer from expression X at
109
   offset O.  */
110
static LONGEST
111
read_const (struct agent_expr *x, int o, int n)
112
{
113
  int i;
114
  LONGEST accum = 0;
115
 
116
  /* Make sure we're not reading off the end of the expression.  */
117
  if (o + n > x->len)
118
    error ("GDB bug: ax-general.c (read_const): incomplete constant");
119
 
120
  for (i = 0; i < n; i++)
121
    accum = (accum << 8) | x->buf[o + i];
122
 
123
  return accum;
124
}
125
 
126
 
127
/* Append a simple operator OP to EXPR.  */
128
void
129
ax_simple (struct agent_expr *x, enum agent_op op)
130
{
131
  grow_expr (x, 1);
132
  x->buf[x->len++] = op;
133
}
134
 
135
 
136
/* Append a sign-extension or zero-extension instruction to EXPR, to
137
   extend an N-bit value.  */
138
static void
139
generic_ext (struct agent_expr *x, enum agent_op op, int n)
140
{
141
  /* N must fit in a byte.  */
142
  if (n < 0 || n > 255)
143
    error ("GDB bug: ax-general.c (generic_ext): bit count out of range");
144
  /* That had better be enough range.  */
145
  if (sizeof (LONGEST) * 8 > 255)
146
    error ("GDB bug: ax-general.c (generic_ext): opcode has inadequate range");
147
 
148
  grow_expr (x, 2);
149
  x->buf[x->len++] = op;
150
  x->buf[x->len++] = n;
151
}
152
 
153
 
154
/* Append a sign-extension instruction to EXPR, to extend an N-bit value.  */
155
void
156
ax_ext (struct agent_expr *x, int n)
157
{
158
  generic_ext (x, aop_ext, n);
159
}
160
 
161
 
162
/* Append a zero-extension instruction to EXPR, to extend an N-bit value.  */
163
void
164
ax_zero_ext (struct agent_expr *x, int n)
165
{
166
  generic_ext (x, aop_zero_ext, n);
167
}
168
 
169
 
170
/* Append a trace_quick instruction to EXPR, to record N bytes.  */
171
void
172
ax_trace_quick (struct agent_expr *x, int n)
173
{
174
  /* N must fit in a byte.  */
175
  if (n < 0 || n > 255)
176
    error ("GDB bug: ax-general.c (ax_trace_quick): size out of range for trace_quick");
177
 
178
  grow_expr (x, 2);
179
  x->buf[x->len++] = aop_trace_quick;
180
  x->buf[x->len++] = n;
181
}
182
 
183
 
184
/* Append a goto op to EXPR.  OP is the actual op (must be aop_goto or
185
   aop_if_goto).  We assume we don't know the target offset yet,
186
   because it's probably a forward branch, so we leave space in EXPR
187
   for the target, and return the offset in EXPR of that space, so we
188
   can backpatch it once we do know the target offset.  Use ax_label
189
   to do the backpatching.  */
190
int
191
ax_goto (struct agent_expr *x, enum agent_op op)
192
{
193
  grow_expr (x, 3);
194
  x->buf[x->len + 0] = op;
195
  x->buf[x->len + 1] = 0xff;
196
  x->buf[x->len + 2] = 0xff;
197
  x->len += 3;
198
  return x->len - 2;
199
}
200
 
201
/* Suppose a given call to ax_goto returns some value PATCH.  When you
202
   know the offset TARGET that goto should jump to, call
203
   ax_label (EXPR, PATCH, TARGET)
204
   to patch TARGET into the ax_goto instruction.  */
205
void
206
ax_label (struct agent_expr *x, int patch, int target)
207
{
208
  /* Make sure the value is in range.  Don't accept 0xffff as an
209
     offset; that's our magic sentinel value for unpatched branches.  */
210
  if (target < 0 || target >= 0xffff)
211
    error ("GDB bug: ax-general.c (ax_label): label target out of range");
212
 
213
  x->buf[patch] = (target >> 8) & 0xff;
214
  x->buf[patch + 1] = target & 0xff;
215
}
216
 
217
 
218
/* Assemble code to push a constant on the stack.  */
219
void
220
ax_const_l (struct agent_expr *x, LONGEST l)
221
{
222
  static enum agent_op ops[]
223
  =
224
  {aop_const8, aop_const16, aop_const32, aop_const64};
225
  int size;
226
  int op;
227
 
228
  /* How big is the number?  'op' keeps track of which opcode to use.
229
     Notice that we don't really care whether the original number was
230
     signed or unsigned; we always reproduce the value exactly, and
231
     use the shortest representation.  */
232
  for (op = 0, size = 8; size < 64; size *= 2, op++)
233
    if (-((LONGEST) 1 << size) <= l && l < ((LONGEST) 1 << size))
234
      break;
235
 
236
  /* Emit the right opcode... */
237
  ax_simple (x, ops[op]);
238
 
239
  /* Emit the low SIZE bytes as an unsigned number.  We know that
240
     sign-extending this will yield l.  */
241
  append_const (x, l, size / 8);
242
 
243
  /* Now, if it was negative, and not full-sized, sign-extend it.  */
244
  if (l < 0 && size < 64)
245
    ax_ext (x, size);
246
}
247
 
248
 
249
void
250
ax_const_d (struct agent_expr *x, LONGEST d)
251
{
252
  /* FIXME: floating-point support not present yet.  */
253
  error ("GDB bug: ax-general.c (ax_const_d): floating point not supported yet");
254
}
255
 
256
 
257
/* Assemble code to push the value of register number REG on the
258
   stack.  */
259
void
260
ax_reg (struct agent_expr *x, int reg)
261
{
262
  /* Make sure the register number is in range.  */
263
  if (reg < 0 || reg > 0xffff)
264
    error ("GDB bug: ax-general.c (ax_reg): register number out of range");
265
  grow_expr (x, 3);
266
  x->buf[x->len] = aop_reg;
267
  x->buf[x->len + 1] = (reg >> 8) & 0xff;
268
  x->buf[x->len + 2] = (reg) & 0xff;
269
  x->len += 3;
270
}
271
 
272
 
273
 
274
/* Functions for disassembling agent expressions, and otherwise
275
   debugging the expression compiler.  */
276
 
277
struct aop_map aop_map[] =
278
{
279
  {0, 0, 0, 0, 0},
280
  {"float", 0, 0, 0, 0},    /* 0x01 */
281
  {"add", 0, 0, 2, 1},            /* 0x02 */
282
  {"sub", 0, 0, 2, 1},            /* 0x03 */
283
  {"mul", 0, 0, 2, 1},            /* 0x04 */
284
  {"div_signed", 0, 0, 2, 1},     /* 0x05 */
285
  {"div_unsigned", 0, 0, 2, 1},   /* 0x06 */
286
  {"rem_signed", 0, 0, 2, 1},     /* 0x07 */
287
  {"rem_unsigned", 0, 0, 2, 1},   /* 0x08 */
288
  {"lsh", 0, 0, 2, 1},            /* 0x09 */
289
  {"rsh_signed", 0, 0, 2, 1},     /* 0x0a */
290
  {"rsh_unsigned", 0, 0, 2, 1},   /* 0x0b */
291
  {"trace", 0, 0, 2, 0},   /* 0x0c */
292
  {"trace_quick", 1, 0, 1, 1},   /* 0x0d */
293
  {"log_not", 0, 0, 1, 1},        /* 0x0e */
294
  {"bit_and", 0, 0, 2, 1},        /* 0x0f */
295
  {"bit_or", 0, 0, 2, 1}, /* 0x10 */
296
  {"bit_xor", 0, 0, 2, 1},        /* 0x11 */
297
  {"bit_not", 0, 0, 1, 1},        /* 0x12 */
298
  {"equal", 0, 0, 2, 1},  /* 0x13 */
299
  {"less_signed", 0, 0, 2, 1},    /* 0x14 */
300
  {"less_unsigned", 0, 0, 2, 1},  /* 0x15 */
301
  {"ext", 1, 0, 1, 1},           /* 0x16 */
302
  {"ref8", 0, 8, 1, 1},          /* 0x17 */
303
  {"ref16", 0, 16, 1, 1},        /* 0x18 */
304
  {"ref32", 0, 32, 1, 1},        /* 0x19 */
305
  {"ref64", 0, 64, 1, 1},        /* 0x1a */
306
  {"ref_float", 0, 0, 1, 1},      /* 0x1b */
307
  {"ref_double", 0, 0, 1, 1},     /* 0x1c */
308
  {"ref_long_double", 0, 0, 1, 1},        /* 0x1d */
309
  {"l_to_d", 0, 0, 1, 1}, /* 0x1e */
310
  {"d_to_l", 0, 0, 1, 1}, /* 0x1f */
311
  {"if_goto", 2, 0, 1, 0},        /* 0x20 */
312
  {"goto", 2, 0, 0, 0},            /* 0x21 */
313
  {"const8", 1, 8, 0, 1},        /* 0x22 */
314
  {"const16", 2, 16, 0, 1},      /* 0x23 */
315
  {"const32", 4, 32, 0, 1},      /* 0x24 */
316
  {"const64", 8, 64, 0, 1},      /* 0x25 */
317
  {"reg", 2, 0, 0, 1},            /* 0x26 */
318
  {"end", 0, 0, 0, 0},              /* 0x27 */
319
  {"dup", 0, 0, 1, 2},            /* 0x28 */
320
  {"pop", 0, 0, 1, 0},             /* 0x29 */
321
  {"zero_ext", 1, 0, 1, 1},      /* 0x2a */
322
  {"swap", 0, 0, 2, 2},           /* 0x2b */
323
  {0, 0, 0, 0, 0},           /* 0x2c */
324
  {0, 0, 0, 0, 0},           /* 0x2d */
325
  {0, 0, 0, 0, 0},           /* 0x2e */
326
  {0, 0, 0, 0, 0},           /* 0x2f */
327
  {"trace16", 2, 0, 1, 1},       /* 0x30 */
328
};
329
 
330
 
331
/* Disassemble the expression EXPR, writing to F.  */
332
void
333
ax_print (struct ui_file *f, struct agent_expr *x)
334
{
335
  int i;
336
  int is_float = 0;
337
 
338
  /* Check the size of the name array against the number of entries in
339
     the enum, to catch additions that people didn't sync.  */
340
  if ((sizeof (aop_map) / sizeof (aop_map[0]))
341
      != aop_last)
342
    error ("GDB bug: ax-general.c (ax_print): opcode map out of sync");
343
 
344
  for (i = 0; i < x->len;)
345
    {
346
      enum agent_op op = x->buf[i];
347
 
348
      if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
349
          || !aop_map[op].name)
350
        {
351
          fprintf_filtered (f, "%3d  <bad opcode %02x>\n", i, op);
352
          i++;
353
          continue;
354
        }
355
      if (i + 1 + aop_map[op].op_size > x->len)
356
        {
357
          fprintf_filtered (f, "%3d  <incomplete opcode %s>\n",
358
                            i, aop_map[op].name);
359
          break;
360
        }
361
 
362
      fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
363
      if (aop_map[op].op_size > 0)
364
        {
365
          fputs_filtered (" ", f);
366
 
367
          print_longest (f, 'd', 0,
368
                         read_const (x, i + 1, aop_map[op].op_size));
369
        }
370
      fprintf_filtered (f, "\n");
371
      i += 1 + aop_map[op].op_size;
372
 
373
      is_float = (op == aop_float);
374
    }
375
}
376
 
377
 
378
/* Given an agent expression AX, fill in an agent_reqs structure REQS
379
   describing it.  */
380
void
381
ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
382
{
383
  int i;
384
  int height;
385
 
386
  /* Bit vector for registers used.  */
387
  int reg_mask_len = 1;
388
  unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));
389
 
390
  /* Jump target table.  targets[i] is non-zero iff there is a jump to
391
     offset i.  */
392
  char *targets = (char *) alloca (ax->len * sizeof (targets[0]));
393
 
394
  /* Instruction boundary table.  boundary[i] is non-zero iff an
395
     instruction starts at offset i.  */
396
  char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));
397
 
398
  /* Stack height record.  iff either targets[i] or boundary[i] is
399
     non-zero, heights[i] is the height the stack should have before
400
     executing the bytecode at that point.  */
401
  int *heights = (int *) alloca (ax->len * sizeof (heights[0]));
402
 
403
  /* Pointer to a description of the present op.  */
404
  struct aop_map *op;
405
 
406
  memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
407
  memset (targets, 0, ax->len * sizeof (targets[0]));
408
  memset (boundary, 0, ax->len * sizeof (boundary[0]));
409
 
410
  reqs->max_height = reqs->min_height = height = 0;
411
  reqs->flaw = agent_flaw_none;
412
  reqs->max_data_size = 0;
413
 
414
  for (i = 0; i < ax->len; i += 1 + op->op_size)
415
    {
416
      if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
417
        {
418
          reqs->flaw = agent_flaw_bad_instruction;
419
          xfree (reg_mask);
420
          return;
421
        }
422
 
423
      op = &aop_map[ax->buf[i]];
424
 
425
      if (!op->name)
426
        {
427
          reqs->flaw = agent_flaw_bad_instruction;
428
          xfree (reg_mask);
429
          return;
430
        }
431
 
432
      if (i + 1 + op->op_size > ax->len)
433
        {
434
          reqs->flaw = agent_flaw_incomplete_instruction;
435
          xfree (reg_mask);
436
          return;
437
        }
438
 
439
      /* If this instruction is a jump target, does the current stack
440
         height match the stack height at the jump source?  */
441
      if (targets[i] && (heights[i] != height))
442
        {
443
          reqs->flaw = agent_flaw_height_mismatch;
444
          xfree (reg_mask);
445
          return;
446
        }
447
 
448
      boundary[i] = 1;
449
      heights[i] = height;
450
 
451
      height -= op->consumed;
452
      if (height < reqs->min_height)
453
        reqs->min_height = height;
454
      height += op->produced;
455
      if (height > reqs->max_height)
456
        reqs->max_height = height;
457
 
458
      if (op->data_size > reqs->max_data_size)
459
        reqs->max_data_size = op->data_size;
460
 
461
      /* For jump instructions, check that the target is a valid
462
         offset.  If it is, record the fact that that location is a
463
         jump target, and record the height we expect there.  */
464
      if (aop_goto == op - aop_map
465
          || aop_if_goto == op - aop_map)
466
        {
467
          int target = read_const (ax, i + 1, 2);
468
          if (target < 0 || target >= ax->len)
469
            {
470
              reqs->flaw = agent_flaw_bad_jump;
471
              xfree (reg_mask);
472
              return;
473
            }
474
          /* Have we already found other jumps to the same location?  */
475
          else if (targets[target])
476
            {
477
              if (heights[i] != height)
478
                {
479
                  reqs->flaw = agent_flaw_height_mismatch;
480
                  xfree (reg_mask);
481
                  return;
482
                }
483
            }
484
          else
485
            {
486
              targets[target] = 1;
487
              heights[target] = height;
488
            }
489
        }
490
 
491
      /* For unconditional jumps with a successor, check that the
492
         successor is a target, and pick up its stack height.  */
493
      if (aop_goto == op - aop_map
494
          && i + 3 < ax->len)
495
        {
496
          if (!targets[i + 3])
497
            {
498
              reqs->flaw = agent_flaw_hole;
499
              xfree (reg_mask);
500
              return;
501
            }
502
 
503
          height = heights[i + 3];
504
        }
505
 
506
      /* For reg instructions, record the register in the bit mask.  */
507
      if (aop_reg == op - aop_map)
508
        {
509
          int reg = read_const (ax, i + 1, 2);
510
          int byte = reg / 8;
511
 
512
          /* Grow the bit mask if necessary.  */
513
          if (byte >= reg_mask_len)
514
            {
515
              /* It's not appropriate to double here.  This isn't a
516
                 string buffer.  */
517
              int new_len = byte + 1;
518
              reg_mask = xrealloc (reg_mask,
519
                                   new_len * sizeof (reg_mask[0]));
520
              memset (reg_mask + reg_mask_len, 0,
521
                      (new_len - reg_mask_len) * sizeof (reg_mask[0]));
522
              reg_mask_len = new_len;
523
            }
524
 
525
          reg_mask[byte] |= 1 << (reg % 8);
526
        }
527
    }
528
 
529
  /* Check that all the targets are on boundaries.  */
530
  for (i = 0; i < ax->len; i++)
531
    if (targets[i] && !boundary[i])
532
      {
533
        reqs->flaw = agent_flaw_bad_jump;
534
        xfree (reg_mask);
535
        return;
536
      }
537
 
538
  reqs->final_height = height;
539
  reqs->reg_mask_len = reg_mask_len;
540
  reqs->reg_mask = reg_mask;
541
}

powered by: WebSVN 2.1.0

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