Exemple #1
0
/* Disassemble the expression EXPR, writing to F.  */
void
ax_print (struct ui_file *f, struct agent_expr *x)
{
    int i;

    fprintf_filtered (f, _("Scope: %s\n"), paddress (x->gdbarch, x->scope));
    fprintf_filtered (f, _("Reg mask:"));
    for (i = 0; i < x->reg_mask_len; ++i)
        fprintf_filtered (f, _(" %02x"), x->reg_mask[i]);
    fprintf_filtered (f, _("\n"));

    /* Check the size of the name array against the number of entries in
       the enum, to catch additions that people didn't sync.  */
    if ((sizeof (aop_map) / sizeof (aop_map[0]))
            != aop_last)
        error (_("GDB bug: ax-general.c (ax_print): opcode map out of sync"));

    for (i = 0; i < x->len;)
    {
        enum agent_op op = x->buf[i];

        if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
                || !aop_map[op].name)
        {
            fprintf_filtered (f, _("%3d  <bad opcode %02x>\n"), i, op);
            i++;
            continue;
        }
        if (i + 1 + aop_map[op].op_size > x->len)
        {
            fprintf_filtered (f, _("%3d  <incomplete opcode %s>\n"),
                              i, aop_map[op].name);
            break;
        }

        fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
        if (aop_map[op].op_size > 0)
        {
            fputs_filtered (" ", f);

            print_longest (f, 'd', 0,
                           read_const (x, i + 1, aop_map[op].op_size));
        }
        /* Handle the complicated printf arguments specially.  */
        else if (op == aop_printf)
        {
            int slen, nargs;

            i++;
            nargs = x->buf[i++];
            slen = x->buf[i++];
            slen = slen * 256 + x->buf[i++];
            fprintf_filtered (f, _(" \"%s\", %d args"),
                              &(x->buf[i]), nargs);
            i += slen - 1;
        }
        fprintf_filtered (f, "\n");
        i += 1 + aop_map[op].op_size;
    }
}
Exemple #2
0
PCFOP * read_instr(struct PCFState * st, const char * line, uint32_t iptr)
{
  char buf[LINE_MAX], *bitr;
  buf[0] = '\0';
  bitr = buf;

  assert(line[0] == '(');
  line++;

  while((line[0] != ' ') && (line[0] != ')'))
    {
      bitr[0] = line[0];
      line++;
      bitr++;
    }
  bitr[0] = '\0';

  if(strcmp(buf, "LABEL") == 0)
    return read_label(line, st, iptr);
  else if(strcmp(buf, "INITBASE") == 0)
    return read_initbase(line);
  else if(strcmp(buf, "CONST") == 0)
    return read_const(line);
  else if(strcmp(buf, "GATE") == 0)
    return read_gate(line);
  else if(strcmp(buf, "BITS") == 0)
    return read_bits(line);
  else if(strcmp(buf, "MKPTR") == 0)
    return read_mkptr(line);
  else if(strcmp(buf, "COPY") == 0)
    return read_copy(line);
  else if(strcmp(buf, "COPY-INDIR") == 0)
    return read_copy_indir(line);
  else if(strcmp(buf, "INDIR-COPY") == 0)
    return read_indir_copy(line);
  else if(strcmp(buf, "CALL") == 0)
    return read_call(line);
  else if(strcmp(buf, "RET") == 0)
    return read_ret(line);
  else if(strcmp(buf, "BRANCH") == 0)
    return read_branch(line);
  else if(strcmp(buf, "CLEAR") == 0)
    return read_clear(line);
  else if(strcmp(buf, "JOIN") == 0)
    return read_join(line);
  else if(strcmp(buf, "ADD") == 0)
    return read_add(line);
  else if(strcmp(buf, "MUL") == 0)
    return read_mul(line);
  assert(0);
}
/* Disassemble the expression EXPR, writing to F.  */
void
ax_print(struct ui_file *f, struct agent_expr *x)
{
  long i;
  bool is_float = 0;

  /* Check the size of the name array against the number of entries in
   * the enum, to catch additions that people did NOT sync: */
  if ((sizeof(aop_map) / sizeof(aop_map[0]))
      != aop_last)
    error(_("GDB bug: ax-general.c (ax_print): opcode map out of sync"));

  for (i = 0; i < (long)x->len;)
    {
      enum agent_op op = (enum agent_op)x->buf[i];

      if ((op >= (sizeof(aop_map) / sizeof(aop_map[0])))
	  || !aop_map[op].name)
	{
	  fprintf_filtered(f, _("%3d  <bad opcode %02x>\n"), (int)i, op);
	  i++;
	  continue;
	}
      if (((size_t)(i + 1L) + aop_map[op].op_size) > x->len)
	{
	  fprintf_filtered(f, _("%3d  <incomplete opcode %s>\n"),
			   (int)i, aop_map[op].name);
	  break;
	}

      fprintf_filtered(f, "%3d  %s", (int)i, aop_map[op].name);
      if (aop_map[op].op_size > 0)
	{
	  fputs_filtered(" ", f);

	  print_longest(f, 'd', 0,
                        read_const(x, (int)(i + 1), (int)aop_map[op].op_size));
	}
      fprintf_filtered(f, "\n");
      i += (1L + (long)aop_map[op].op_size);

      is_float = (op == aop_float);

      if (is_float) {
        ; /* ??? */
      }
    }
}
/* Disassemble the expression EXPR, writing to F.  */
void
ax_print (struct ui_file *f, struct agent_expr *x)
{
  int i;
  int is_float = 0;

  /* Check the size of the name array against the number of entries in
     the enum, to catch additions that people didn't sync.  */
  if ((sizeof (aop_map) / sizeof (aop_map[0]))
      != aop_last)
    error (_("GDB bug: ax-general.c (ax_print): opcode map out of sync"));

  for (i = 0; i < x->len;)
    {
      enum agent_op op = x->buf[i];

      if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
	  || !aop_map[op].name)
	{
	  fprintf_filtered (f, _("%3d  <bad opcode %02x>\n"), i, op);
	  i++;
	  continue;
	}
      if (i + 1 + aop_map[op].op_size > x->len)
	{
	  fprintf_filtered (f, _("%3d  <incomplete opcode %s>\n"),
			    i, aop_map[op].name);
	  break;
	}

      fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
      if (aop_map[op].op_size > 0)
	{
	  fputs_filtered (" ", f);

	  print_longest (f, 'd', 0,
			 read_const (x, i + 1, aop_map[op].op_size));
	}
      fprintf_filtered (f, "\n");
      i += 1 + aop_map[op].op_size;

      is_float = (op == aop_float);
    }
}
Exemple #5
0
/* Given an agent expression AX, fill in requirements and other descriptive
   bits.  */
