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