diff options
author | K. Richard Pixley <rich@cygnus> | 1991-03-28 16:28:29 +0000 |
---|---|---|
committer | K. Richard Pixley <rich@cygnus> | 1991-03-28 16:28:29 +0000 |
commit | dd3b648e8b12ceb7bfce66e7f179b671403aea9c (patch) | |
tree | 91119a0f4943acc9293cd8baba06943621b6e6c7 /gdb/tdesc.c | |
parent | bd5635a1e2b38ee8432fcdaa6456079191375277 (diff) | |
download | gdb-dd3b648e8b12ceb7bfce66e7f179b671403aea9c.zip gdb-dd3b648e8b12ceb7bfce66e7f179b671403aea9c.tar.gz gdb-dd3b648e8b12ceb7bfce66e7f179b671403aea9c.tar.bz2 |
Johns release
Diffstat (limited to 'gdb/tdesc.c')
-rwxr-xr-x | gdb/tdesc.c | 1650 |
1 files changed, 1650 insertions, 0 deletions
diff --git a/gdb/tdesc.c b/gdb/tdesc.c new file mode 100755 index 0000000..9a632e3 --- /dev/null +++ b/gdb/tdesc.c @@ -0,0 +1,1650 @@ +/* This file has been modified by Data General Corporation, November 1989. */ + +/* +This file provides an abstract interface to "tdesc" information. + It is designed to be used in a uniform manner by several kinds + of debuggers: + (1) code in live debugged process (e.g., a traceback routine) + (2) a separate-process debugger debugging a live process + (3) a separate-process debugger debugging a memory dump + + Dcontext model notes + * captures machine context + * partial: excludes memory + * frames + * kinds + * make one for starters, chain in reverse order to previous ones + * representation: pointer to opaque + * alloc/free protocol + + Overall model + * access functions + * handle + * error handling +*/ + + + +typedef int dc_boolean_t; /* range 0 .. 1 */ +#define DC_FALSE 0 +#define DC_TRUE 1 + + +typedef int dc_tristate_t; /* range 0 .. 2 */ +#define DC_NO 0 +#define DC_YES 1 +#define DC_MAYBE 2 + + +/* + A word is 32 bits of information. In memory, a word is word-aligned. + + A common and important use of dc_word_t is to represent values in the + target process, including (byte) addresses in the target process. + In this case, C arithmetic can be used to simulate machine address + arithmetic on the target. (Unsigned arithmetic is actually modulus + arithmetic.) +*/ +typedef unsigned int dc_word_t; + + +/* These bit operations number bits from 0 at the least significant end. */ +#define bit_test(word,bit) ((word) & (1 << (bit))) /* returns 0 or other */ +#define bit_value(word,bit) (((word) >> (bit)) & 1) /* returns 0 or 1 */ +#define bit_set(word,bit) ((word) |= (1 << (bit))) +#define bit_clear(word,bit) ((word) &= ~(1 << (bit))) +#define bit_assign(word, bit, bool) \ + if (bool) bit_set(word, bit); else bit_clear(word, bit) + + +/*----------------*/ + + +/* The exactness of locations may not be certainly known. */ +typedef dc_tristate_t dc_exactness_t; + + +/* + The model includes five kinds of contexts. Because each context + has an associated region and frame, these describe region kinds + and frame kinds as well. + [more description needed] + Currently, only call contexts exist. +*/ + +typedef int dc_kind_t; /* range 0 .. 4 */ +#define DC_CALL_KIND 0 +#define DC_SAVE_KIND 1 +#define DC_EXCEPTION_KIND 2 +#define DC_PROTECTION_KIND 3 +#define DC_SPECIAL_KIND 4 +#define DC_NUM_KINDS 5 + +#define DC_MIO_ENTRY_POINT (1<< 0) +#define DC_MIO_PROLOGUE_END (1<< 1) +#define DC_MIO_EPILOGUE_START (1<< 2) +#define DC_MIO_IMPLICIT_PROLOGUE_END (1<<16) +#define DC_MIO_LITERAL_ENTRY_POINT (1<<17) +#define DC_MIO_LITERAL_EPILOGUE_START (1<<18) + +#define DC_MII_PRECEDING_TDESC_END (1<<0) +#define DC_MII_FOLLOWING_TDESC_START (1<<1) + +typedef struct dc_debug_info { + unsigned int protocol; /* 1 for this structure */ + dc_word_t tdesc_ptr; + unsigned int text_words_count; + dc_word_t text_words_ptr; + unsigned int data_words_count; + dc_word_t data_words_ptr; +} dc_debug_info_t; + + +typedef struct tdesc_hdr { + unsigned int map_protocol; /* 1 for this structure */ + unsigned int end; /* address beyond end */ +} tdesc_hdr_t; + + +typedef struct tdesc_chunk_hdr { + int zeroes : 8; + int info_length : 22; + int info_alignment : 2; + unsigned int info_protocol; + dc_word_t start_address; + dc_word_t end_address; +} tdesc_chunk_hdr_t; + + +typedef struct tdesc_chunk_info1 { + int variant : 8; /* 1 for this structure */ + int register_save_mask : 17; + int pad1 : 1; + int return_address_info_discriminant : 1; + int frame_address_register : 5; + unsigned int frame_address_offset; + unsigned int return_address_info; + unsigned int register_save_offset; +} tdesc_chunk_info1_t; + + +typedef struct tdesc_chunk1 { + tdesc_chunk_hdr_t hdr; + tdesc_chunk_info1_t info; +} tdesc_chunk1_t; + + +typedef struct dc_mstate { + dc_word_t reg[32]; /* general registers */ + dc_word_t xip; + dc_word_t nip; + dc_word_t fip; + dc_word_t fpsr; + dc_word_t fpcr; + dc_word_t psr; +} dc_mstate_t; + + +typedef struct dc_map_info_in { + dc_word_t flags; + dc_word_t preceding_tdesc_end; + dc_word_t following_tdesc_start; +} dc_map_info_in_t; + + +typedef struct dc_map_info_out { + dc_word_t flags; + dc_word_t entry_point; + dc_word_t prologue_end; + dc_word_t epilogue_start; +} dc_map_info_out_t; + + +#if 0 + + void error_fcn (env, continuable, message) + dc_word_t env; /* environment (arbitrary datum) */ + dc_boolean_t continuable; /* whether error function may return */ + char *message; /* string (no trailing newline) */ + + /* In the future, we probably want the error_fcn to be: */ + void error_fcn (env, continuable, code, ...) + dc_word_t env; /* environment (arbitrary datum) */ + dc_boolean_t continuable; /* whether error function may return */ + int code; /* error code */ + ... /* parameters to message associated + with the code */ + + void read_fcn (env, memory, length, buffer) + dc_word_t env; /* environment (arbitrary datum) */ + dc_word_t memory; /* start address in image */ + int length; /* in bytes */ + char *buffer; /* start address of buffer */ + /* There are no alignment assumptions for the read function. */ + + void write_fcn (env, memory, length, buffer) + dc_word_t env; /* environment (arbitrary datum) */ + dc_word_t memory; /* start address in image */ + int length; /* in bytes */ + char *buffer; /* start address of buffer */ + /* There are no alignment assumptions for the write function. */ + /* The write function is optional. It must be provided if changes + to writable registers are to be made. */ + + void exec_fcn (env, mstate) + dc_word_t env; /* environment (arbitrary datum) */ + dc_mstate_t *mstate; /* machine state (read-write) */ + /* The execute function is optional. It would be used (in the future) + by the implementation of a procedurally specified tdesc mechanism. */ + +#endif + +/*----------------*/ + + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern char *malloc(); +extern char *calloc(); +extern void qsort(); + + +/* + At initialization, create a tdesc table from the tdesc info. + A tdesc table is simply a sorted array of tdesc elements. + A tdesc element is the last 6 words of the tdesc chunk. + We require that all tdesc chunks have info protocol 1. +*/ + +typedef struct tdesc_elem { + dc_word_t start_address; + dc_word_t end_address; + tdesc_chunk_info1_t info; +} tdesc_elem_t; + +typedef tdesc_elem_t *tdesc_table_t; + +void dc_correct_cr_data(); + +int dc_compare_tdesc_elems (elem1, elem2) + char *elem1, *elem2; +{ + dc_word_t s1, s2, e1, e2; + s1 = ((tdesc_elem_t *) elem1)->start_address; + s2 = ((tdesc_elem_t *) elem2)->start_address; + if (s1 < s2) return -1; + if (s1 > s2) return +1; + e1 = ((tdesc_elem_t *) elem1)->end_address; + e2 = ((tdesc_elem_t *) elem2)->end_address; + if (e1 < e2) return -1; + if (e1 > e2) return +1; + return 0; +} + + +typedef struct handle_info { + dc_word_t debug_info_ptr; + void (*error_fcn)(); + dc_word_t error_env; + void (*read_fcn)(); + dc_word_t read_env; + void (*write_fcn)(); /* NULL => absent */ + dc_word_t write_env; + void (*exec_fcn)(); /* NULL => absent */ + dc_word_t exec_env; + void (*map_fcn)(); /* NULL => absent */ + dc_word_t map_env; + tdesc_table_t tdesc_table; + int tdesc_table_size; +} handle_info_t; + +typedef handle_info_t *dc_handle_t; + + +/* + Errors detected in this module are funnelled through dc_error or dc_warn, + as appropriate. Both routines call dc_exception, which invokes the error + handler supplied by the user. + + Currently, dc_exception substitutes parameters into the message given + it and passes the resulting string to the user error handler. + In the future, dc_exception should simply pass an error code and + the parameters on to the user error handler. +*/ + +#include <varargs.h> +extern int vsprintf(); + +/* Exit status for exception-processing machinery failure */ +#define DC_EXCEPTION_FAILURE 250 + +void dc_exception(continuable, args) + dc_boolean_t continuable; + va_list args; +{ + dc_handle_t handle; + char *format; + char buffer[1024]; + + handle = va_arg(args, dc_handle_t); + format = va_arg(args, char *); + (void) vsprintf(buffer, format, args); + (*(handle->error_fcn)) (handle->error_env, continuable, buffer); + if (!continuable) + exit(DC_EXCEPTION_FAILURE); /* User error handler should never return in this case. */ +} + + +void dc_error(va_alist) /* (handle, format, args... ) */ + va_dcl +{ + va_list args; + + va_start(args); + dc_exception(DC_FALSE, args); + va_end(args); +} + + +void dc_warn(va_alist) /* (handle, format, args... ) */ + va_dcl +{ + va_list args; + + va_start(args); + dc_exception(DC_TRUE, args); + va_end(args); +} + + + +#define MALLOC_FAILURE_MESSAGE "Heap space exhausted (malloc failed)." +#define CALLOC_FAILURE_MESSAGE "Heap space exhausted (Calloc failed)." + + +/* Commonize memory allocation call so failure diagnosis is easier */ + +char* dc_malloc( handle, size ) + dc_handle_t handle; + int size; +{ + char* space = malloc( size ); + if (space == (char *)NULL) + dc_error( handle, MALLOC_FAILURE_MESSAGE ); + + return space; +} + + +/* Commonize memory allocation call so failure diagnosis is easier */ + +char* dc_calloc( handle,nelem, size ) + dc_handle_t handle; + int nelem; + int size; +{ + char* space = calloc( nelem, size ); + if (space == (char *)NULL) + dc_error( handle, CALLOC_FAILURE_MESSAGE ); + + return space; +} + + +dc_word_t dc_read_word (handle, address) + dc_handle_t handle; + dc_word_t address; +{ + dc_word_t word; + (*(handle->read_fcn)) (handle->read_env, address, + sizeof(dc_word_t), (char *)(&(word))); + return word; +} + + +void dc_write_word (handle, address, value) + dc_handle_t handle; + dc_word_t address; + dc_word_t value; +{ + dc_word_t word; + word = value; + if (handle->write_fcn) { + (*(handle->write_fcn)) (handle->write_env, address, + sizeof(dc_word_t), (char *)(&(word))); + } else { + dc_error (handle, "Writing is disabled."); + } +} + + +void dc_write_masked_word (handle, address, mask, value) + dc_handle_t handle; + dc_word_t address; + dc_word_t mask; + dc_word_t value; +{ + dc_write_word (handle, address, + (value & mask) | (dc_read_word(handle, address) & ~mask)); +} + + +dc_handle_t dc_initiate (debug_info_ptr, + error_fcn, error_env, + read_fcn, read_env, + write_fcn, write_env, + exec_fcn, exec_env, + map_fcn, map_env) + dc_word_t debug_info_ptr; + void (*error_fcn)(); + dc_word_t error_env; + void (*read_fcn)(); + dc_word_t read_env; + void (*write_fcn)(); /* NULL => absent */ + dc_word_t write_env; + void (*exec_fcn)(); /* NULL => absent */ + dc_word_t exec_env; + void (*map_fcn)(); /* NULL => absent */ + dc_word_t map_env; + /* write_fcn may be given as NULL if no writing is required. */ + /* exec_fcn may be given as NULL if no execution is required. + Currently, no execution is required. It would be if the + implementation needed to invoke procedures in the debugged process. */ +{ + dc_handle_t handle; + unsigned int debug_info_protocol; + dc_debug_info_t debug_info; + unsigned int tdesc_map_protocol; + tdesc_hdr_t tdesc_hdr; + dc_word_t tdesc_info_start; + dc_word_t tdesc_info_end; + dc_word_t tdesc_info_length; + + /* Set up handle enough for dc_error. */ + handle = (dc_handle_t) malloc(sizeof(handle_info_t)); + /* Cant use dc_malloc() as handle is being created ... */ + /* if (handle == NULL) (*error_fcn)( error_env, MALLOC_FAILURE_MESSAGE ) */ + handle->error_fcn = error_fcn; + handle->error_env = error_env; + handle->read_fcn = read_fcn; + handle->read_env = read_env; + handle->write_fcn = write_fcn; + handle->write_env = write_env; + handle->exec_fcn = exec_fcn; + handle->exec_env = exec_env; +/****************************************************************/ +/* BUG 9/19/89 Found by hls. Map functions not initialized. */ +/****************************************************************/ + handle->map_fcn = map_fcn; + handle->map_env = map_env; + handle->debug_info_ptr = debug_info_ptr; + handle->tdesc_table = (tdesc_table_t)NULL; + + /* Find tdesc info. */ + if (debug_info_ptr) { + (*read_fcn) (read_env, debug_info_ptr, sizeof(unsigned int), + (char *)(&debug_info_protocol)); + if (debug_info_protocol != 1) + dc_error (handle, "Unrecognized debug info protocol: %d", + debug_info_protocol); + (*read_fcn) (read_env, debug_info_ptr, sizeof(dc_debug_info_t), + (char *)(&debug_info)); + (*read_fcn) (read_env, debug_info.tdesc_ptr, sizeof(unsigned int), + (char *)(&tdesc_map_protocol)); + if (tdesc_map_protocol != 1) + dc_error (handle, "Unrecognized tdesc map protocol: %d", + tdesc_map_protocol); + (*read_fcn) (read_env, debug_info.tdesc_ptr, sizeof(tdesc_hdr_t), + (char *)(&tdesc_hdr)); + tdesc_info_start = debug_info.tdesc_ptr + sizeof(tdesc_hdr_t); + tdesc_info_end = tdesc_hdr.end; + tdesc_info_length = tdesc_info_end - tdesc_info_start; + + /* Create tdesc table from tdesc info. */ + { + /* Over-allocate in order to avoid second pass over tdesc info. */ + tdesc_table_t tt = (tdesc_table_t) dc_malloc(handle, tdesc_info_length); + dc_word_t p = tdesc_info_start; + dc_word_t q = tdesc_info_end - sizeof(tdesc_chunk1_t); + int n = 0; + tdesc_chunk1_t chunk; + dc_word_t start_address, end_address; + int i; + + for (; p <= q; ) { + (*read_fcn) (read_env, p, sizeof(tdesc_chunk1_t), (char *)(&chunk)); + if (chunk.hdr.zeroes != 0) { + /* Skip padding. */ + p += sizeof(dc_word_t); + continue; + } + if (chunk.hdr.info_protocol != 1) { + dc_warn (handle, "Unrecognized tdesc info protocol: %d", + chunk.hdr.info_protocol); + goto next_chunk; + } + if (chunk.hdr.info_length != 16) { + dc_warn (handle, "Incorrect tdesc info length: %d", + chunk.hdr.info_length); + goto next_chunk; + } + if (chunk.hdr.info_alignment > 2) { + dc_warn (handle, "Incorrect tdesc info alignment: %d", + chunk.hdr.info_alignment); + goto next_chunk; + } + start_address = chunk.hdr.start_address; + end_address = chunk.hdr.end_address; + if ((start_address&3)!=0) { + dc_warn (handle, + "Tdesc start address is not word-aligned: %#.8X", + start_address); + goto next_chunk; + } + if ((end_address&3)!=0) { + dc_warn (handle, + "Tdesc end address is not word-aligned: %#.8X", + end_address); + goto next_chunk; + } + if (start_address > end_address) { + /* Note that the range may be null. */ + dc_warn (handle, + "Tdesc start address (%#.8X) follows end address (%#.8X).", + start_address, end_address); + goto next_chunk; + } + if (chunk.info.variant != 1) { + dc_warn (handle, "Invalid tdesc chunk variant: %d", + chunk.info.variant); + goto next_chunk; + } + if (chunk.info.pad1 != 0) { + dc_warn (handle, "Tdesc chunk padding is not zero."); + goto next_chunk; + } + if (chunk.info.return_address_info_discriminant != 0) { + if ((chunk.info.return_address_info & 3) != 0) { + dc_warn (handle, + "Tdesc return address offset is not word-aligned: %#.8X", + chunk.info.return_address_info); + goto next_chunk; + } + } else { + if ((chunk.info.return_address_info & ~31) != 0) { + dc_warn (handle, + "Invalid tdesc return address register: %d", + chunk.info.return_address_info); + goto next_chunk; + } + } + if ((chunk.info.register_save_offset & 3) != 0) { + dc_warn (handle, + "Tdesc register save offset is not word-aligned: %#.8X", + chunk.info.register_save_offset); + goto next_chunk; + } + + tt[n].start_address = start_address; + tt[n].end_address = end_address; + tt[n].info = chunk.info; + n++; + + next_chunk: + p += sizeof(tdesc_chunk1_t); + } + /* Leftover (less than a tdesc_chunk1_t in size) is padding or + in error. Ignore it in either case. */ + + if (n != 0) { + + /* Sort table by start address. */ + qsort ((char *)tt, n, sizeof(tdesc_elem_t), dc_compare_tdesc_elems); + + /* Check for overlap among tdesc chunks. */ + for (i=0; i<(n-1); i++) { + if (tt[i].end_address > tt[i+1].start_address) + dc_error (handle, "Text chunks overlap."); + } + } + + /* Finish setting up handle. */ + handle->tdesc_table = tt; + handle->tdesc_table_size = n; + } + } else { + handle->tdesc_table_size = 0; + } + + return (dc_handle_t) handle; +} + + +void dc_terminate (handle) + dc_handle_t handle; +{ + if (((dc_handle_t)handle)->tdesc_table) { + free((char *)(((dc_handle_t)handle)->tdesc_table)); + } + free((char *)handle); +} + + + +/* + + Dcontext Model + + For each interesting register (word-sized piece of machine state), + a word of value information is kept. This word may + be either the value of the register, or the address in + subject memory where the value can be found (and changed). In + addition, the register may be invalid (in which case the value + information is undefined). These three cases are encoded for + a given register in the same-numbered bit of two words of flags: + + flags[0] bit flags[1] bit meaning + ------------ ------------ ------- + 0 0 register is invalid; info is undefined + 0 1 register is readable; info is value + 1 0 register is writable; info is address + 1 1 (reserved) + + The general registers (r0-r31) are handled by reg_info and + reg_flags. The bit number for a register is that register's number. + The other registers are grouped together for convenience and are + handled by aux_info and aux_flags. The bit numbers for these + registers are: + + bit number register + ---------- -------- + 0 location + 1 SXIP + 2 SNIP + 3 SFIP + 4 FPSR + 5 FPCR + + The SXIP, SNIP, and SFIP are the exception-time values of the + XIP, NIP, and FIP registers. They are valid only in the topmost frame. + (That is, in any context obtained from dc_previous_context, they + are invalid.) + + "location" is a pseudo-register of this model and represents the + location of the context. It is always valid. It also has an + exactness associated with it. The location and its exactness of a + context obtained from dc_previous_context are taken from the + return address and its exactness of the context given as an argument + to dc_previous_context. + + The following model is recommended for dealing with the partial + redundancy between location and the SXIP, SNIP, and SFIP values + in the topmost frame. The location should be set to either the + SNIP or SXIP value, and its exactness should be set to DC_NO. A + change to the register whose value the location is set to should + be accompanied by an identical change to the location. + + The PSR is handled separately, because it is a diverse collection + of flags. The PSR, as a whole, is always valid. A separate + psr_ind flag tells whether the psr_info data is a value or + an address. Each bit of the PSR has its own pair of flag bits to + mark validity and writability. + +*/ + + +/* The following value means "other", because state is stored in 2 bits. */ +#define DC_RESERVED 3 + + +#define RSTATE(flags, bit) \ + ((bit_value((flags)[0], bit) << 1) + bit_value((flags)[1], bit)) + +#define REG_STATE(dcontext, reg) RSTATE(dcontext->reg_flags, reg) +#define AUX_STATE(dcontext, reg) RSTATE(dcontext->aux_flags, reg) +#define PSR_STATE(dcontext, reg) RSTATE(dcontext->psr_flags, reg) + + +#define SET_INVALID(flags, bit) \ + { bit_clear ((flags)[0], bit); bit_clear ((flags)[1], bit); } + +#define SET_READABLE(flags, bit) \ + { bit_clear ((flags)[0], bit); bit_set ((flags)[1], bit); } + +#define SET_WRITABLE(flags, bit) \ + { bit_set ((flags)[0], bit); bit_clear ((flags)[1], bit); } + +#define ASSIGN_RSTATE(to_flags, to_bit, from_flags, from_bit) \ + { bit_assign ((to_flags)[0], to_bit, bit_value((from_flags)[0], from_bit));\ + bit_assign ((to_flags)[1], to_bit, bit_value((from_flags)[1], from_bit));} + + +#define CHECK_REG_READ(dcontext, reg) \ + if (REG_STATE(dcontext, reg) == DC_INVALID) \ + dc_error (dcontext->handle, \ + "General register %d is not readable.", reg) + +#define CHECK_REG_WRITE(dcontext, reg) \ + if (REG_STATE(dcontext, reg) != DC_WRITABLE) \ + dc_error (dcontext->handle, \ + "General register %d is not writable.", reg) + +#define CHECK_AUX_READ(dcontext, reg) \ + if (AUX_STATE(dcontext, reg) == DC_INVALID) \ + dc_error (dcontext->handle, \ + "Auxiliary register %d is not readable.", reg) + +#define CHECK_AUX_WRITE(dcontext, reg) \ + if (AUX_STATE(dcontext, reg) != DC_WRITABLE) \ + dc_error (dcontext->handle, \ + "Auxiliary register %d is not writable.", reg) + + + +#define DC_REG_RA 1 +#define DC_REG_FP 30 +#define DC_REG_SP 31 +#define DC_NUM_REG 32 + +#define DC_AUX_LOC 0 + /* DC_AUX_LOC must be first, with value 0 */ +#define DC_AUX_SXIP 1 +#define DC_AUX_SNIP 2 +#define DC_AUX_SFIP 3 +#define DC_AUX_FPSR 4 +#define DC_AUX_FPCR 5 +#define DC_NUM_AUX 6 + + + +#define CHECK_REG(dcontext, reg) \ + if ((reg < 0) || (reg >= DC_NUM_REG)) \ + dc_error (dcontext->handle, \ + "Bad general register number: %d", reg) + +#define CHECK_AUX(dcontext, reg) \ + if ((reg < 1) || (reg >= DC_NUM_AUX)) \ + dc_error (dcontext->handle, \ + "Bad auxiliary register number: %d", reg) + /* CHECK_AUX is not used for location pseudo-register. */ + +#define CHECK_BIT(dcontext, bit) \ + if ((bit < 0) || (bit >= 32)) \ + dc_error (dcontext->handle, \ + "Bad bit number: %d", bit) + + + +typedef struct cr_value { + int reg; + unsigned int off; + } dc_cr_value_t; + +#define DC_UNDEF 32 + +/* + A "dc_cr_value" represents an execution-time value symbolically, in + terms of the initial value of a register (the value on entry to + the procedure being analyzed) and a known offset. A value with + a 'reg' field value of 0 through 31 represents the value obtained + by summing (using 32-bit modulus arithmetic) the initial value of + register 'reg' and the value 'off'. Note that the value (0,k) + represents the constant value k, that (31,0) represents the CFA, and + that (1,0) represents the return address. A value with a 'reg' field + of DC_UNDEF represents an indeterminable value; in this case the + 'off' field is undefined. Other values of 'reg' are erroneous. +*/ + +typedef struct cr_data { + dc_cr_value_t reg_val[DC_NUM_REG]; + dc_word_t saved; + dc_word_t how; + unsigned int where[DC_NUM_REG]; +} dc_cr_data_t; + +/* + 'cr_data' collects all the information needed to represent the + symbolic machine state during code reading. + + The 'reg_val' array gives the current dc_cr_value for each register. + + The 'saved', 'how', and 'where' fields combine to describe what + registers have been saved, and where. The 'saved' and 'how' fields + are implicitly bit arrays over 0..31, where the numbering is from + 0 on the right. (Hence, 1<<r gives the mask for register r.) + If saved[r] is 0, the register is not saved, and how[r] and where[r] + are undefined. If saved[r] is 1, then how[r] tells whether register r + was saved in another register (how[r]==0) or in the frame (how[r]==1). + In the former case, where[r] gives the register number; in the latter + case, where[r] gives the frame position. +*/ + + +typedef int dc_register_state_t; /* range 0 to 2 */ + +#define DC_INVALID 0 +#define DC_READABLE 1 +#define DC_WRITABLE 2 + + + + +typedef struct dcontext_info { + dc_handle_t handle; /* environment of context */ + dc_word_t reg_info[DC_NUM_REG]; + dc_word_t reg_flags[2]; + dc_word_t aux_info[DC_NUM_AUX]; + dc_word_t aux_flags[2]; + dc_exactness_t loc_exact; + dc_word_t psr_info; /* value or address */ + dc_word_t psr_ind; /* DC_TRUE iff address */ + dc_word_t psr_flags[2]; /* per-PSR-bit flags */ + unsigned int code_reading; /* no tdesc therefore must read code*/ + union { + tdesc_elem_t *tdesc_elem_ptr; /* locates tdesc chunk */ + dc_cr_data_t *cr_data_ptr; /* or code reading data */ + } info_ptr; +} dcontext_info_t; + +typedef dcontext_info_t *dc_dcontext_t; + +dc_word_t dc_get_value (handle, info, flags, pos) + dc_handle_t handle; + dc_word_t info[]; + dc_word_t flags[2]; + int pos; + /* Assumes either DC_READABLE or DC_WRITABLE. */ +{ + if (bit_test(flags[0], pos)) { + /* DC_WRITABLE case */ + return dc_read_word(handle, info[pos]); + } else { + /* DC_READABLE case */ + return info[pos]; + } +} + +void dc_set_value (handle, info, flags, pos, value) + dc_handle_t handle; + dc_word_t info[]; + dc_word_t flags[2]; + int pos; + dc_word_t value; + /* Assumes DC_WRITABLE. */ +{ + dc_write_word(handle, info[pos], value); +} + + +#define GET_REG_VALUE(dcontext, reg) \ + dc_get_value(dcontext->handle, dcontext->reg_info, dcontext->reg_flags, reg) + +#define SET_REG_VALUE(dcontext, reg, value) \ + dc_set_value(dcontext->handle, dcontext->reg_info, dcontext->reg_flags, reg, \ + value) + +#define GET_AUX_VALUE(dcontext, reg) \ + dc_get_value(dcontext->handle, dcontext->aux_info, dcontext->aux_flags, reg) + +#define SET_AUX_VALUE(dcontext, reg, value) \ + dc_set_value(dcontext->handle, dcontext->aux_info, dcontext->aux_flags, reg, \ + value) + + + +void dc_check_dcontext (dc) + dc_dcontext_t dc; + /* Check consistency of information supplied to make a dcontext. */ +{ + int i; + + if ((REG_STATE(dc, 0) != DC_READABLE) || (dc->reg_info[0] != 0)) + dc_error (dc->handle, "Register 0 is misspecified"); + for (i = 1; i < DC_NUM_REG; i++) + if (REG_STATE(dc, i) == DC_RESERVED) + dc_error (dc->handle, + "State for general register %d is incorrect", i); + for (i = 0; i < DC_NUM_AUX; i++) + if (AUX_STATE(dc, i) == DC_RESERVED) + dc_error (dc->handle, + "State for auxiliary register %d is incorrect", i); + if (AUX_STATE(dc, DC_AUX_LOC) == DC_INVALID) + dc_error (dc->handle, "Location is specified as invalid"); + if (GET_AUX_VALUE(dc, DC_AUX_LOC) == 0) + dc_error (dc->handle, "Location is zero."); + if (dc->loc_exact >= 3) + dc_error (dc->handle, "Location exactness is incorrectly specified: %d", + dc->loc_exact); + if (dc->psr_ind >= 2) + dc_error (dc->handle, + "PSR indirection flag is incorrectly specified: %d", + dc->psr_ind); + for (i = 0; i < 32; i++) + if (PSR_STATE(dc, i) == DC_RESERVED) + dc_error (dc->handle, "State for PSR bit %d is incorrect", i); +} + + + +tdesc_elem_t * dc_tdesc_lookup (loc, tt, tt_size, map_info_in_ptr) + dc_word_t loc; + tdesc_table_t tt; + int tt_size; + dc_map_info_in_t *map_info_in_ptr; + /* Return address of tdesc_elem_t for given location, or NULL if + there is no tdesc chunk for the location. + */ +{ + int l = 0; + int h = tt_size; + int m; + + if (tt_size == 0) { + map_info_in_ptr->flags = 0; + return (tdesc_elem_t *)NULL; + } + for (;;) { + m = (l + h) / 2; + if (m == l) break; + if (loc >= tt[m].start_address) + l = m; + else + h = m; + } + if (loc >= tt[m].end_address) { + map_info_in_ptr->preceding_tdesc_end = tt[m].end_address; + if (m+1 < tt_size) { + map_info_in_ptr->following_tdesc_start = tt[m+1].start_address; + map_info_in_ptr->flags = DC_MII_PRECEDING_TDESC_END | + DC_MII_FOLLOWING_TDESC_START; + } else { + map_info_in_ptr->flags = DC_MII_PRECEDING_TDESC_END; + } + return (tdesc_elem_t *)NULL; + } else if (loc < tt[m].start_address) { + map_info_in_ptr->following_tdesc_start = tt[m].start_address; + map_info_in_ptr->flags = DC_MII_FOLLOWING_TDESC_START; + return (tdesc_elem_t *)NULL; + } else { + return (&tt[m]); + } +} + + + +dc_dcontext_t dc_make_dcontext (handle, + reg_info, reg_flags, + aux_info, aux_flags, loc_exact, + psr_info, psr_ind, psr_flags) + dc_handle_t handle; + dc_word_t reg_info[DC_NUM_REG]; + dc_word_t reg_flags[2]; + dc_word_t aux_info[DC_NUM_AUX]; + dc_word_t aux_flags[2]; + dc_exactness_t loc_exact; + dc_word_t psr_info; + dc_boolean_t psr_ind; + dc_word_t psr_flags[2]; +{ + dc_dcontext_t dc = (dc_dcontext_t) dc_malloc (handle, sizeof(dcontext_info_t)); + int i; + dc_map_info_in_t map_info_in; + + /* Fill in supplied content. */ + dc->handle = ((dc_handle_t)handle); + for (i = 0; i < DC_NUM_REG; i++) dc->reg_info[i] = reg_info[i]; + for (i = 0; i < 2; i++) dc->reg_flags[i] = reg_flags[i]; + for (i = 0; i < DC_NUM_AUX; i++) dc->aux_info[i] = aux_info[i]; + for (i = 0; i < 2; i++) dc->aux_flags[i] = aux_flags[i]; + dc->loc_exact = loc_exact; + dc->psr_info = psr_info; + dc->psr_ind = psr_ind; + for (i = 0; i < 2; i++) dc->psr_flags[i] = psr_flags[i]; + + dc_check_dcontext(dc); + + /* Find tdesc information for the text chunk. */ + { +/***************************************************************/ +/* BUG 8/16/89 Found by hls. Not zeroing EV bits of location. */ +/* SHOULD USE dc_location()! */ +/* dc_word_t loc = GET_AUX_VALUE(dc, DC_AUX_LOC); */ +/***************************************************************/ + dc_word_t loc = GET_AUX_VALUE(dc, DC_AUX_LOC) & ~3; + tdesc_elem_t *tep = + dc_tdesc_lookup(loc, ((dc_handle_t)handle)->tdesc_table, + ((dc_handle_t)handle)->tdesc_table_size,&map_info_in); + if (tep) { + dc->code_reading = 0; + dc->info_ptr.tdesc_elem_ptr = tep; + } else { + dc->code_reading = 1; + if (!dc->handle->map_fcn) { + dc_error (dc->handle, "No tdesc information for %#.8X and no map function supplied.",loc); + } +/****************************************************************/ +/* BUG 9/18/89 Found by hls. Not using dc_malloc() */ +/* dc->info_ptr.cr_data_ptr= (dc_cr_data_t *)malloc(sizeof(dc_cr_data_t )); */ +/****************************************************************/ + dc->info_ptr.cr_data_ptr= (dc_cr_data_t *)dc_calloc(dc->handle,1,sizeof(dc_cr_data_t )); + dc_read_code(loc,dc,map_info_in,dc->info_ptr.cr_data_ptr); + } + } + + return (dc_dcontext_t) dc; +} + + + +void dc_free_dcontext (dcontext) + dc_dcontext_t dcontext; +{ +/****************************************************************/ +/* BUG 9/19/89 Found by hls. Freeing non-pointer value. */ +/* free((char *)dcontext->code_reading); */ +/****************************************************************/ + if (dcontext->code_reading) + free((char *)dcontext->info_ptr.cr_data_ptr); + free((char *)dcontext); +} + + + +dc_register_state_t dc_location_state (dcontext) + dc_dcontext_t dcontext; +{ + return AUX_STATE(((dc_dcontext_t)dcontext), DC_AUX_LOC); +} + + +dc_exactness_t dc_location_exactness (dcontext) + dc_dcontext_t dcontext; +{ + return ((dc_dcontext_t)dcontext)->loc_exact; +} + + +dc_word_t dc_location (dcontext) + dc_dcontext_t dcontext; + /* Return high 30 bits only. */ +{ + /* Don't need: CHECK_AUX_READ (((dc_dcontext_t)dcontext), DC_AUX_LOC); */ + return GET_AUX_VALUE (((dc_dcontext_t)dcontext), DC_AUX_LOC) & ~3; +} + + +dc_boolean_t dc_location_in_text_chunk( dcontext, value ) + dc_dcontext_t dcontext; + dc_word_t value; +{ + /* Check that new location is still within same text chunk. */ + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; +/********************************************************************/ +/* Bug in predicate -- LS adjusted according to OCS documentation.. */ +/* if ((value < tep->start_address) || (value >= tep->end_address))*/ +/********************************************************************/ + if ((value >= tep->start_address) && (value < tep->end_address)) + return DC_TRUE; + else + return DC_FALSE; + +} + + +void dc_set_location (dcontext, value) + dc_dcontext_t dcontext; + dc_word_t value; + /* Set high 30 bits only. */ +{ + if (dc_location_in_text_chunk( dcontext, value ) != DC_TRUE) + dc_warn (((dc_dcontext_t)dcontext)->handle, + "New location is not in same text chunk."); + + CHECK_AUX_WRITE (((dc_dcontext_t)dcontext), DC_AUX_LOC); + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + ((dc_dcontext_t)dcontext)->aux_info[DC_AUX_LOC], ~3, value); +} + + + +dc_register_state_t dc_general_register_state (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_REG (((dc_dcontext_t)dcontext), reg); + return REG_STATE(((dc_dcontext_t)dcontext), reg); +} + + +dc_word_t dc_general_register (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_REG (((dc_dcontext_t)dcontext), reg); + CHECK_REG_READ (((dc_dcontext_t)dcontext), reg); + return GET_REG_VALUE(((dc_dcontext_t)dcontext), reg); +} + + +void dc_set_general_register (dcontext, reg, value) + dc_dcontext_t dcontext; + int reg; + dc_word_t value; +{ + CHECK_REG (((dc_dcontext_t)dcontext), reg); + CHECK_REG_WRITE (((dc_dcontext_t)dcontext), reg); + SET_REG_VALUE (((dc_dcontext_t)dcontext), reg, value); +} + + + +dc_register_state_t dc_auxiliary_register_state (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_AUX (((dc_dcontext_t)dcontext), reg); + return AUX_STATE(((dc_dcontext_t)dcontext), reg); +} + + +dc_word_t dc_auxiliary_register (dcontext, reg) + dc_dcontext_t dcontext; + int reg; +{ + CHECK_AUX (((dc_dcontext_t)dcontext), reg); + CHECK_AUX_READ (((dc_dcontext_t)dcontext), reg); + return GET_AUX_VALUE(((dc_dcontext_t)dcontext), reg); +} + + +void dc_set_auxiliary_register (dcontext, reg, value) + dc_dcontext_t dcontext; + int reg; + dc_word_t value; +{ + CHECK_AUX (((dc_dcontext_t)dcontext), reg); + CHECK_AUX_WRITE (((dc_dcontext_t)dcontext), reg); + SET_AUX_VALUE (((dc_dcontext_t)dcontext), reg, value); +} + + + +dc_register_state_t dc_psr_register_bit_state (dcontext, bit) + dc_dcontext_t dcontext; + int bit; +{ + CHECK_BIT (((dc_dcontext_t)dcontext), bit); + return PSR_STATE(((dc_dcontext_t)dcontext), bit); +} + + +dc_word_t dc_psr_register (dcontext) + dc_dcontext_t dcontext; +{ + if (((dc_dcontext_t)dcontext)->psr_ind) { + return dc_read_word(((dc_dcontext_t)dcontext)->handle, + ((dc_dcontext_t)dcontext)->psr_info); + } else { + return ((dc_dcontext_t)dcontext)->psr_info; + } +} + + +void dc_set_psr_register (dcontext, mask, value) + dc_dcontext_t dcontext; + dc_word_t mask; + dc_word_t value; + /* Set bits of PSR corresponding to 1 bits in mask. */ +{ + if (((dc_dcontext_t)dcontext)->psr_ind) { + if (((((dc_dcontext_t)dcontext)->psr_flags[0] & mask) != mask) || + ((((dc_dcontext_t)dcontext)->psr_flags[1] & mask) != 0)) + dc_error (((dc_dcontext_t)dcontext)->handle, + "Some PSR bits specified are not writable."); + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + ((dc_dcontext_t)dcontext)->psr_info, mask, value); + } else { + dc_error (((dc_dcontext_t)dcontext)->handle, "PSR is not writable."); + } +} + + + +dc_word_t dc_frame_address (dcontext) + dc_dcontext_t dcontext; +{ + if (!dcontext->code_reading) { + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + return dc_general_register(dcontext, + tep->info.frame_address_register) + tep->info.frame_address_offset; + } else { + if (dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_FP].reg == DC_REG_SP) { + return (dc_general_register(dcontext,DC_REG_FP) + - dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_FP].off); + } + if (dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_SP].reg == DC_REG_SP) { + return (dc_general_register(dcontext,DC_REG_SP) + - dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_SP].off); + } + dc_error (((dc_dcontext_t)dcontext)->handle, "Cannot locate frame pointer."); + } +} + + + +dc_kind_t dc_context_kind (dcontext) + dc_dcontext_t dcontext; +{ + return DC_CALL_KIND; +} + + + + +/* operations valid for call contexts only */ + + +dc_register_state_t dc_return_address_state (dcontext) + dc_dcontext_t dcontext; +{ + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + int reg; + + if (!dcontext->code_reading) { + if (tep->info.return_address_info_discriminant) { + return DC_WRITABLE; + } else { + return REG_STATE(((dc_dcontext_t)dcontext), tep->info.return_address_info); + } + } else { + reg= DC_REG_RA; + if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,DC_REG_RA)) { + if (bit_test(dcontext->info_ptr.cr_data_ptr->how,DC_REG_RA)) { + return DC_WRITABLE; + } else { + reg= dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]; + } + } + return REG_STATE(((dc_dcontext_t)dcontext),reg); + + + } +} + + +dc_exactness_t dc_return_address_exactness (dcontext) + dc_dcontext_t dcontext; +{ + return DC_MAYBE; +} + + +dc_word_t dc_return_address (dcontext) + dc_dcontext_t dcontext; + /* Return high 30 bits only. */ +{ + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + dc_word_t rai = tep->info.return_address_info; + dc_word_t val; + int reg; + + if (!dcontext->code_reading) { + if (tep->info.return_address_info_discriminant) { + val = dc_read_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + rai); + } else { + val = dc_general_register (dcontext, rai); + } + } else { + reg=DC_REG_RA; + if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,reg)) { + if (bit_test(dcontext->info_ptr.cr_data_ptr->how,reg)) { + val = dc_read_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + + (dcontext->info_ptr.cr_data_ptr->where[reg])); + } else { + reg= dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]; + val = dc_general_register (dcontext, reg); + } + } else { + val = dc_general_register (dcontext, reg); + } + } + return val & ~3; +} + + +void dc_set_return_address (dcontext, value) + dc_dcontext_t dcontext; + dc_word_t value; + /* Set high 30 bits only. */ +{ + if (!dcontext->code_reading) { + tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; + dc_word_t rai = tep->info.return_address_info; + + if (tep->info.return_address_info_discriminant) { + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + rai, ~3, value); + } else { + dc_set_general_register (dcontext, rai, + (value & ~3) | (dc_general_register(dcontext, rai) & 3)); + } + } else { + if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,DC_REG_RA)) { + if (bit_test(dcontext->info_ptr.cr_data_ptr->how,DC_REG_RA)) { + dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, + dc_frame_address(dcontext) + + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA], ~3, value); + } else { + dc_set_general_register( dcontext, + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]); + } + } else { + dc_set_general_register( dcontext, + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]); + } + } +} + + + +/* operations valid for save contexts only */ + +/* (none) */ + + + +/* operations valid for exception contexts only */ + + +void dc_get_exception_info (dcontext, handler, datum) + dc_dcontext_t dcontext; + dc_word_t *handler; + dc_word_t *datum; +{ + dc_error (((dc_dcontext_t)dcontext)->handle, + "dc_get_exception_info is not yet implemented."); +} + + + +/* operations valid for protection contexts only */ + + +void dc_get_protection_info (dcontext, handler, datum) + dc_dcontext_t dcontext; + dc_word_t *handler; + dc_word_t *datum; +{ + dc_error (((dc_dcontext_t)dcontext)->handle, + "dc_get_protection_info is not yet implemented."); +} + + + +/* operations valid for special contexts only */ + + +void dc_get_special_info (dcontext, kind, datum) + dc_dcontext_t dcontext; + dc_word_t *kind; + dc_word_t *datum; +{ + dc_error (((dc_dcontext_t)dcontext)->handle, + "dc_get_special_info is not yet implemented."); +} + + + +/* operations valid for all contexts (again) */ + + +dc_dcontext_t dc_previous_dcontext (dcontext) + dc_dcontext_t dcontext; + /* Return NULL if there is no previous context. */ +{ + dc_dcontext_t old = (dc_dcontext_t) dcontext; + dcontext_info_t new; /* to serve as temporary storage only */ + tdesc_elem_t *tep; + dc_cr_data_t *cdp; + dc_word_t cfa; + int rsm; + dc_word_t offset; + dc_word_t rai; + int r; + + if (dc_return_address_state((dc_dcontext_t)old) == DC_INVALID) + dc_error (old->handle, "Return address is invalid."); + + if (dc_return_address((dc_dcontext_t)old) == 0) + return (dc_dcontext_t)NULL; /* end of the chain */ + + /* Copy over old contents. */ + new = *old; + + cfa = dc_frame_address(old); + /* Restore stack pointer. */ + new.reg_info[DC_REG_SP] = cfa; + SET_READABLE (new.reg_flags, DC_REG_SP); + + /* Invalidate temporary registers. */ + for (r = 1; r <= 13; r++) SET_INVALID (new.reg_flags, r); + + if (!old->code_reading) { + tep = old->info_ptr.tdesc_elem_ptr; + /* Restore preserved registers. */ + rsm = tep->info.register_save_mask; + offset = cfa + tep->info.register_save_offset; + for (r = 14; r <= 30; r++) { + if (bit_test(rsm, 30-r)) { + new.reg_info[r] = offset; + SET_WRITABLE (new.reg_flags, r); + offset += sizeof(dc_word_t); + } + } + + /* Set location from old return address. */ + rai = tep->info.return_address_info; + if (tep->info.return_address_info_discriminant) { + new.aux_info[DC_AUX_LOC] = cfa + rai; + SET_WRITABLE (new.aux_flags, DC_AUX_LOC); + } else { + new.aux_info[DC_AUX_LOC] = old->reg_info[rai]; + ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, old->reg_flags, rai); + } + } else { + cdp = old->info_ptr.cr_data_ptr; + + /* Restore preserved registers. */ + for (r = 14; r <= 30; r++) { + if (bit_test(cdp->saved,r)) { + if (bit_test(cdp->how,r)){ /* saved in the frame */ + new.reg_info[r] = cfa+cdp->where[r]; + SET_WRITABLE (new.reg_flags, r); + } else { /* saved in the in a register */ + new.reg_info[r] = dc_general_register(old,cdp->where[r]); + ASSIGN_RSTATE (new.aux_flags, r, old->reg_flags, cdp->where[r]); + } + } /* not saved, therefore, already valid , no else*/ + } + + /* Set location from old return address. */ + if (bit_test(cdp->saved,DC_REG_RA)) { + if (bit_test(cdp->how,DC_REG_RA)){ /* saved in the frame */ + new.aux_info[DC_AUX_LOC] = + new.reg_info[DC_REG_RA] = cfa+cdp->where[DC_REG_RA]; + SET_WRITABLE (new.reg_flags, DC_REG_RA); + SET_WRITABLE (new.aux_flags, DC_AUX_LOC); + } else { /* saved in the in a register */ + new.reg_info[DC_REG_RA] = + new.aux_info[DC_AUX_LOC] = + dc_general_register(old,cdp->where[DC_REG_RA]); + ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, + old->reg_flags, cdp->where[DC_REG_RA]); + } + } else { /* not saved, therefore, already valid , set DC_AUX_LOC only*/ + new.aux_info[DC_AUX_LOC] = + dc_general_register(old,DC_REG_RA); + ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, + old->reg_flags, DC_REG_RA); + } + } + + /* Invalidate instruction pointers. */ + SET_INVALID (new.aux_flags, DC_AUX_SXIP); + SET_INVALID (new.aux_flags, DC_AUX_SNIP); + SET_INVALID (new.aux_flags, DC_AUX_SFIP); + + /* No change to FCR registers. */ + + /* No change to PSR register. */ + + return dc_make_dcontext ((dc_handle_t)new.handle, + new.reg_info, new.reg_flags, + new.aux_info, new.aux_flags, new.loc_exact, + new.psr_info, new.psr_ind, new.psr_flags); +} + + + +/* extensions for nonlocal goto */ + +#if 0 + +typedef + struct label { + ??? + } label_t; + + +label_t dc_make_label (dcontext, location) + dc_dcontext_t dcontext; + dc_word_t location; +{ +} + +#endif + +/* procedure for reading code */ + +dc_read_code(loc,dc,map_info_in,cdp) +dc_word_t loc; +dc_dcontext_t dc; +dc_cr_data_t *cdp; +dc_map_info_in_t map_info_in; +{ +dc_map_info_out_t map_info_out; +dc_word_t pc; +dc_boolean_t found_branch=DC_FALSE; +dc_word_t instr; + + (*dc->handle->map_fcn)(dc->handle->map_env,loc,map_info_in,&map_info_out); + if (map_info_out.flags & DC_MIO_ENTRY_POINT + && (!(map_info_in.flags & DC_MII_PRECEDING_TDESC_END) + || map_info_out.entry_point >= map_info_in.preceding_tdesc_end + || map_info_out.flags & DC_MIO_LITERAL_ENTRY_POINT)) { + dc_init_cr_data(cdp,(tdesc_elem_t *)NULL); + pc= map_info_out.entry_point; + } else if (map_info_in.flags & DC_MII_PRECEDING_TDESC_END) { + /**/ + /* tdesc_lookup gets the tep for the preceeding tdesc information + /* so we call it with one less than the preceding tdesc end since + /* tdesc information is exclusive of the ending address + /**/ + dc_init_cr_data(cdp, + dc_tdesc_lookup(map_info_in.preceding_tdesc_end-1, + ((dc_handle_t)dc->handle)->tdesc_table, + ((dc_handle_t)dc->handle)->tdesc_table_size, + &map_info_in)); + pc= map_info_in.preceding_tdesc_end; + } else { + dc_error (dc->handle, "Insufficient information for code reading."); + } + for (;;pc+=4) { + if (pc==loc) { + return (DC_TRUE); + } + instr= dc_read_word(dc->handle,pc); + found_branch= dc_decode_finds_branch(dc,instr); + if ((map_info_out.flags & DC_MIO_PROLOGUE_END) + && (pc==map_info_out.prologue_end)) { + break; + } + if (found_branch) { + if (DC_MIO_IMPLICIT_PROLOGUE_END & map_info_out.flags) { + break; + } else { + dc_error (dc->handle, "Found branch before end of prologue."); + } + } + } + if (!(map_info_out.flags & DC_MIO_LITERAL_EPILOGUE_START) + && (map_info_out.epilogue_start >= loc + || !(map_info_out.flags & DC_MIO_EPILOGUE_START))) { + return (DC_TRUE); + } + dc_correct_cr_data(cdp,dc->handle); + for (pc=map_info_out.epilogue_start;pc<loc;pc+=4) { + instr= dc_read_word(dc->handle,pc); + if (dc_decode_finds_branch(dc,instr)) { + return (DC_FALSE); + } + } + return (DC_TRUE); + +} + + + +dc_init_cr_data(cdp,tep) +dc_cr_data_t *cdp; +tdesc_elem_t *tep; +{ +int reg; +dc_word_t rai; +dc_word_t raid; +dc_word_t rsm; +dc_word_t frpos; + + if (tep){ + + /* Start off with all registers undefined and none saved. */ + for (reg = 0; reg < DC_NUM_REG; reg++) { + cdp->reg_val[reg].reg = DC_UNDEF; + } + cdp->saved = 0; + + /* Overwrite with what tdesc element says. */ + + cdp->reg_val[tep->info.frame_address_register].reg = DC_REG_SP; + cdp->reg_val[tep->info.frame_address_register].off = + - tep->info.frame_address_offset; + + rai = tep->info.return_address_info; + raid = tep->info.return_address_info_discriminant; + if (raid || rai != DC_REG_RA) { + bit_set(cdp->saved,DC_REG_RA); + bit_assign(cdp->how,DC_REG_RA,raid); + cdp->where[DC_REG_RA] = rai; + } + + rsm = tep->info.register_save_mask; + frpos = tep->info.register_save_offset; + for (reg = 14; reg <= 30; reg++) { + if (bit_test(rsm, 30-reg)) { + bit_set(cdp->saved,reg); + bit_set(cdp->how,reg); + cdp->where[reg] = frpos; + frpos += sizeof(dc_word_t); + } else { + cdp->reg_val[reg].reg = reg; + cdp->reg_val[reg].off = 0; + } + } + + cdp->reg_val[0].reg = 0; /* guarantee what hardware does */ + cdp->reg_val[0].off = 0; + + } else { + /* Each register has its own initial value. */ + for (reg = 0; reg < DC_NUM_REG; reg++) { + cdp->reg_val[reg].reg = reg; + cdp->reg_val[reg].off = 0; + } + /* No register is yet saved. */ + cdp->saved = 0; + cdp->how = 0; + } +} +void dc_correct_cr_data(cdp,handle) +dc_cr_data_t *cdp; +dc_handle_t handle; +{ +long sr,r; +dc_word_t save_regs = 0; /* registers used to save others */ + for (r = 1; r < DC_REG_SP; r++) { + if (bit_test(cdp->saved,r) && !bit_test(cdp->how,r)) { + sr = cdp->where[r]; + if (bit_test(save_regs,sr)) { + dc_error(handle, "Same register used to save two others."); + } + bit_set(save_regs,sr); + } + } + for (r = 1; r < DC_REG_FP; r++) { + if ((r < 14 || bit_test(cdp->saved,r)) && !bit_test(save_regs,r)) { + cdp->reg_val[r].reg = DC_UNDEF; + } + } + if (bit_test(cdp->saved,DC_REG_FP) && + cdp->reg_val[DC_REG_FP].reg == DC_REG_SP) { /* is r30 the far? */ + cdp->reg_val[DC_REG_SP].reg = DC_UNDEF; /* trash sp */ + } else if (cdp->reg_val[DC_REG_SP].reg == DC_REG_SP) { /* is r31 the far? */ + if (bit_test(cdp->saved,DC_REG_FP) && !bit_test(save_regs,DC_REG_FP)) { + cdp->reg_val[DC_REG_FP].reg = DC_UNDEF; /* trash r30 */ + } + } +} |