void
ax_reqs (struct agent_expr *ax)
{
  int i;
  int height;

  /* Jump target table.  targets[i] is non-zero iff we have found a
     jump to offset i.  */
  char *targets = (char *) alloca (ax->len * sizeof (targets[0]));

  /* Instruction boundary table.  boundary[i] is non-zero iff our scan
     has reached an instruction starting at offset i.  */
  char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));

  /* Stack height record.  If either targets[i] or boundary[i] is
     non-zero, heights[i] is the height the stack should have before
     executing the bytecode at that point.  */
  int *heights = (int *) alloca (ax->len * sizeof (heights[0]));

  /* Pointer to a description of the present op.  */
  struct aop_map *op;

  memset (targets, 0, ax->len * sizeof (targets[0]));
  memset (boundary, 0, ax->len * sizeof (boundary[0]));

  ax->max_height = ax->min_height = height = 0;
  ax->flaw = agent_flaw_none;
  ax->max_data_size = 0;

  for (i = 0; i < ax->len; i += 1 + op->op_size)
    {
      if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
	{
	  ax->flaw = agent_flaw_bad_instruction;
	  return;
	}

      op = &aop_map[ax->buf[i]];

      if (!op->name)
	{
	  ax->flaw = agent_flaw_bad_instruction;
	  return;
	}

      if (i + 1 + op->op_size > ax->len)
	{
	  ax->flaw = agent_flaw_incomplete_instruction;
	  return;
	}

      /* If this instruction is a forward jump target, does the
         current stack height match the stack height at the jump
         source?  */
      if (targets[i] && (heights[i] != height))
	{
	  ax->flaw = agent_flaw_height_mismatch;
	  return;
	}

      boundary[i] = 1;
      heights[i] = height;

      height -= op->consumed;
      if (height < ax->min_height)
	ax->min_height = height;
      height += op->produced;
      if (height > ax->max_height)
	ax->max_height = height;

      if (op->data_size > ax->max_data_size)
	ax->max_data_size = op->data_size;

      /* For jump instructions, check that the target is a valid
         offset.  If it is, record the fact that that location is a
         jump target, and record the height we expect there.  */
      if (aop_goto == op - aop_map
	  || aop_if_goto == op - aop_map)
	{
	  int target = read_const (ax, i + 1, 2);
	  if (target < 0 || target >= ax->len)
	    {
	      ax->flaw = agent_flaw_bad_jump;
	      return;
	    }

	  /* Do we have any information about what the stack height
             should be at the target?  */
	  if (targets[target] || boundary[target])
	    {
	      if (heights[target] != height)
		{
		  ax->flaw = agent_flaw_height_mismatch;
		  return;
		}
	    }

          /* Record the target, along with the stack height we expect.  */
          targets[target] = 1;
          heights[target] = height;
	}

      /* For unconditional jumps with a successor, check that the
         successor is a target, and pick up its stack height.  */
      if (aop_goto == op - aop_map
	  && i + 3 < ax->len)
	{
	  if (!targets[i + 3])
	    {
	      ax->flaw = agent_flaw_hole;
	      return;
	    }

	  height = heights[i + 3];
	}

      /* For reg instructions, record the register in the bit mask.  */
      if (aop_reg == op - aop_map)
	{
	  int reg = read_const (ax, i + 1, 2);

	  ax_reg_mask (ax, reg);
	}
    }

  /* Check that all the targets are on boundaries.  */
  for (i = 0; i < ax->len; i++)
    if (targets[i] && !boundary[i])
      {
	ax->flaw = agent_flaw_bad_jump;
	return;
      }

  ax->final_height = height;
}
/* Given an agent expression AX, fill in an agent_reqs structure REQS
   describing it.  */
