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