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