Home | History | Annotate | Line # | Download | only in gdb
      1   1.1  christos /* Functions for manipulating expressions designed to be executed on the agent
      2  1.11  christos    Copyright (C) 1998-2024 Free Software Foundation, Inc.
      3   1.1  christos 
      4   1.1  christos    This file is part of GDB.
      5   1.1  christos 
      6   1.1  christos    This program is free software; you can redistribute it and/or modify
      7   1.1  christos    it under the terms of the GNU General Public License as published by
      8   1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9   1.1  christos    (at your option) any later version.
     10   1.1  christos 
     11   1.1  christos    This program is distributed in the hope that it will be useful,
     12   1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14   1.1  christos    GNU General Public License for more details.
     15   1.1  christos 
     16   1.1  christos    You should have received a copy of the GNU General Public License
     17   1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18   1.1  christos 
     19   1.1  christos /* Despite what the above comment says about this file being part of
     20   1.1  christos    GDB, we would like to keep these functions free of GDB
     21   1.1  christos    dependencies, since we want to be able to use them in contexts
     22   1.1  christos    outside of GDB (test suites, the stub, etc.)  */
     23   1.1  christos 
     24   1.1  christos #include "ax.h"
     25   1.9  christos #include "gdbarch.h"
     26   1.1  christos 
     27   1.1  christos #include "value.h"
     28   1.1  christos #include "user-regs.h"
     29   1.1  christos 
     30   1.1  christos static void append_const (struct agent_expr *x, LONGEST val, int n);
     31   1.1  christos 
     32   1.1  christos static LONGEST read_const (struct agent_expr *x, int o, int n);
     33   1.1  christos 
     34   1.1  christos static void generic_ext (struct agent_expr *x, enum agent_op op, int n);
     35   1.1  christos 
     36   1.1  christos /* Functions for building expressions.  */
     38   1.1  christos 
     39   1.1  christos /* Append the low N bytes of VAL as an N-byte integer to the
     40   1.1  christos    expression X, in big-endian order.  */
     41   1.1  christos static void
     42   1.1  christos append_const (struct agent_expr *x, LONGEST val, int n)
     43  1.11  christos {
     44  1.11  christos   size_t len = x->buf.size ();
     45  1.11  christos   x->buf.resize (len + n);
     46   1.1  christos   for (int i = n - 1; i >= 0; i--)
     47  1.11  christos     {
     48   1.1  christos       x->buf[len + i] = val & 0xff;
     49   1.1  christos       val >>= 8;
     50   1.1  christos     }
     51   1.1  christos }
     52   1.1  christos 
     53   1.1  christos 
     54   1.1  christos /* Extract an N-byte big-endian unsigned integer from expression X at
     55   1.1  christos    offset O.  */
     56   1.1  christos static LONGEST
     57   1.1  christos read_const (struct agent_expr *x, int o, int n)
     58   1.1  christos {
     59   1.1  christos   int i;
     60   1.1  christos   LONGEST accum = 0;
     61   1.1  christos 
     62  1.11  christos   /* Make sure we're not reading off the end of the expression.  */
     63   1.1  christos   if (o + n > x->buf.size ())
     64   1.1  christos     error (_("GDB bug: ax-general.c (read_const): incomplete constant"));
     65   1.1  christos 
     66   1.1  christos   for (i = 0; i < n; i++)
     67   1.1  christos     accum = (accum << 8) | x->buf[o + i];
     68   1.1  christos 
     69   1.1  christos   return accum;
     70   1.1  christos }
     71   1.6  christos 
     72   1.6  christos /* See ax.h.  */
     73   1.6  christos 
     74   1.6  christos void
     75   1.6  christos ax_raw_byte (struct agent_expr *x, gdb_byte byte)
     76  1.11  christos {
     77   1.6  christos   x->buf.push_back (byte);
     78   1.1  christos }
     79   1.1  christos 
     80   1.1  christos /* Append a simple operator OP to EXPR.  */
     81   1.1  christos void
     82   1.1  christos ax_simple (struct agent_expr *x, enum agent_op op)
     83   1.6  christos {
     84   1.1  christos   ax_raw_byte (x, op);
     85   1.1  christos }
     86   1.1  christos 
     87   1.1  christos /* Append a pick operator to EXPR.  DEPTH is the stack item to pick,
     88   1.1  christos    with 0 being top of stack.  */
     89   1.1  christos 
     90   1.1  christos void
     91   1.1  christos ax_pick (struct agent_expr *x, int depth)
     92   1.1  christos {
     93   1.1  christos   if (depth < 0 || depth > 255)
     94   1.1  christos     error (_("GDB bug: ax-general.c (ax_pick): stack depth out of range"));
     95   1.1  christos   ax_simple (x, aop_pick);
     96   1.1  christos   append_const (x, 1, depth);
     97   1.1  christos }
     98   1.1  christos 
     99   1.1  christos 
    100   1.1  christos /* Append a sign-extension or zero-extension instruction to EXPR, to
    101   1.1  christos    extend an N-bit value.  */
    102   1.1  christos static void
    103   1.1  christos generic_ext (struct agent_expr *x, enum agent_op op, int n)
    104   1.1  christos {
    105   1.1  christos   /* N must fit in a byte.  */
    106   1.1  christos   if (n < 0 || n > 255)
    107   1.1  christos     error (_("GDB bug: ax-general.c (generic_ext): bit count out of range"));
    108   1.1  christos   /* That had better be enough range.  */
    109   1.1  christos   if (sizeof (LONGEST) * 8 > 255)
    110   1.1  christos     error (_("GDB bug: ax-general.c (generic_ext): "
    111   1.1  christos 	     "opcode has inadequate range"));
    112  1.11  christos 
    113  1.11  christos   x->buf.push_back (op);
    114   1.1  christos   x->buf.push_back (n);
    115   1.1  christos }
    116   1.1  christos 
    117   1.1  christos 
    118   1.1  christos /* Append a sign-extension instruction to EXPR, to extend an N-bit value.  */
    119   1.1  christos void
    120   1.1  christos ax_ext (struct agent_expr *x, int n)
    121   1.1  christos {
    122   1.1  christos   generic_ext (x, aop_ext, n);
    123   1.1  christos }
    124   1.1  christos 
    125   1.1  christos 
    126   1.1  christos /* Append a zero-extension instruction to EXPR, to extend an N-bit value.  */
    127   1.1  christos void
    128   1.1  christos ax_zero_ext (struct agent_expr *x, int n)
    129   1.1  christos {
    130   1.1  christos   generic_ext (x, aop_zero_ext, n);
    131   1.1  christos }
    132   1.1  christos 
    133   1.1  christos 
    134   1.1  christos /* Append a trace_quick instruction to EXPR, to record N bytes.  */
    135   1.1  christos void
    136   1.1  christos ax_trace_quick (struct agent_expr *x, int n)
    137   1.1  christos {
    138   1.1  christos   /* N must fit in a byte.  */
    139   1.1  christos   if (n < 0 || n > 255)
    140   1.1  christos     error (_("GDB bug: ax-general.c (ax_trace_quick): "
    141   1.1  christos 	     "size out of range for trace_quick"));
    142  1.11  christos 
    143  1.11  christos   x->buf.push_back (aop_trace_quick);
    144   1.1  christos   x->buf.push_back (n);
    145   1.1  christos }
    146   1.1  christos 
    147   1.1  christos 
    148   1.1  christos /* Append a goto op to EXPR.  OP is the actual op (must be aop_goto or
    149   1.1  christos    aop_if_goto).  We assume we don't know the target offset yet,
    150   1.1  christos    because it's probably a forward branch, so we leave space in EXPR
    151   1.1  christos    for the target, and return the offset in EXPR of that space, so we
    152   1.1  christos    can backpatch it once we do know the target offset.  Use ax_label
    153   1.1  christos    to do the backpatching.  */
    154   1.1  christos int
    155   1.1  christos ax_goto (struct agent_expr *x, enum agent_op op)
    156  1.11  christos {
    157  1.11  christos   x->buf.push_back (op);
    158  1.11  christos   x->buf.push_back (0xff);
    159  1.11  christos   x->buf.push_back (0xff);
    160   1.1  christos   return x->buf.size () - 2;
    161   1.1  christos }
    162   1.1  christos 
    163   1.1  christos /* Suppose a given call to ax_goto returns some value PATCH.  When you
    164   1.1  christos    know the offset TARGET that goto should jump to, call
    165   1.1  christos    ax_label (EXPR, PATCH, TARGET)
    166   1.1  christos    to patch TARGET into the ax_goto instruction.  */
    167   1.1  christos void
    168   1.1  christos ax_label (struct agent_expr *x, int patch, int target)
    169   1.1  christos {
    170   1.1  christos   /* Make sure the value is in range.  Don't accept 0xffff as an
    171   1.1  christos      offset; that's our magic sentinel value for unpatched branches.  */
    172   1.1  christos   if (target < 0 || target >= 0xffff)
    173   1.1  christos     error (_("GDB bug: ax-general.c (ax_label): label target out of range"));
    174   1.1  christos 
    175   1.1  christos   x->buf[patch] = (target >> 8) & 0xff;
    176   1.1  christos   x->buf[patch + 1] = target & 0xff;
    177   1.1  christos }
    178   1.1  christos 
    179   1.1  christos 
    180   1.1  christos /* Assemble code to push a constant on the stack.  */
    181   1.1  christos void
    182   1.1  christos ax_const_l (struct agent_expr *x, LONGEST l)
    183   1.1  christos {
    184   1.1  christos   static enum agent_op ops[]
    185   1.1  christos   =
    186   1.1  christos   {aop_const8, aop_const16, aop_const32, aop_const64};
    187   1.1  christos   int size;
    188   1.1  christos   int op;
    189   1.1  christos 
    190   1.1  christos   /* How big is the number?  'op' keeps track of which opcode to use.
    191   1.1  christos      Notice that we don't really care whether the original number was
    192   1.1  christos      signed or unsigned; we always reproduce the value exactly, and
    193   1.1  christos      use the shortest representation.  */
    194   1.1  christos   for (op = 0, size = 8; size < 64; size *= 2, op++)
    195   1.1  christos     {
    196   1.1  christos       LONGEST lim = ((LONGEST) 1) << (size - 1);
    197   1.1  christos 
    198  1.10  christos       if (-lim <= l && l <= lim - 1)
    199   1.1  christos 	break;
    200   1.1  christos     }
    201   1.1  christos 
    202   1.1  christos   /* Emit the right opcode...  */
    203   1.1  christos   ax_simple (x, ops[op]);
    204   1.1  christos 
    205   1.1  christos   /* Emit the low SIZE bytes as an unsigned number.  We know that
    206   1.1  christos      sign-extending this will yield l.  */
    207   1.1  christos   append_const (x, l, size / 8);
    208   1.1  christos 
    209   1.1  christos   /* Now, if it was negative, and not full-sized, sign-extend it.  */
    210   1.1  christos   if (l < 0 && size < 64)
    211   1.1  christos     ax_ext (x, size);
    212   1.1  christos }
    213   1.1  christos 
    214   1.1  christos 
    215   1.1  christos void
    216   1.1  christos ax_const_d (struct agent_expr *x, LONGEST d)
    217   1.1  christos {
    218   1.1  christos   /* FIXME: floating-point support not present yet.  */
    219   1.1  christos   error (_("GDB bug: ax-general.c (ax_const_d): "
    220   1.1  christos 	   "floating point not supported yet"));
    221   1.1  christos }
    222   1.1  christos 
    223   1.1  christos 
    224   1.1  christos /* Assemble code to push the value of register number REG on the
    225   1.1  christos    stack.  */
    226   1.1  christos void
    227   1.1  christos ax_reg (struct agent_expr *x, int reg)
    228   1.1  christos {
    229   1.1  christos   if (reg >= gdbarch_num_regs (x->gdbarch))
    230   1.1  christos     {
    231   1.1  christos       /* This is a pseudo-register.  */
    232   1.1  christos       if (!gdbarch_ax_pseudo_register_push_stack_p (x->gdbarch))
    233   1.1  christos 	error (_("'%s' is a pseudo-register; "
    234   1.1  christos 		 "GDB cannot yet trace its contents."),
    235   1.1  christos 	       user_reg_map_regnum_to_name (x->gdbarch, reg));
    236   1.1  christos       if (gdbarch_ax_pseudo_register_push_stack (x->gdbarch, x, reg))
    237   1.1  christos 	error (_("Trace '%s' failed."),
    238   1.1  christos 	       user_reg_map_regnum_to_name (x->gdbarch, reg));
    239   1.1  christos     }
    240   1.1  christos   else
    241   1.6  christos     {
    242   1.6  christos       /* Get the remote register number.  */
    243   1.6  christos       reg = gdbarch_remote_register_number (x->gdbarch, reg);
    244   1.1  christos 
    245   1.1  christos       /* Make sure the register number is in range.  */
    246  1.10  christos       if (reg < 0 || reg > 0xffff)
    247   1.1  christos 	error (_("GDB bug: ax-general.c (ax_reg): "
    248  1.11  christos 		 "register number out of range"));
    249  1.11  christos       x->buf.push_back (aop_reg);
    250  1.11  christos       x->buf.push_back ((reg >> 8) & 0xff);
    251   1.1  christos       x->buf.push_back ((reg) & 0xff);
    252   1.1  christos     }
    253   1.1  christos }
    254   1.1  christos 
    255   1.1  christos /* Assemble code to operate on a trace state variable.  */
    256   1.1  christos 
    257   1.1  christos void
    258   1.1  christos ax_tsv (struct agent_expr *x, enum agent_op op, int num)
    259   1.1  christos {
    260   1.1  christos   /* Make sure the tsv number is in range.  */
    261  1.10  christos   if (num < 0 || num > 0xffff)
    262   1.1  christos     internal_error (_("ax-general.c (ax_tsv): variable "
    263   1.1  christos 		      "number is %d, out of range"), num);
    264  1.11  christos 
    265  1.11  christos   x->buf.push_back (op);
    266  1.11  christos   x->buf.push_back ((num >> 8) & 0xff);
    267   1.1  christos   x->buf.push_back ((num) & 0xff);
    268   1.1  christos }
    269   1.1  christos 
    270   1.1  christos /* Append a string to the expression.  Note that the string is going
    271   1.1  christos    into the bytecodes directly, not on the stack.  As a precaution,
    272   1.1  christos    include both length as prefix, and terminate with a NUL.  (The NUL
    273   1.1  christos    is counted in the length.)  */
    274   1.1  christos 
    275   1.1  christos void
    276   1.1  christos ax_string (struct agent_expr *x, const char *str, int slen)
    277   1.1  christos {
    278   1.1  christos   int i;
    279   1.1  christos 
    280   1.1  christos   /* Make sure the string length is reasonable.  */
    281  1.10  christos   if (slen < 0 || slen > 0xffff)
    282   1.1  christos     internal_error (_("ax-general.c (ax_string): string "
    283   1.1  christos 		      "length is %d, out of allowed range"), slen);
    284  1.11  christos 
    285  1.11  christos   x->buf.push_back (((slen + 1) >> 8) & 0xff);
    286   1.1  christos   x->buf.push_back ((slen + 1) & 0xff);
    287  1.11  christos   for (i = 0; i < slen; ++i)
    288  1.11  christos     x->buf.push_back (str[i]);
    289   1.1  christos   x->buf.push_back ('\0');
    290   1.1  christos }
    291   1.1  christos 
    292   1.1  christos 
    294   1.1  christos 
    295   1.1  christos /* Functions for disassembling agent expressions, and otherwise
    296  1.11  christos    debugging the expression compiler.  */
    297  1.11  christos 
    298  1.11  christos /* An entry in the opcode map.  */
    299  1.11  christos struct aop_map
    300  1.11  christos   {
    301  1.11  christos 
    302  1.11  christos     /* The name of the opcode.  Null means that this entry is not a
    303  1.11  christos        valid opcode --- a hole in the opcode space.  */
    304  1.11  christos     const char *name;
    305  1.11  christos 
    306  1.11  christos     /* All opcodes take no operands from the bytecode stream, or take
    307  1.11  christos        unsigned integers of various sizes.  If this is a positive number
    308  1.11  christos        n, then the opcode is followed by an n-byte operand, which should
    309  1.11  christos        be printed as an unsigned integer.  If this is zero, then the
    310  1.11  christos        opcode takes no operands from the bytecode stream.
    311  1.11  christos 
    312  1.11  christos        If we get more complicated opcodes in the future, don't add other
    313  1.11  christos        magic values of this; that's a crock.  Add an `enum encoding'
    314  1.11  christos        field to this, or something like that.  */
    315  1.11  christos     int op_size;
    316  1.11  christos 
    317  1.11  christos     /* The size of the data operated upon, in bits, for bytecodes that
    318  1.11  christos        care about that (ref and const).  Zero for all others.  */
    319  1.11  christos     int data_size;
    320  1.11  christos 
    321  1.11  christos     /* Number of stack elements consumed, and number produced.  */
    322  1.11  christos     int consumed, produced;
    323  1.11  christos   };
    324  1.11  christos 
    325  1.11  christos /* Map of the bytecodes, indexed by bytecode number.  */
    326   1.1  christos 
    327   1.1  christos static struct aop_map aop_map[] =
    328   1.1  christos {
    329   1.1  christos   {0, 0, 0, 0, 0}
    330   1.9  christos #define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) \
    331   1.1  christos   , { # NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED }
    332   1.1  christos #include "gdbsupport/ax.def"
    333   1.1  christos #undef DEFOP
    334   1.1  christos };
    335   1.1  christos 
    336   1.1  christos 
    337   1.1  christos /* Disassemble the expression EXPR, writing to F.  */
    338   1.1  christos void
    339   1.1  christos ax_print (struct ui_file *f, struct agent_expr *x)
    340   1.1  christos {
    341  1.10  christos   int i;
    342  1.10  christos 
    343  1.11  christos   gdb_printf (f, _("Scope: %s\n"), paddress (x->gdbarch, x->scope));
    344  1.11  christos   gdb_printf (f, _("Reg mask:"));
    345  1.11  christos   for (i = 0; i < x->reg_mask.size (); ++i)
    346  1.11  christos     {
    347  1.11  christos       if ((i % 8) == 0)
    348  1.11  christos 	gdb_printf (f, " ");
    349  1.10  christos       gdb_printf (f, _("%d"), (int) x->reg_mask[i]);
    350   1.1  christos     }
    351  1.11  christos   gdb_printf (f, _("\n"));
    352   1.1  christos 
    353   1.6  christos   for (i = 0; i < x->buf.size ();)
    354   1.1  christos     {
    355  1.11  christos       enum agent_op op = (enum agent_op) x->buf[i];
    356   1.1  christos 
    357  1.10  christos       if (op >= ARRAY_SIZE (aop_map) || aop_map[op].name == nullptr)
    358   1.1  christos 	{
    359   1.1  christos 	  gdb_printf (f, _("%3d  <bad opcode %02x>\n"), i, op);
    360   1.1  christos 	  i++;
    361  1.11  christos 	  continue;
    362   1.1  christos 	}
    363  1.10  christos       if (i + 1 + aop_map[op].op_size > x->buf.size ())
    364  1.10  christos 	{
    365   1.1  christos 	  gdb_printf (f, _("%3d  <incomplete opcode %s>\n"),
    366   1.1  christos 		      i, aop_map[op].name);
    367   1.1  christos 	  break;
    368  1.10  christos 	}
    369   1.1  christos 
    370   1.1  christos       gdb_printf (f, "%3d  %s", i, aop_map[op].name);
    371  1.10  christos       if (aop_map[op].op_size > 0)
    372   1.1  christos 	{
    373   1.1  christos 	  gdb_puts (" ", f);
    374   1.1  christos 
    375   1.1  christos 	  print_longest (f, 'd', 0,
    376   1.1  christos 			 read_const (x, i + 1, aop_map[op].op_size));
    377   1.1  christos 	}
    378   1.1  christos       /* Handle the complicated printf arguments specially.  */
    379   1.1  christos       else if (op == aop_printf)
    380   1.1  christos 	{
    381   1.1  christos 	  int slen, nargs;
    382   1.1  christos 
    383   1.1  christos 	  i++;
    384   1.1  christos 	  nargs = x->buf[i++];
    385  1.10  christos 	  slen = x->buf[i++];
    386  1.10  christos 	  slen = slen * 256 + x->buf[i++];
    387   1.1  christos 	  gdb_printf (f, _(" \"%s\", %d args"),
    388   1.1  christos 		      &(x->buf[i]), nargs);
    389  1.10  christos 	  i += slen - 1;
    390   1.1  christos 	}
    391   1.1  christos       gdb_printf (f, "\n");
    392   1.1  christos       i += 1 + aop_map[op].op_size;
    393   1.1  christos     }
    394   1.1  christos }
    395   1.1  christos 
    396   1.1  christos /* Add register REG to the register mask for expression AX.  */
    397   1.1  christos void
    398   1.1  christos ax_reg_mask (struct agent_expr *ax, int reg)
    399   1.1  christos {
    400   1.1  christos   if (reg >= gdbarch_num_regs (ax->gdbarch))
    401   1.1  christos     {
    402   1.1  christos       /* This is a pseudo-register.  */
    403   1.1  christos       if (!gdbarch_ax_pseudo_register_collect_p (ax->gdbarch))
    404   1.1  christos 	error (_("'%s' is a pseudo-register; "
    405   1.1  christos 		 "GDB cannot yet trace its contents."),
    406   1.1  christos 	       user_reg_map_regnum_to_name (ax->gdbarch, reg));
    407   1.1  christos       if (gdbarch_ax_pseudo_register_collect (ax->gdbarch, ax, reg))
    408   1.1  christos 	error (_("Trace '%s' failed."),
    409   1.1  christos 	       user_reg_map_regnum_to_name (ax->gdbarch, reg));
    410   1.1  christos     }
    411   1.6  christos   else
    412   1.6  christos     {
    413   1.1  christos       /* Get the remote register number.  */
    414   1.1  christos       reg = gdbarch_remote_register_number (ax->gdbarch, reg);
    415  1.11  christos 
    416  1.11  christos       /* Grow the bit mask if necessary.  */
    417   1.1  christos       if (reg >= ax->reg_mask.size ())
    418  1.11  christos 	ax->reg_mask.resize (reg + 1);
    419   1.1  christos 
    420   1.1  christos       ax->reg_mask[reg] = true;
    421   1.1  christos     }
    422   1.1  christos }
    423   1.1  christos 
    424   1.1  christos /* Given an agent expression AX, fill in requirements and other descriptive
    425   1.1  christos    bits.  */
    426   1.1  christos void
    427   1.1  christos ax_reqs (struct agent_expr *ax)
    428   1.1  christos {
    429   1.1  christos   int i;
    430   1.1  christos   int height;
    431   1.1  christos 
    432  1.11  christos   /* Jump target table.  targets[i] is non-zero iff we have found a
    433   1.1  christos      jump to offset i.  */
    434   1.1  christos   char *targets = (char *) alloca (ax->buf.size () * sizeof (targets[0]));
    435   1.1  christos 
    436  1.11  christos   /* Instruction boundary table.  boundary[i] is non-zero iff our scan
    437   1.1  christos      has reached an instruction starting at offset i.  */
    438   1.1  christos   char *boundary = (char *) alloca (ax->buf.size () * sizeof (boundary[0]));
    439   1.1  christos 
    440   1.1  christos   /* Stack height record.  If either targets[i] or boundary[i] is
    441  1.11  christos      non-zero, heights[i] is the height the stack should have before
    442   1.1  christos      executing the bytecode at that point.  */
    443   1.1  christos   int *heights = (int *) alloca (ax->buf.size () * sizeof (heights[0]));
    444   1.1  christos 
    445   1.1  christos   /* Pointer to a description of the present op.  */
    446  1.11  christos   struct aop_map *op;
    447  1.11  christos 
    448   1.1  christos   memset (targets, 0, ax->buf.size () * sizeof (targets[0]));
    449   1.1  christos   memset (boundary, 0, ax->buf.size () * sizeof (boundary[0]));
    450   1.1  christos 
    451   1.1  christos   ax->max_height = ax->min_height = height = 0;
    452   1.1  christos   ax->flaw = agent_flaw_none;
    453  1.11  christos   ax->max_data_size = 0;
    454   1.1  christos 
    455  1.11  christos   for (i = 0; i < ax->buf.size (); i += 1 + op->op_size)
    456   1.1  christos     {
    457   1.1  christos       if (ax->buf[i] >= ARRAY_SIZE (aop_map))
    458   1.1  christos 	{
    459   1.1  christos 	  ax->flaw = agent_flaw_bad_instruction;
    460   1.1  christos 	  return;
    461   1.1  christos 	}
    462   1.1  christos 
    463   1.1  christos       op = &aop_map[ax->buf[i]];
    464   1.1  christos 
    465   1.1  christos       if (!op->name)
    466   1.1  christos 	{
    467   1.1  christos 	  ax->flaw = agent_flaw_bad_instruction;
    468   1.1  christos 	  return;
    469  1.11  christos 	}
    470   1.1  christos 
    471   1.1  christos       if (i + 1 + op->op_size > ax->buf.size ())
    472   1.1  christos 	{
    473   1.1  christos 	  ax->flaw = agent_flaw_incomplete_instruction;
    474   1.1  christos 	  return;
    475   1.1  christos 	}
    476  1.10  christos 
    477  1.10  christos       /* If this instruction is a forward jump target, does the
    478   1.1  christos 	 current stack height match the stack height at the jump
    479   1.1  christos 	 source?  */
    480   1.1  christos       if (targets[i] && (heights[i] != height))
    481   1.1  christos 	{
    482   1.1  christos 	  ax->flaw = agent_flaw_height_mismatch;
    483   1.1  christos 	  return;
    484   1.1  christos 	}
    485   1.1  christos 
    486   1.1  christos       boundary[i] = 1;
    487   1.1  christos       heights[i] = height;
    488   1.1  christos 
    489   1.1  christos       height -= op->consumed;
    490   1.1  christos       if (height < ax->min_height)
    491   1.1  christos 	ax->min_height = height;
    492   1.1  christos       height += op->produced;
    493   1.1  christos       if (height > ax->max_height)
    494   1.1  christos 	ax->max_height = height;
    495   1.1  christos 
    496   1.1  christos       if (op->data_size > ax->max_data_size)
    497   1.1  christos 	ax->max_data_size = op->data_size;
    498  1.10  christos 
    499  1.10  christos       /* For jump instructions, check that the target is a valid
    500   1.1  christos 	 offset.  If it is, record the fact that that location is a
    501   1.1  christos 	 jump target, and record the height we expect there.  */
    502   1.1  christos       if (aop_goto == op - aop_map
    503   1.1  christos 	  || aop_if_goto == op - aop_map)
    504  1.11  christos 	{
    505   1.1  christos 	  int target = read_const (ax, i + 1, 2);
    506   1.1  christos 	  if (target < 0 || target >= ax->buf.size ())
    507   1.1  christos 	    {
    508   1.1  christos 	      ax->flaw = agent_flaw_bad_jump;
    509   1.1  christos 	      return;
    510   1.1  christos 	    }
    511  1.10  christos 
    512   1.1  christos 	  /* Do we have any information about what the stack height
    513   1.1  christos 	     should be at the target?  */
    514   1.1  christos 	  if (targets[target] || boundary[target])
    515   1.1  christos 	    {
    516   1.1  christos 	      if (heights[target] != height)
    517   1.1  christos 		{
    518   1.1  christos 		  ax->flaw = agent_flaw_height_mismatch;
    519   1.1  christos 		  return;
    520   1.1  christos 		}
    521  1.10  christos 	    }
    522  1.10  christos 
    523  1.10  christos 	  /* Record the target, along with the stack height we expect.  */
    524   1.1  christos 	  targets[target] = 1;
    525   1.1  christos 	  heights[target] = height;
    526   1.1  christos 	}
    527  1.10  christos 
    528   1.1  christos       /* For unconditional jumps with a successor, check that the
    529  1.11  christos 	 successor is a target, and pick up its stack height.  */
    530   1.1  christos       if (aop_goto == op - aop_map
    531   1.1  christos 	  && i + 3 < ax->buf.size ())
    532   1.1  christos 	{
    533   1.1  christos 	  if (!targets[i + 3])
    534   1.1  christos 	    {
    535   1.1  christos 	      ax->flaw = agent_flaw_hole;
    536   1.1  christos 	      return;
    537   1.1  christos 	    }
    538   1.1  christos 
    539   1.1  christos 	  height = heights[i + 3];
    540   1.1  christos 	}
    541   1.1  christos 
    542   1.1  christos       /* For reg instructions, record the register in the bit mask.  */
    543   1.1  christos       if (aop_reg == op - aop_map)
    544   1.1  christos 	{
    545   1.1  christos 	  int reg = read_const (ax, i + 1, 2);
    546   1.1  christos 
    547   1.1  christos 	  ax_reg_mask (ax, reg);
    548   1.1  christos 	}
    549   1.1  christos     }
    550  1.11  christos 
    551   1.1  christos   /* Check that all the targets are on boundaries.  */
    552   1.1  christos   for (i = 0; i < ax->buf.size (); i++)
    553   1.1  christos     if (targets[i] && !boundary[i])
    554   1.1  christos       {
    555   1.1  christos 	ax->flaw = agent_flaw_bad_jump;
    556   1.1  christos 	return;
    557   1.1  christos       }
    558   1.1  christos 
    559                   ax->final_height = height;
    560                 }
    561