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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [ax-general.c] - Blame information for rev 853

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

Line No. Rev Author Line
1 227 jeremybenn
/* Functions for manipulating expressions designed to be executed on the agent
2
   Copyright (C) 1998, 1999, 2000, 2007, 2008, 2009, 2010
3
   Free Software Foundation, Inc.
4
 
5
   This file is part of GDB.
6
 
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
 
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
 
20
/* Despite what the above comment says about this file being part of
21
   GDB, we would like to keep these functions free of GDB
22
   dependencies, since we want to be able to use them in contexts
23
   outside of GDB (test suites, the stub, etc.)  */
24
 
25
#include "defs.h"
26
#include "ax.h"
27
 
28
#include "value.h"
29
#include "gdb_string.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
    {
234
      LONGEST lim = 1 << (size - 1);
235
 
236
      if (-lim <= l && l <= lim - 1)
237
        break;
238
    }
239
 
240
  /* Emit the right opcode... */
241
  ax_simple (x, ops[op]);
242
 
243
  /* Emit the low SIZE bytes as an unsigned number.  We know that
244
     sign-extending this will yield l.  */
245
  append_const (x, l, size / 8);
246
 
247
  /* Now, if it was negative, and not full-sized, sign-extend it.  */
248
  if (l < 0 && size < 64)
249
    ax_ext (x, size);
250
}
251
 
252
 
253
void
254
ax_const_d (struct agent_expr *x, LONGEST d)
255
{
256
  /* FIXME: floating-point support not present yet.  */
257
  error (_("GDB bug: ax-general.c (ax_const_d): floating point not supported yet"));
258
}
259
 
260
 
261
/* Assemble code to push the value of register number REG on the
262
   stack.  */
263
void
264
ax_reg (struct agent_expr *x, int reg)
265
{
266
  /* Make sure the register number is in range.  */
267
  if (reg < 0 || reg > 0xffff)
268
    error (_("GDB bug: ax-general.c (ax_reg): register number out of range"));
269
  grow_expr (x, 3);
270
  x->buf[x->len] = aop_reg;
271
  x->buf[x->len + 1] = (reg >> 8) & 0xff;
272
  x->buf[x->len + 2] = (reg) & 0xff;
273
  x->len += 3;
274
}
275
 
276
/* Assemble code to operate on a trace state variable.  */
277
 
278
void
279
ax_tsv (struct agent_expr *x, enum agent_op op, int num)
280
{
281
  /* Make sure the tsv number is in range.  */
282
  if (num < 0 || num > 0xffff)
283
    internal_error (__FILE__, __LINE__, _("ax-general.c (ax_tsv): variable number is %d, out of range"), num);
284
 
285
  grow_expr (x, 3);
286
  x->buf[x->len] = op;
287
  x->buf[x->len + 1] = (num >> 8) & 0xff;
288
  x->buf[x->len + 2] = (num) & 0xff;
289
  x->len += 3;
290
}
291
 
292
 
293
 
294
/* Functions for disassembling agent expressions, and otherwise
295
   debugging the expression compiler.  */
296
 
