xref: /openbsd-src/gnu/usr.bin/binutils/gdb/ax-general.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
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