Cleanup delete_breakpoint cleanups.
[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
c5aa993b 31static void grow_expr PARAMS ((struct agent_expr * x, int n));
392a587b 32
c5aa993b 33static void append_const PARAMS ((struct agent_expr * x, LONGEST val, int n));
392a587b 34
c5aa993b 35static LONGEST read_const PARAMS ((struct agent_expr * x, int o, int n));
392a587b 36
c5aa993b 37static void generic_ext PARAMS ((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
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. */
68static void
69grow_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. */
85static void
86append_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. */
105static LONGEST
106read_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];
c5aa993b 119
c906108c
SS
120 return accum;
121}
122
123
124/* Append a simple operator OP to EXPR. */
125void
126ax_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. */
137static void
138generic_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. */
157void
158ax_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. */
167void
168ax_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. */
177void
178ax_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. */
c5aa993b
JM
198int
199ax_goto (x, op)
c906108c
SS
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
c5aa993b 213 ax_label (EXPR, PATCH, TARGET)
c906108c
SS
214 to patch TARGET into the ax_goto instruction. */
215void
216ax_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");
c5aa993b 225
c906108c
SS
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. */
232void
233ax_const_l (x, l)
234 struct agent_expr *x;
235 LONGEST l;
236{
237 static enum agent_op ops[]
c5aa993b
JM
238 =
239 {aop_const8, aop_const16, aop_const32, aop_const64};
c906108c
SS
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
264void
265ax_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. */
c5aa993b
JM
276void
277ax_reg (x, reg)
c906108c
SS
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);
c5aa993b 285 x->buf[x->len] = aop_reg;
c906108c 286 x->buf[x->len + 1] = (reg >> 8) & 0xff;
c5aa993b 287 x->buf[x->len + 2] = (reg) & 0xff;
c906108c
SS
288 x->len += 3;
289}
c5aa993b 290\f
c906108c
SS
291
292
c906108c
SS
293/* Functions for disassembling agent expressions, and otherwise
294 debugging the expression compiler. */
295
c5aa993b
JM
296struct 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 */
c906108c
SS
347};
348
349
350/* Disassemble the expression EXPR, writing to F. */
351void
352ax_print (f, x)
d9fcf2fb 353 struct ui_file *f;
c906108c
SS
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");
c5aa993b
JM
364
365 for (i = 0; i < x->len;)
c906108c
SS
366 {
367 enum agent_op op = x->buf[i];
368
369 if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
c5aa993b 370 || !aop_map[op].name)
c906108c
SS
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);
c5aa993b 387
c906108c
SS
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. */
401void
402ax_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
c5aa993b 448 if (!op->name)
c906108c
SS
449 {
450 reqs->flaw = agent_flaw_bad_instruction;
451 free (reg_mask);
452 return;
453 }
c5aa993b 454
c906108c
SS
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
c5aa993b
JM
485 offset. If it is, record the fact that that location is a
486 jump target, and record the height we expect there. */
c906108c
SS
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 }
c5aa993b 513
c906108c
SS
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 {
c5aa993b 519 if (!targets[i + 3])
c906108c
SS
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
c5aa993b 539 string buffer. */
c906108c 540 int new_len = byte + 1;
c5aa993b 541 reg_mask = xrealloc (reg_mask,
c906108c
SS
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}
This page took 0.072339 seconds and 4 git commands to generate.