aboutsummaryrefslogtreecommitdiff
path: root/gdb/tdesc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/tdesc.c')
-rwxr-xr-xgdb/tdesc.c1650
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 */
+ }
+ }
+}