297
struct aop_map aop_map[] =
298
{
299
  {0, 0, 0, 0, 0},
300
  {"float", 0, 0, 0, 0},    /* 0x01 */
301
  {"add", 0, 0, 2, 1},            /* 0x02 */
302
  {"sub", 0, 0, 2, 1},            /* 0x03 */
303
  {"mul", 0, 0, 2, 1},            /* 0x04 */
304
  {"div_signed", 0, 0, 2, 1},     /* 0x05 */
305
  {"div_unsigned", 0, 0, 2, 1},   /* 0x06 */
306
  {"rem_signed", 0, 0, 2, 1},     /* 0x07 */
307
  {"rem_unsigned", 0, 0, 2, 1},   /* 0x08 */
308
  {"lsh", 0, 0, 2, 1},            /* 0x09 */
309
  {"rsh_signed", 0, 0, 2, 1},     /* 0x0a */
310
  {"rsh_unsigned", 0, 0, 2, 1},   /* 0x0b */
311
  {"trace", 0, 0, 2, 0},   /* 0x0c */
312
  {"trace_quick", 1, 0, 1, 1},   /* 0x0d */
313
  {"log_not", 0, 0, 1, 1},        /* 0x0e */
314
  {"bit_and", 0, 0, 2, 1},        /* 0x0f */
315
  {"bit_or", 0, 0, 2, 1}, /* 0x10 */
316
  {"bit_xor", 0, 0, 2, 1},        /* 0x11 */
317
  {"bit_not", 0, 0, 1, 1},        /* 0x12 */
318
  {"equal", 0, 0, 2, 1},  /* 0x13 */
319
  {"less_signed", 0, 0, 2, 1},    /* 0x14 */
320
  {"less_unsigned", 0, 0, 2, 1},  /* 0x15 */
321
  {"ext", 1, 0, 1, 1},           /* 0x16 */
322
  {"ref8", 0, 8, 1, 1},          /* 0x17 */
323
  {"ref16", 0, 16, 1, 1},        /* 0x18 */
324
  {"ref32", 0, 32, 1, 1},        /* 0x19 */
325
  {"ref64", 0, 64, 1, 1},        /* 0x1a */
326
  {"ref_float", 0, 0, 1, 1},      /* 0x1b */
327
  {"ref_double", 0, 0, 1, 1},     /* 0x1c */
328
  {"ref_long_double", 0, 0, 1, 1},        /* 0x1d */
329
  {"l_to_d", 0, 0, 1, 1}, /* 0x1e */
330
  {"d_to_l", 0, 0, 1, 1}, /* 0x1f */
331
  {"if_goto", 2, 0, 1, 0},        /* 0x20 */
332
  {"goto", 2, 0, 0, 0},            /* 0x21 */
333
  {"const8", 1, 8, 0, 1},        /* 0x22 */
334
  {"const16", 2, 16, 0, 1},      /* 0x23 */
335
  {"const32", 4, 32, 0, 1},      /* 0x24 */
336
  {"const64", 8, 64, 0, 1},      /* 0x25 */
337
  {"reg", 2, 0, 0, 1},            /* 0x26 */
338
  {"end", 0, 0, 0, 0},              /* 0x27 */
339
  {"dup", 0, 0, 1, 2},            /* 0x28 */
340
  {"pop", 0, 0, 1, 0},             /* 0x29 */
341
  {"zero_ext", 1, 0, 1, 1},      /* 0x2a */
342
  {"swap", 0, 0, 2, 2},           /* 0x2b */
343
  {"getv", 2, 0, 0, 1},           /* 0x2c */
344
  {"setv", 2, 0, 0, 1},           /* 0x2d */
345
  {"tracev", 2, 0, 0, 1}, /* 0x2e */
346
  {0, 0, 0, 0, 0},           /* 0x2f */
347
  {"trace16", 2, 0, 1, 1},       /* 0x30 */
348
};
349
 
350
 
351
/* Disassemble the expression EXPR, writing to F.  */
352
void
353
ax_print (struct ui_file *f, struct agent_expr *x)
354
{
355
  int i;
356
  int is_float = 0;
357
 
358
  /* Check the size of the name array against the number of entries in
359
     the enum, to catch additions that people didn't sync.  */
360
  if ((sizeof (aop_map) / sizeof (aop_map[0]))
361
      != aop_last)
362
    error (_("GDB bug: ax-general.c (ax_print): opcode map out of sync"));
363
 
364
  for (i = 0; i < x->len;)
365
    {
366
      enum agent_op op = x->buf[i];
367
 
368
      if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
369
          || !aop_map[op].name)
370
        {
371
          fprintf_filtered (f, _("%3d  <bad opcode %02x>\n"), i, op);
372
          i++;
373
          continue;
374
        }
375
      if (i + 1 + aop_map[op].op_size > x->len)
376
        {
377
          fprintf_filtered (f, _("%3d  <incomplete opcode %s>\n"),
378
                            i, aop_map[op].name);
379
          break;
380
        }
381
 
382
      fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
383
      if (aop_map[op].op_size > 0)
384
        {
385
          fputs_filtered (" ", f);
386
 
387
          print_longest (f, 'd', 0,
388
                         read_const (x, i + 1, aop_map[op].op_size));
389
        }
390
      fprintf_filtered (f, "\n");
391
      i += 1 + aop_map[op].op_size;
392
 
393
      is_float = (op == aop_float);
394
    }
395
}
396
 
397
 
398
/* Given an agent expression AX, fill in an agent_reqs structure REQS
399
   describing it.  */
400
void
401
ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
402
{
403
  int i;
404
  int height;
405
 
406
  /* Bit vector for registers used.  */
407
  int reg_mask_len = 1;
408
  unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));
409
 
410
  /* Jump target table.  targets[i] is non-zero iff we have found a
411
     jump to offset i.  */
412
  char *targets = (char *) alloca (ax->len * sizeof (targets[0]));
413
 
414
  /* Instruction boundary table.  boundary[i] is non-zero iff our scan
415
     has reached an instruction starting at offset i.  */
416
  char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));
417
 
418
  /* Stack height record.  If either targets[i] or boundary[i] is
419
     non-zero, heights[i] is the height the stack should have before
420
     executing the bytecode at that point.  */
421
  int *heights = (int *) alloca (ax->len * sizeof (heights[0]));
422
 
