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