void
ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
{
  int i;
  int height;

  /* Bit vector for registers used.  */
  int reg_mask_len = 1;
  unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));

  /* Jump target table.  targets[i] is non-zero iff we have found a
     jump to offset i.  */
  char *targets = (char *) alloca (ax->len * sizeof (targets[0]));

  /* Instruction boundary table.  boundary[i] is non-zero iff our scan
     has reached an instruction starting at offset i.  */
  char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));

  /* Stack height record.  If either targets[i] or boundary[i] is
     non-zero, heights[i] is the height the stack should have before
     executing the bytecode at that point.  */
  int *heights = (int *) alloca (ax->len * sizeof (heights[0]));

  /* Pointer to a description of the present op.  */
  struct aop_map *op;

  memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
  memset (targets, 0, ax->len * sizeof (targets[0]));
  memset (boundary, 0, ax->len * sizeof (boundary[0]));

  reqs->max_height = reqs->min_height = height = 0;
  reqs->flaw = agent_flaw_none;
  reqs->max_data_size = 0;

  for (i = 0; i < ax->len; i += 1 + op->op_size)
    {
      if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
	{
	  reqs->flaw = agent_flaw_bad_instruction;
	  xfree (reg_mask);
	  return;
	}

      op = &aop_map[ax->buf[i]];

      if (!op->name)
	{
	  reqs->flaw = agent_flaw_bad_instruction;
	  xfree (reg_mask);
	  return;
	}

      if (i + 1 + op->op_size > ax->len)
	{
	  reqs->flaw = agent_flaw_incomplete_instruction;
	  xfree (reg_mask);
	  return;
	}

      /* If this instruction is a forward jump target, does the
         current stack height match the stack height at the jump
         source?  */
      if (targets[i] && (heights[i] != height))
	{
	  reqs->flaw = agent_flaw_height_mismatch;
	  xfree (reg_mask);
	  return;
	}

      boundary[i] = 1;
      heights[i] = height;

      height -= op->consumed;
      if (height < reqs->min_height)
	reqs->min_height = height;
      height += op->produced;
      if (height > reqs->max_height)
	reqs->max_height = height;

      if (op->data_size > reqs->max_data_size)
	reqs->max_data_size = op->data_size;

      /* For jump instructions, check that the target is a valid
         offset.  If it is, record the fact that that location is a
         jump target, and record the height we expect there.  */
      if (aop_goto == op - aop_map
	  || aop_if_goto == op - aop_map)
	{
	  int target = read_const (ax, i + 1, 2);
	  if (target < 0 || target >= ax->len)
	    {
	      reqs->flaw = agent_flaw_bad_jump;
	      xfree (reg_mask);
	      return;
	    }

	  /* Do we have any information about what the stack height
             should be at the target?  */
	  if (targets[target] || boundary[target])
	    {
	      if (heights[target] != height)
		{
		  reqs->flaw = agent_flaw_height_mismatch;
		  xfree (reg_mask);
		  return;
		}
	    }

          /* Record the target, along with the stack height we expect.  */
          targets[target] = 1;
          heights[target] = height;
	}

      /* For unconditional jumps with a successor, check that the
         successor is a target, and pick up its stack height.  */
      if (aop_goto == op - aop_map
	  && i + 3 < ax->len)
	{
	  if (!targets[i + 3])
	    {
	      reqs->flaw = agent_flaw_hole;
	      xfree (reg_mask);
	      return;
	    }

	  height = heights[i + 3];
	}

      /* For reg instructions, record the register in the bit mask.  */
      if (aop_reg == op - aop_map)
	{
	  int reg = read_const (ax, i + 1, 2);
	  int byte = reg / 8;

	  /* Grow the bit mask if necessary.  */
	  if (byte >= reg_mask_len)
	    {
	      /* It's not appropriate to double here.  This isn't a
	         string buffer.  */
	      int new_len = byte + 1;
	      reg_mask = xrealloc (reg_mask,
				   new_len * sizeof (reg_mask[0]));
	      memset (reg_mask + reg_mask_len, 0,
		      (new_len - reg_mask_len) * sizeof (reg_mask[0]));
	      reg_mask_len = new_len;
	    }

	  reg_mask[byte] |= 1 << (reg % 8);
	}
    }

  /* Check that all the targets are on boundaries.  */
  for (i = 0; i < ax->len; i++)
    if (targets[i] && !boundary[i])
      {
	reqs->flaw = agent_flaw_bad_jump;
	xfree (reg_mask);
	return;
      }

  reqs->final_height = height;
  reqs->reg_mask_len = reg_mask_len;
  reqs->reg_mask = reg_mask;
}
Exemple #7
0
int Linker::read_code(FILE* f, FILE* pFtarg, long init_pos, int length, 
							 aBYTE* buf)
{
  aBYTE op;
  int   x;
#ifdef BUG_LINK
  int   i;
#endif
  
  while( init_pos < length)
    {
#ifdef BUG_LINK
      fprintf(lout, "\nstart length %d init_pos %d ", length, init_pos);
#endif
      if (0 == fread(buf, CODESIZE, 1, f))
        aborteof(aS("code"));
      ucFWRITE(buf, CODESIZE, 1, pFtarg);
      init_pos += CODESIZE;
      op = *buf;
#ifdef BUG_LINK
      fprintf(lout, "\nop %d, %s: ", (int) op, lops[op]);
#endif
      switch(op)
        {    
        case Ono_op:                           // no args 
        case Ofail:
        case Oproceed:
        case Odealloc:
        case Ocut:
        case Ocut64:
        case Otrust_me_else:
        case Ou_var_getlist:
        case Ounify_nil:
          break;
          
        case Ounify_y_var:                     // Xi or Yi 
        case Ounify_y_val:
        case Ounify_unsafe:
        case Oget_nil:
        case Oget_list:
        case Oput_nil:
        case Oput_list:
        case Ounify_x_var:
        case Ounify_x_val:
          if (0 == fread(buf, 2, 1, f))
            aborteof(aS("unify x val"));
          ucFWRITE(buf, 2, 1, pFtarg);
          init_pos += 2;
          break;
          
        case Oget_y_var:                       // Xi and Yi or Xj 
        case Oget_y_val:
        case Oput_y_var:
        case Oput_y_val:
        case Oput_unsafe:
        case Oget_x_var:
        case Oget_x_val:
        case Oput_x_var:
        case Oput_x_val:
          if (0 == fread(buf, 2, 2, f))
            aborteof(aS("put x val"));
          ucFWRITE(buf, 2, 2, pFtarg);
          init_pos += 4;
          break;
          
        case Ounify_void:                      // short int 
        case Oalloc:
        case Ocutd:
        case Oretry_me_else:
        case Oretry:
        case Otrust:
        case Ogoto:
        case Otrust_me_2_else:
        case Olabel:
          if (0 == fread(buf, 2, 1, f))
            aborteof(aS("label"));
          ucFWRITE(buf, 2, 1, pFtarg);
          init_pos += 2;
#ifdef BUG_LINK
          fprintf(lout, "%d", (int) getint16(buf));
#endif
          break;
          
        case Otry_me_else:
        case Otry_me_or_else:
        case Otry:                             // 2 short ints 
          if (0 == fread(buf, 2, 2, f))
            aborteof(aS("try"));
          ucFWRITE(buf, 2, 2, pFtarg);
          init_pos += 4;
#ifdef BUG_LINK
          fprintf(lout, "%d, %d", 
                  (int) getint16(buf), (int) getint16(buf+2));
#endif
          break;
          
        case Oget_con:                         // Constant, Xi 
        case Oput_con:
          read_const(f, pFtarg, &init_pos);
          if (0 == fread(buf, 2, 1, f))
            aborteof(aS("put con"));
          ucFWRITE(buf, 2, 1, pFtarg);
          init_pos += 2;
          break;
          
        case Oexec:
        case Oescape:
        case Ocall:                          
        case Omod_call:
        case Omod_exec:
        case Oget_struc:              // functor, arity, (Xi or short or null)
        case Oput_struc:
          read_atom(f, pFtarg);                // functor 
          init_pos += 2;
          if (op == Ocall || op == Oexec || op == Omod_call || op == Omod_exec)      // new style call/exec 
            {
              //if (0 == fread(buf, 2, 1, f)) 
              //  aborteof(aS("put struc"));
              //ucFWRITE(buf, 2, 1, pFtarg);
             // shouldn't this be a read atom, not just a buf??
             read_atom(f, pFtarg);
              init_pos += 2;
            }       
          
          if (0 == fread(buf, 2, 1, f))
            aborteof(aS("put struc 2"));
          ucFWRITE(buf, 2, 1, pFtarg);
          init_pos += 2;
#ifdef BUG_LINK
          fprintf(lout, "  arity = %d", (int) getint16(buf));
#endif
                                             // now figure third (optional arg 
          if (op == Oget_struc || 
              op == Oput_struc)                // Xi 
            {
              if (0 == fread(buf, 2, 1, f))
                aborteof(aS("put struc 3"));
              ucFWRITE(buf, 2, 1, pFtarg);
              init_pos += 2;
#ifdef BUG_LINK
          fprintf(lout, "  xi(get/put_struc) = %d", (int) getint16(buf));
#endif
            }
          else if (op == Ocall || op == Omod_call)                // short 
            {
              if (0 == fread(buf, 2, 1, f))
                aborteof(aS("put struc 4"));
              ucFWRITE(buf, 2, 1, pFtarg);
              init_pos += 2;
#ifdef BUG_LINK
          fprintf(lout, "  short(call/mod_call) = %d", (int) getint16(buf));
#endif
            }
                                              // else no 3rd arg 
          break;
          
        case Ounify_con:
          read_const(f, pFtarg, &init_pos);
          break;
          
          
        case Oswitch_on_term:
          if (0 == fread(buf, 2, 3, f))        // lab1, lab2, lab3 
            aborteof(aS("switch on term"));
          init_pos += 6;
          ucFWRITE(buf, 2, 3, pFtarg);
#ifdef BUG_LINK
          for (i=0; i<3; i++) 
            fprintf(lout, " %d ",(int) getint16(buf + 2 * i));
#endif
          break;
          
        case Oswitch_on_cons:           // short size, (size x |CELL|LABEL|) 
          if (0 == fread(buf, 2, 1, f))
            aborteof(aS("switch on cons"));
          ucFWRITE(buf, 2, 1, pFtarg);
          x = getint16(buf);
          init_pos += 2;
          while(x--)
            {       
              read_const(f, pFtarg, &init_pos); // get const 
              if (0 == fread(buf, 2, 1, f))     // branch label 
                aborteof(aS("switch on cons 2"));

#ifdef BUG_LINK

              fprintf(lout, " branch[%d] ", (int) getint16(buf));
#endif
              ucFWRITE(buf, 2, 1, pFtarg);
              init_pos += 2;
            }
          break;
          
        case Oswitch_on_struc:    // short size, (size x |NAME|ARITY|LABEL|) 
          if (0 == fread(buf, 2, 1, f))
            aborteof(aS("switch on struc"));
          ucFWRITE(buf, 2, 1, pFtarg);
          x = getint16(buf);
          init_pos += 2;
          while(x--)
            {       
              read_atom(f, pFtarg);
              if (0 == fread(buf, 2, 1, f)) // arity 
                aborteof(aS("switch on struc 2"));
              ucFWRITE(buf, 2, 1, pFtarg);
              
              if (0 == fread(buf, 2, 1, f))    // label 
                aborteof(aS("switch on struc 2"));

#ifdef BUG_LINK
              fprintf(lout, " branch[%d] ", (int) getint16(buf));

#endif
              ucFWRITE(buf, 2, 1, pFtarg);
              init_pos += 2 + 2 + 2;
            }
          break;
          
        default:
          abort_linker(aS("Error: Bad opcode in CodeStream %d"), op);
        }
#ifdef BUG_LINK
      fprintf(lout, "\nend length %d init_pos %d ", length, init_pos);
#endif
    }
  return(1);
}
/* Given an agent expression AX, fill in an agent_reqs structure REQS
   describing it.  */