423
  /* Pointer to a description of the present op.  */
424
  struct aop_map *op;
425
 
426
  memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
427
  memset (targets, 0, ax->len * sizeof (targets[0]));
428
  memset (boundary, 0, ax->len * sizeof (boundary[0]));
429
 
430
  reqs->max_height = reqs->min_height = height = 0;
431
  reqs->flaw = agent_flaw_none;
432
  reqs->max_data_size = 0;
433
 
434
  for (i = 0; i < ax->len; i += 1 + op->op_size)
435
    {
436
      if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
437
        {
438
          reqs->flaw = agent_flaw_bad_instruction;
439
          xfree (reg_mask);
440
          return;
441
        }
442
 
443
      op = &aop_map[ax->buf[i]];
444
 
445
      if (!op->name)
446
        {
447
          reqs->flaw = agent_flaw_bad_instruction;
448
          xfree (reg_mask);
449
          return;
450
        }
451
 
452
      if (i + 1 + op->op_size > ax->len)
453
        {
454
          reqs->flaw = agent_flaw_incomplete_instruction;
455
          xfree (reg_mask);
456
          return;
457
        }
458
 
459
      /* If this instruction is a forward jump target, does the
460
         current stack height match the stack height at the jump
461
         source?  */
462
      if (targets[i] && (heights[i] != height))
463
        {
464
          reqs->flaw = agent_flaw_height_mismatch;
465
          xfree (reg_mask);
466
          return;
467
        }
468
 
469
      boundary[i] = 1;
470
      heights[i] = height;
471
 
472
      height -= op->consumed;
473
      if (height < reqs->min_height)
474
        reqs->min_height = height;
475
      height += op->produced;
476
      if (height > reqs->max_height)
477
        reqs->max_height = height;
478
 
479
      if (op->data_size > reqs->max_data_size)
480
        reqs->max_data_size = op->data_size;
481
 
482
      /* For jump instructions, check that the target is a valid
483
         offset.  If it is, record the fact that that location is a
484
         jump target, and record the height we expect there.  */
485
      if (aop_goto == op - aop_map
486
          || aop_if_goto == op - aop_map)
487
        {
488
          int target = read_const (ax, i + 1, 2);
489
          if (target < 0 || target >= ax->len)
490
            {
491
              reqs->flaw = agent_flaw_bad_jump;
492
              xfree (reg_mask);
493
              return;
494
            }
495
 
496
          /* Do we have any information about what the stack height
497
             should be at the target?  */
498
          if (targets[target] || boundary[target])
499
            {
500
              if (heights[target] != height)
501
                {
502
                  reqs->flaw = agent_flaw_height_mismatch;
503
                  xfree (reg_mask);
504
                  return;
505
                }
506
            }
507
 
508
          /* Record the target, along with the stack height we expect.  */
509
          targets[target] = 1;
510
          heights[target] = height;
511
        }
512
 
513
      /* For unconditional jumps with a successor, check that the
514
         successor is a target, and pick up its stack height.  */
515
      if (aop_goto == op - aop_map
516
          && i + 3 < ax->len)
517
        {
518
          if (!targets[i + 3])
519
            {
520
              reqs->flaw = agent_flaw_hole;
521
              xfree (reg_mask);
522
              return;
523
            }
524
 
525
          height = heights[i + 3];
526
        }
527
 
528
      /* For reg instructions, record the register in the bit mask.  */
529
      if (aop_reg == op - aop_map)
530
        {
531
          int reg = read_const (ax, i + 1, 2);
532
          int byte = reg / 8;
533
 
534
          /* Grow the bit mask if necessary.  */
535
          if (byte >= reg_mask_len)
536
            {
537
              /* It's not appropriate to double here.  This isn't a
538
                 string buffer.  */
539
              int new_len = byte + 1;
540
              reg_mask = xrealloc (reg_mask,
541
                                   new_len * sizeof (reg_mask[0]));
542
              memset (reg_mask + reg_mask_len, 0,
543
                      (new_len - reg_mask_len) * sizeof (reg_mask[0]));
544
              reg_mask_len = new_len;
545
            }
546
 
547
          reg_mask[byte] |= 1 << (reg % 8);
548
        }
549
    }
550
 
551
  /* Check that all the targets are on boundaries.  */
552
  for (i = 0; i < ax->len; i++)
553
    if (targets[i] && !boundary[i])
554
      {
555
        reqs->flaw = agent_flaw_bad_jump;
556
        xfree (reg_mask);
557
        return;
558
      }
559
 
560
  reqs->final_height = height;
561
  reqs->reg_mask_len = reg_mask_len;
562
  reqs->reg_mask = reg_mask;
563
}

powered by: WebSVN 2.1.0

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