146283Sdfr/* Functions for manipulating expressions designed to be executed on the agent
298944Sobrien   Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
346283Sdfr
498944Sobrien   This file is part of GDB.
546283Sdfr
698944Sobrien   This program is free software; you can redistribute it and/or modify
798944Sobrien   it under the terms of the GNU General Public License as published by
898944Sobrien   the Free Software Foundation; either version 2 of the License, or
998944Sobrien   (at your option) any later version.
1046283Sdfr
1198944Sobrien   This program is distributed in the hope that it will be useful,
1298944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1398944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1498944Sobrien   GNU General Public License for more details.
1546283Sdfr
1698944Sobrien   You should have received a copy of the GNU General Public License
1798944Sobrien   along with this program; if not, write to the Free Software
1898944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
1998944Sobrien   Boston, MA 02111-1307, USA.  */
2046283Sdfr
2146283Sdfr/* Despite what the above comment says about this file being part of
2246283Sdfr   GDB, we would like to keep these functions free of GDB
2346283Sdfr   dependencies, since we want to be able to use them in contexts
2446283Sdfr   outside of GDB (test suites, the stub, etc.)  */
2546283Sdfr
2646283Sdfr#include "defs.h"
2746283Sdfr#include "ax.h"
2846283Sdfr
2998944Sobrien#include "value.h"
30130803Smarcel#include "gdb_string.h"
3198944Sobrien
3298944Sobrienstatic void grow_expr (struct agent_expr *x, int n);
3398944Sobrien
3498944Sobrienstatic void append_const (struct agent_expr *x, LONGEST val, int n);
3598944Sobrien
3698944Sobrienstatic LONGEST read_const (struct agent_expr *x, int o, int n);
3798944Sobrien
3898944Sobrienstatic void generic_ext (struct agent_expr *x, enum agent_op op, int n);
3946283Sdfr
4046283Sdfr/* Functions for building expressions.  */
4146283Sdfr
4246283Sdfr/* Allocate a new, empty agent expression.  */
4346283Sdfrstruct agent_expr *
4498944Sobriennew_agent_expr (CORE_ADDR scope)
4546283Sdfr{
4646283Sdfr  struct agent_expr *x = xmalloc (sizeof (*x));
4798944Sobrien  x->len = 0;
4846283Sdfr  x->size = 1;			/* Change this to a larger value once
4946283Sdfr				   reallocation code is tested.  */
5098944Sobrien  x->buf = xmalloc (x->size);
5146283Sdfr  x->scope = scope;
5246283Sdfr
5346283Sdfr  return x;
5446283Sdfr}
5546283Sdfr
5646283Sdfr/* Free a agent expression.  */
5746283Sdfrvoid
5898944Sobrienfree_agent_expr (struct agent_expr *x)
5946283Sdfr{
6098944Sobrien  xfree (x->buf);
6198944Sobrien  xfree (x);
6246283Sdfr}
6346283Sdfr
6498944Sobrienstatic void
6598944Sobriendo_free_agent_expr_cleanup (void *x)
6698944Sobrien{
6798944Sobrien  free_agent_expr (x);
6898944Sobrien}
6946283Sdfr
7098944Sobrienstruct cleanup *
7198944Sobrienmake_cleanup_free_agent_expr (struct agent_expr *x)
7298944Sobrien{
7398944Sobrien  return make_cleanup (do_free_agent_expr_cleanup, x);
7498944Sobrien}
7598944Sobrien
7698944Sobrien
7746283Sdfr/* Make sure that X has room for at least N more bytes.  This doesn't
7846283Sdfr   affect the length, just the allocated size.  */
7946283Sdfrstatic void
8098944Sobriengrow_expr (struct agent_expr *x, int n)
8146283Sdfr{
8246283Sdfr  if (x->len + n > x->size)
8346283Sdfr    {
8446283Sdfr      x->size *= 2;
8546283Sdfr      if (x->size < x->len + n)
8646283Sdfr	x->size = x->len + n + 10;
8746283Sdfr      x->buf = xrealloc (x->buf, x->size);
8846283Sdfr    }
8946283Sdfr}
9046283Sdfr
9146283Sdfr
9246283Sdfr/* Append the low N bytes of VAL as an N-byte integer to the
9346283Sdfr   expression X, in big-endian order.  */
9446283Sdfrstatic void
9598944Sobrienappend_const (struct agent_expr *x, LONGEST val, int n)
9646283Sdfr{
9746283Sdfr  int i;
9846283Sdfr
9946283Sdfr  grow_expr (x, n);
10046283Sdfr  for (i = n - 1; i >= 0; i--)
10146283Sdfr    {
10246283Sdfr      x->buf[x->len + i] = val & 0xff;
10346283Sdfr      val >>= 8;
10446283Sdfr    }
10546283Sdfr  x->len += n;
10646283Sdfr}
10746283Sdfr
10846283Sdfr
10946283Sdfr/* Extract an N-byte big-endian unsigned integer from expression X at
11046283Sdfr   offset O.  */
11146283Sdfrstatic LONGEST
11298944Sobrienread_const (struct agent_expr *x, int o, int n)
11346283Sdfr{
11446283Sdfr  int i;
11546283Sdfr  LONGEST accum = 0;
11646283Sdfr
11746283Sdfr  /* Make sure we're not reading off the end of the expression.  */
11846283Sdfr  if (o + n > x->len)
11946283Sdfr    error ("GDB bug: ax-general.c (read_const): incomplete constant");
12046283Sdfr
12146283Sdfr  for (i = 0; i < n; i++)
12246283Sdfr    accum = (accum << 8) | x->buf[o + i];
12398944Sobrien
12446283Sdfr  return accum;
12546283Sdfr}
12646283Sdfr
12746283Sdfr
12846283Sdfr/* Append a simple operator OP to EXPR.  */
12946283Sdfrvoid
13098944Sobrienax_simple (struct agent_expr *x, enum agent_op op)
13146283Sdfr{
13246283Sdfr  grow_expr (x, 1);
13346283Sdfr  x->buf[x->len++] = op;
13446283Sdfr}
13546283Sdfr
13646283Sdfr
13746283Sdfr/* Append a sign-extension or zero-extension instruction to EXPR, to
13846283Sdfr   extend an N-bit value.  */
13946283Sdfrstatic void
14098944Sobriengeneric_ext (struct agent_expr *x, enum agent_op op, int n)
14146283Sdfr{
14246283Sdfr  /* N must fit in a byte.  */
14346283Sdfr  if (n < 0 || n > 255)
14446283Sdfr    error ("GDB bug: ax-general.c (generic_ext): bit count out of range");
14546283Sdfr  /* That had better be enough range.  */
14646283Sdfr  if (sizeof (LONGEST) * 8 > 255)
14746283Sdfr    error ("GDB bug: ax-general.c (generic_ext): opcode has inadequate range");
14846283Sdfr
14946283Sdfr  grow_expr (x, 2);
15046283Sdfr  x->buf[x->len++] = op;
15146283Sdfr  x->buf[x->len++] = n;
15246283Sdfr}
15346283Sdfr
15446283Sdfr
15546283Sdfr/* Append a sign-extension instruction to EXPR, to extend an N-bit value.  */
15646283Sdfrvoid
15798944Sobrienax_ext (struct agent_expr *x, int n)
15846283Sdfr{
15946283Sdfr  generic_ext (x, aop_ext, n);
16046283Sdfr}
16146283Sdfr
16246283Sdfr
16346283Sdfr/* Append a zero-extension instruction to EXPR, to extend an N-bit value.  */
16446283Sdfrvoid
16598944Sobrienax_zero_ext (struct agent_expr *x, int n)
16646283Sdfr{
16746283Sdfr  generic_ext (x, aop_zero_ext, n);
16846283Sdfr}
16946283Sdfr
17046283Sdfr
17146283Sdfr/* Append a trace_quick instruction to EXPR, to record N bytes.  */
17246283Sdfrvoid
17398944Sobrienax_trace_quick (struct agent_expr *x, int n)
17446283Sdfr{
17546283Sdfr  /* N must fit in a byte.  */
17646283Sdfr  if (n < 0 || n > 255)
17746283Sdfr    error ("GDB bug: ax-general.c (ax_trace_quick): size out of range for trace_quick");
17846283Sdfr
17946283Sdfr  grow_expr (x, 2);
18046283Sdfr  x->buf[x->len++] = aop_trace_quick;
18146283Sdfr  x->buf[x->len++] = n;
18246283Sdfr}
18346283Sdfr
18446283Sdfr
18546283Sdfr/* Append a goto op to EXPR.  OP is the actual op (must be aop_goto or
18646283Sdfr   aop_if_goto).  We assume we don't know the target offset yet,
18746283Sdfr   because it's probably a forward branch, so we leave space in EXPR
18846283Sdfr   for the target, and return the offset in EXPR of that space, so we
18946283Sdfr   can backpatch it once we do know the target offset.  Use ax_label
19046283Sdfr   to do the backpatching.  */
19198944Sobrienint
19298944Sobrienax_goto (struct agent_expr *x, enum agent_op op)
19346283Sdfr{
19446283Sdfr  grow_expr (x, 3);
19546283Sdfr  x->buf[x->len + 0] = op;
19646283Sdfr  x->buf[x->len + 1] = 0xff;
19746283Sdfr  x->buf[x->len + 2] = 0xff;
19846283Sdfr  x->len += 3;
19946283Sdfr  return x->len - 2;
20046283Sdfr}
20146283Sdfr
20246283Sdfr/* Suppose a given call to ax_goto returns some value PATCH.  When you
20346283Sdfr   know the offset TARGET that goto should jump to, call
20498944Sobrien   ax_label (EXPR, PATCH, TARGET)
20546283Sdfr   to patch TARGET into the ax_goto instruction.  */
20646283Sdfrvoid
20798944Sobrienax_label (struct agent_expr *x, int patch, int target)
20846283Sdfr{
20946283Sdfr  /* Make sure the value is in range.  Don't accept 0xffff as an
21046283Sdfr     offset; that's our magic sentinel value for unpatched branches.  */
21146283Sdfr  if (target < 0 || target >= 0xffff)
21246283Sdfr    error ("GDB bug: ax-general.c (ax_label): label target out of range");
21398944Sobrien
21446283Sdfr  x->buf[patch] = (target >> 8) & 0xff;
21546283Sdfr  x->buf[patch + 1] = target & 0xff;
21646283Sdfr}
21746283Sdfr
21846283Sdfr
21946283Sdfr/* Assemble code to push a constant on the stack.  */
22046283Sdfrvoid
22198944Sobrienax_const_l (struct agent_expr *x, LONGEST l)
22246283Sdfr{
22346283Sdfr  static enum agent_op ops[]
22498944Sobrien  =
22598944Sobrien  {aop_const8, aop_const16, aop_const32, aop_const64};
22646283Sdfr  int size;
22746283Sdfr  int op;
22846283Sdfr
22946283Sdfr  /* How big is the number?  'op' keeps track of which opcode to use.
23046283Sdfr     Notice that we don't really care whether the original number was
23146283Sdfr     signed or unsigned; we always reproduce the value exactly, and
23246283Sdfr     use the shortest representation.  */
23346283Sdfr  for (op = 0, size = 8; size < 64; size *= 2, op++)
23446283Sdfr    if (-((LONGEST) 1 << size) <= l && l < ((LONGEST) 1 << size))
23546283Sdfr      break;
23646283Sdfr
23746283Sdfr  /* Emit the right opcode... */
23846283Sdfr  ax_simple (x, ops[op]);
23946283Sdfr
24046283Sdfr  /* Emit the low SIZE bytes as an unsigned number.  We know that
24146283Sdfr     sign-extending this will yield l.  */
24246283Sdfr  append_const (x, l, size / 8);
24346283Sdfr
24446283Sdfr  /* Now, if it was negative, and not full-sized, sign-extend it.  */
24546283Sdfr  if (l < 0 && size < 64)
24646283Sdfr    ax_ext (x, size);
24746283Sdfr}
24846283Sdfr
24946283Sdfr
25046283Sdfrvoid
25198944Sobrienax_const_d (struct agent_expr *x, LONGEST d)
25246283Sdfr{
25346283Sdfr  /* FIXME: floating-point support not present yet.  */
25446283Sdfr  error ("GDB bug: ax-general.c (ax_const_d): floating point not supported yet");
25546283Sdfr}
25646283Sdfr
25746283Sdfr
25846283Sdfr/* Assemble code to push the value of register number REG on the
25946283Sdfr   stack.  */
26098944Sobrienvoid
26198944Sobrienax_reg (struct agent_expr *x, int reg)
26246283Sdfr{
26346283Sdfr  /* Make sure the register number is in range.  */
26446283Sdfr  if (reg < 0 || reg > 0xffff)
26546283Sdfr    error ("GDB bug: ax-general.c (ax_reg): register number out of range");
26646283Sdfr  grow_expr (x, 3);
26798944Sobrien  x->buf[x->len] = aop_reg;
26846283Sdfr  x->buf[x->len + 1] = (reg >> 8) & 0xff;
26998944Sobrien  x->buf[x->len + 2] = (reg) & 0xff;
27046283Sdfr  x->len += 3;
27146283Sdfr}
27298944Sobrien
27346283Sdfr
27446283Sdfr
27546283Sdfr/* Functions for disassembling agent expressions, and otherwise
27646283Sdfr   debugging the expression compiler.  */
27746283Sdfr
27898944Sobrienstruct aop_map aop_map[] =
27998944Sobrien{
28098944Sobrien  {0, 0, 0, 0, 0},
28198944Sobrien  {"float", 0, 0, 0, 0},	/* 0x01 */
28298944Sobrien  {"add", 0, 0, 2, 1},		/* 0x02 */
28398944Sobrien  {"sub", 0, 0, 2, 1},		/* 0x03 */
28498944Sobrien  {"mul", 0, 0, 2, 1},		/* 0x04 */
28598944Sobrien  {"div_signed", 0, 0, 2, 1},	/* 0x05 */
28698944Sobrien  {"div_unsigned", 0, 0, 2, 1},	/* 0x06 */
28798944Sobrien  {"rem_signed", 0, 0, 2, 1},	/* 0x07 */
28898944Sobrien  {"rem_unsigned", 0, 0, 2, 1},	/* 0x08 */
28998944Sobrien  {"lsh", 0, 0, 2, 1},		/* 0x09 */
29098944Sobrien  {"rsh_signed", 0, 0, 2, 1},	/* 0x0a */
29198944Sobrien  {"rsh_unsigned", 0, 0, 2, 1},	/* 0x0b */
29298944Sobrien  {"trace", 0, 0, 2, 0},	/* 0x0c */
29398944Sobrien  {"trace_quick", 1, 0, 1, 1},	/* 0x0d */
29498944Sobrien  {"log_not", 0, 0, 1, 1},	/* 0x0e */
29598944Sobrien  {"bit_and", 0, 0, 2, 1},	/* 0x0f */
29698944Sobrien  {"bit_or", 0, 0, 2, 1},	/* 0x10 */
29798944Sobrien  {"bit_xor", 0, 0, 2, 1},	/* 0x11 */
29898944Sobrien  {"bit_not", 0, 0, 1, 1},	/* 0x12 */
29998944Sobrien  {"equal", 0, 0, 2, 1},	/* 0x13 */
30098944Sobrien  {"less_signed", 0, 0, 2, 1},	/* 0x14 */
30198944Sobrien  {"less_unsigned", 0, 0, 2, 1},	/* 0x15 */
30298944Sobrien  {"ext", 1, 0, 1, 1},		/* 0x16 */
30398944Sobrien  {"ref8", 0, 8, 1, 1},		/* 0x17 */
30498944Sobrien  {"ref16", 0, 16, 1, 1},	/* 0x18 */
30598944Sobrien  {"ref32", 0, 32, 1, 1},	/* 0x19 */
30698944Sobrien  {"ref64", 0, 64, 1, 1},	/* 0x1a */
30798944Sobrien  {"ref_float", 0, 0, 1, 1},	/* 0x1b */
30898944Sobrien  {"ref_double", 0, 0, 1, 1},	/* 0x1c */
30998944Sobrien  {"ref_long_double", 0, 0, 1, 1},	/* 0x1d */
31098944Sobrien  {"l_to_d", 0, 0, 1, 1},	/* 0x1e */
31198944Sobrien  {"d_to_l", 0, 0, 1, 1},	/* 0x1f */
31298944Sobrien  {"if_goto", 2, 0, 1, 0},	/* 0x20 */
31398944Sobrien  {"goto", 2, 0, 0, 0},		/* 0x21 */
31498944Sobrien  {"const8", 1, 8, 0, 1},	/* 0x22 */
31598944Sobrien  {"const16", 2, 16, 0, 1},	/* 0x23 */
31698944Sobrien  {"const32", 4, 32, 0, 1},	/* 0x24 */
31798944Sobrien  {"const64", 8, 64, 0, 1},	/* 0x25 */
31898944Sobrien  {"reg", 2, 0, 0, 1},		/* 0x26 */
31998944Sobrien  {"end", 0, 0, 0, 0},		/* 0x27 */
32098944Sobrien  {"dup", 0, 0, 1, 2},		/* 0x28 */
32198944Sobrien  {"pop", 0, 0, 1, 0},		/* 0x29 */
32298944Sobrien  {"zero_ext", 1, 0, 1, 1},	/* 0x2a */
32398944Sobrien  {"swap", 0, 0, 2, 2},		/* 0x2b */
32498944Sobrien  {0, 0, 0, 0, 0},		/* 0x2c */
32598944Sobrien  {0, 0, 0, 0, 0},		/* 0x2d */
32698944Sobrien  {0, 0, 0, 0, 0},		/* 0x2e */
32798944Sobrien  {0, 0, 0, 0, 0},		/* 0x2f */
32898944Sobrien  {"trace16", 2, 0, 1, 1},	/* 0x30 */
32946283Sdfr};
33046283Sdfr
33146283Sdfr
33246283Sdfr/* Disassemble the expression EXPR, writing to F.  */
33346283Sdfrvoid
33498944Sobrienax_print (struct ui_file *f, struct agent_expr *x)
33546283Sdfr{
33646283Sdfr  int i;
33746283Sdfr  int is_float = 0;
33846283Sdfr
33946283Sdfr  /* Check the size of the name array against the number of entries in
34046283Sdfr     the enum, to catch additions that people didn't sync.  */
34146283Sdfr  if ((sizeof (aop_map) / sizeof (aop_map[0]))
34246283Sdfr      != aop_last)
34346283Sdfr    error ("GDB bug: ax-general.c (ax_print): opcode map out of sync");
34498944Sobrien
34598944Sobrien  for (i = 0; i < x->len;)
34646283Sdfr    {
34746283Sdfr      enum agent_op op = x->buf[i];
34846283Sdfr
34946283Sdfr      if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
35098944Sobrien	  || !aop_map[op].name)
35146283Sdfr	{
35246283Sdfr	  fprintf_filtered (f, "%3d  <bad opcode %02x>\n", i, op);
35346283Sdfr	  i++;
35446283Sdfr	  continue;
35546283Sdfr	}
35646283Sdfr      if (i + 1 + aop_map[op].op_size > x->len)
35746283Sdfr	{
35846283Sdfr	  fprintf_filtered (f, "%3d  <incomplete opcode %s>\n",
35946283Sdfr			    i, aop_map[op].name);
36046283Sdfr	  break;
36146283Sdfr	}
36246283Sdfr
36346283Sdfr      fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
36446283Sdfr      if (aop_map[op].op_size > 0)
36546283Sdfr	{
36646283Sdfr	  fputs_filtered (" ", f);
36798944Sobrien
36846283Sdfr	  print_longest (f, 'd', 0,
36946283Sdfr			 read_const (x, i + 1, aop_map[op].op_size));
37046283Sdfr	}
37146283Sdfr      fprintf_filtered (f, "\n");
37246283Sdfr      i += 1 + aop_map[op].op_size;
37346283Sdfr
37446283Sdfr      is_float = (op == aop_float);
37546283Sdfr    }
37646283Sdfr}
37746283Sdfr
37846283Sdfr
37946283Sdfr/* Given an agent expression AX, fill in an agent_reqs structure REQS
38046283Sdfr   describing it.  */
38146283Sdfrvoid
38298944Sobrienax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
38346283Sdfr{
38446283Sdfr  int i;
38546283Sdfr  int height;
38646283Sdfr
38746283Sdfr  /* Bit vector for registers used.  */
38846283Sdfr  int reg_mask_len = 1;
38946283Sdfr  unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));
39046283Sdfr
39146283Sdfr  /* Jump target table.  targets[i] is non-zero iff there is a jump to
39246283Sdfr     offset i.  */
39346283Sdfr  char *targets = (char *) alloca (ax->len * sizeof (targets[0]));
39446283Sdfr
39546283Sdfr  /* Instruction boundary table.  boundary[i] is non-zero iff an
39646283Sdfr     instruction starts at offset i.  */
39746283Sdfr  char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));
39846283Sdfr
39946283Sdfr  /* Stack height record.  iff either targets[i] or boundary[i] is
40046283Sdfr     non-zero, heights[i] is the height the stack should have before
40146283Sdfr     executing the bytecode at that point.  */
40246283Sdfr  int *heights = (int *) alloca (ax->len * sizeof (heights[0]));
40346283Sdfr
40446283Sdfr  /* Pointer to a description of the present op.  */
40546283Sdfr  struct aop_map *op;
40646283Sdfr
40746283Sdfr  memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
40846283Sdfr  memset (targets, 0, ax->len * sizeof (targets[0]));
40946283Sdfr  memset (boundary, 0, ax->len * sizeof (boundary[0]));
41046283Sdfr
41146283Sdfr  reqs->max_height = reqs->min_height = height = 0;
41246283Sdfr  reqs->flaw = agent_flaw_none;
41346283Sdfr  reqs->max_data_size = 0;
41446283Sdfr
41546283Sdfr  for (i = 0; i < ax->len; i += 1 + op->op_size)
41646283Sdfr    {
41746283Sdfr      if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
41846283Sdfr	{
41946283Sdfr	  reqs->flaw = agent_flaw_bad_instruction;
42098944Sobrien	  xfree (reg_mask);
42146283Sdfr	  return;
42246283Sdfr	}
42346283Sdfr
42446283Sdfr      op = &aop_map[ax->buf[i]];
42546283Sdfr
42698944Sobrien      if (!op->name)
42746283Sdfr	{
42846283Sdfr	  reqs->flaw = agent_flaw_bad_instruction;
42998944Sobrien	  xfree (reg_mask);
43046283Sdfr	  return;
43146283Sdfr	}
43298944Sobrien
43346283Sdfr      if (i + 1 + op->op_size > ax->len)
43446283Sdfr	{
43546283Sdfr	  reqs->flaw = agent_flaw_incomplete_instruction;
43698944Sobrien	  xfree (reg_mask);
43746283Sdfr	  return;
43846283Sdfr	}
43946283Sdfr
44046283Sdfr      /* If this instruction is a jump target, does the current stack
44146283Sdfr         height match the stack height at the jump source?  */
44246283Sdfr      if (targets[i] && (heights[i] != height))
44346283Sdfr	{
44446283Sdfr	  reqs->flaw = agent_flaw_height_mismatch;
44598944Sobrien	  xfree (reg_mask);
44646283Sdfr	  return;
44746283Sdfr	}
44846283Sdfr
44946283Sdfr      boundary[i] = 1;
45046283Sdfr      heights[i] = height;
45146283Sdfr
45246283Sdfr      height -= op->consumed;
45346283Sdfr      if (height < reqs->min_height)
45446283Sdfr	reqs->min_height = height;
45546283Sdfr      height += op->produced;
45646283Sdfr      if (height > reqs->max_height)
45746283Sdfr	reqs->max_height = height;
45846283Sdfr
45946283Sdfr      if (op->data_size > reqs->max_data_size)
46046283Sdfr	reqs->max_data_size = op->data_size;
46146283Sdfr
46246283Sdfr      /* For jump instructions, check that the target is a valid
46398944Sobrien         offset.  If it is, record the fact that that location is a
46498944Sobrien         jump target, and record the height we expect there.  */
46546283Sdfr      if (aop_goto == op - aop_map
46646283Sdfr	  || aop_if_goto == op - aop_map)
46746283Sdfr	{
46846283Sdfr	  int target = read_const (ax, i + 1, 2);
46946283Sdfr	  if (target < 0 || target >= ax->len)
47046283Sdfr	    {
47146283Sdfr	      reqs->flaw = agent_flaw_bad_jump;
47298944Sobrien	      xfree (reg_mask);
47346283Sdfr	      return;
47446283Sdfr	    }
47546283Sdfr	  /* Have we already found other jumps to the same location?  */
47646283Sdfr	  else if (targets[target])
47746283Sdfr	    {
47846283Sdfr	      if (heights[i] != height)
47946283Sdfr		{
48046283Sdfr		  reqs->flaw = agent_flaw_height_mismatch;
48198944Sobrien		  xfree (reg_mask);
48246283Sdfr		  return;
48346283Sdfr		}
48446283Sdfr	    }
48546283Sdfr	  else
48646283Sdfr	    {
48746283Sdfr	      targets[target] = 1;
48846283Sdfr	      heights[target] = height;
48946283Sdfr	    }
49046283Sdfr	}
49198944Sobrien
49246283Sdfr      /* For unconditional jumps with a successor, check that the
49346283Sdfr         successor is a target, and pick up its stack height.  */
49446283Sdfr      if (aop_goto == op - aop_map
49546283Sdfr	  && i + 3 < ax->len)
49646283Sdfr	{
49798944Sobrien	  if (!targets[i + 3])
49846283Sdfr	    {
49946283Sdfr	      reqs->flaw = agent_flaw_hole;
50098944Sobrien	      xfree (reg_mask);
50146283Sdfr	      return;
50246283Sdfr	    }
50346283Sdfr
50446283Sdfr	  height = heights[i + 3];
50546283Sdfr	}
50646283Sdfr
50746283Sdfr      /* For reg instructions, record the register in the bit mask.  */
50846283Sdfr      if (aop_reg == op - aop_map)
50946283Sdfr	{
51046283Sdfr	  int reg = read_const (ax, i + 1, 2);
51146283Sdfr	  int byte = reg / 8;
51246283Sdfr
51346283Sdfr	  /* Grow the bit mask if necessary.  */
51446283Sdfr	  if (byte >= reg_mask_len)
51546283Sdfr	    {
51646283Sdfr	      /* It's not appropriate to double here.  This isn't a
51798944Sobrien	         string buffer.  */
51846283Sdfr	      int new_len = byte + 1;
51998944Sobrien	      reg_mask = xrealloc (reg_mask,
52046283Sdfr				   new_len * sizeof (reg_mask[0]));
52146283Sdfr	      memset (reg_mask + reg_mask_len, 0,
52246283Sdfr		      (new_len - reg_mask_len) * sizeof (reg_mask[0]));
52346283Sdfr	      reg_mask_len = new_len;
52446283Sdfr	    }
52546283Sdfr
52646283Sdfr	  reg_mask[byte] |= 1 << (reg % 8);
52746283Sdfr	}
52846283Sdfr    }
52946283Sdfr
53046283Sdfr  /* Check that all the targets are on boundaries.  */
53146283Sdfr  for (i = 0; i < ax->len; i++)
53246283Sdfr    if (targets[i] && !boundary[i])
53346283Sdfr      {
53446283Sdfr	reqs->flaw = agent_flaw_bad_jump;
53598944Sobrien	xfree (reg_mask);
53646283Sdfr	return;
53746283Sdfr      }
53846283Sdfr
53946283Sdfr  reqs->final_height = height;
54046283Sdfr  reqs->reg_mask_len = reg_mask_len;
54146283Sdfr  reqs->reg_mask = reg_mask;
54246283Sdfr}
543