void
ax_reqs(struct agent_expr *ax, struct agent_reqs *reqs)
{
  long i;
  int height;

  /* Bit vector for registers used: */
  size_t reg_mask_len = 1UL;
  unsigned char *reg_mask = (unsigned char *)xmalloc(reg_mask_len * sizeof(reg_mask[0]));

  /* Jump target table.  targets[i] is non-zero iff there is a jump to
     offset i.  */
  char *targets = (char *)alloca(ax->len * sizeof(targets[0]));

  /* Instruction boundary table.  boundary[i] is non-zero iff an
     instruction starts at offset i.  */
  char *boundary = (char *)alloca(ax->len * sizeof(boundary[0]));

  /* Stack height record.  iff either targets[i] or boundary[i] is
     non-zero, heights[i] is the height the stack should have before
     executing the bytecode at that point.  */
  int *heights = (int *)alloca(ax->len * sizeof(heights[0]));

  /* Pointer to a description of the present op: */
  struct aop_map *op;

  memset(reg_mask, 0, (reg_mask_len * sizeof(reg_mask[0])));
  memset(targets, 0, (ax->len * sizeof(targets[0])));
  memset(boundary, 0, (ax->len * sizeof(boundary[0])));
  memset(heights, 0, (ax->len * sizeof(heights[0])));

  reqs->max_height = reqs->min_height = height = 0;
  reqs->flaw = agent_flaw_none;
  reqs->max_data_size = 0;

  for (i = 0; i < (long)ax->len; i += (long)(1UL + op->op_size))
    {
      if (ax->buf[i] > (sizeof(aop_map) / sizeof(aop_map[0])))
	{
	  reqs->flaw = agent_flaw_bad_instruction;
	  xfree(reg_mask);
	  return;
	}

      op = &aop_map[ax->buf[i]];

      if (!op->name)
	{
	  reqs->flaw = agent_flaw_bad_instruction;
	  xfree (reg_mask);
	  return;
	}

      if (((size_t)(i + 1L) + op->op_size) > ax->len)
	{
	  reqs->flaw = agent_flaw_incomplete_instruction;
	  xfree(reg_mask);
	  return;
	}

      /* If this instruction is a jump target, does the current stack
         height match the stack height at the jump source?  */
      if (targets[i] && (heights[i] != height))
	{
	  reqs->flaw = agent_flaw_height_mismatch;
	  xfree(reg_mask);
	  return;
	}

      boundary[i] = 1;
      heights[i] = height;

      height -= op->consumed;
      if (height < reqs->min_height)
	reqs->min_height = height;
      height += op->produced;
      if (height > reqs->max_height)
	reqs->max_height = height;

      if (op->data_size > reqs->max_data_size)
	reqs->max_data_size = op->data_size;

      /* For jump instructions, check that the target is a valid
         offset.  If it is, record the fact that that location is a
         jump target, and record the height we expect there.  */
      if ((aop_goto == (op - aop_map)) || (aop_if_goto == (op - aop_map)))
	{
	  int target = (int)read_const(ax, (int)(i + 1), 2);
	  if ((target < 0) || (target >= (int)ax->len))
	    {
	      reqs->flaw = agent_flaw_bad_jump;
	      xfree(reg_mask);
	      return;
	    }
	  /* Have we already found other jumps to the same location?  */
	  else if (targets[target])
	    {
	      if (heights[i] != height)
		{
		  reqs->flaw = agent_flaw_height_mismatch;
		  xfree(reg_mask);
		  return;
		}
	    }
	  else
	    {
	      targets[target] = 1;
	      heights[target] = height;
	    }
	}

      /* For unconditional jumps with a successor, check that the
         successor is a target, and pick up its stack height.  */
      if ((aop_goto == (op - aop_map)) && ((i + 3L) < (long)ax->len))
	{
	  if (!targets[i + 3])
	    {
	      reqs->flaw = agent_flaw_hole;
	      xfree(reg_mask);
	      return;
	    }

	  height = heights[i + 3];
	}

      /* For reg instructions, record the register in the bit mask: */
      if (aop_reg == (op - aop_map))
	{
	  int reg = (int)read_const(ax, (int)(i + 1), 2);
	  int byte = (reg / 8);

	  /* Grow the bit mask if necessary: */
	  if (byte >= (int)reg_mask_len)
	    {
	      /* It is not appropriate to double here.  This is NOT a
	         string buffer.  */
	      size_t new_len = ((size_t)byte + 1UL);
	      reg_mask = (unsigned char *)xrealloc(reg_mask,
                                                   (new_len * sizeof(reg_mask[0])));
	      memset((reg_mask + reg_mask_len), 0,
		     ((new_len - reg_mask_len) * sizeof(reg_mask[0])));
	      reg_mask_len = new_len;
	    }

	  reg_mask[byte] |= (1 << (reg % 8));
	}
    }

  /* Check that all the targets are on boundaries: */
  for (i = 0L; i < (long)ax->len; i++)
    if (targets[i] && !boundary[i])
      {
	reqs->flaw = agent_flaw_bad_jump;
	xfree(reg_mask);
	return;
      }

  reqs->final_height = height;
  reqs->reg_mask_len = reg_mask_len;
  reqs->reg_mask = reg_mask;
}