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