Commit | Line | Data |
---|---|---|
dd3b648e RP |
1 | /* This file has been modified by Data General Corporation, November 1989. */ |
2 | ||
3 | /* | |
4 | This file provides an abstract interface to "tdesc" information. | |
5 | It is designed to be used in a uniform manner by several kinds | |
6 | of debuggers: | |
7 | (1) code in live debugged process (e.g., a traceback routine) | |
8 | (2) a separate-process debugger debugging a live process | |
9 | (3) a separate-process debugger debugging a memory dump | |
10 | ||
11 | Dcontext model notes | |
12 | * captures machine context | |
13 | * partial: excludes memory | |
14 | * frames | |
15 | * kinds | |
16 | * make one for starters, chain in reverse order to previous ones | |
17 | * representation: pointer to opaque | |
18 | * alloc/free protocol | |
19 | ||
20 | Overall model | |
21 | * access functions | |
22 | * handle | |
23 | * error handling | |
24 | */ | |
25 | ||
26 | ||
27 | ||
28 | typedef int dc_boolean_t; /* range 0 .. 1 */ | |
29 | #define DC_FALSE 0 | |
30 | #define DC_TRUE 1 | |
31 | ||
32 | ||
33 | typedef int dc_tristate_t; /* range 0 .. 2 */ | |
34 | #define DC_NO 0 | |
35 | #define DC_YES 1 | |
36 | #define DC_MAYBE 2 | |
37 | ||
38 | ||
39 | /* | |
40 | A word is 32 bits of information. In memory, a word is word-aligned. | |
41 | ||
42 | A common and important use of dc_word_t is to represent values in the | |
43 | target process, including (byte) addresses in the target process. | |
44 | In this case, C arithmetic can be used to simulate machine address | |
45 | arithmetic on the target. (Unsigned arithmetic is actually modulus | |
46 | arithmetic.) | |
47 | */ | |
48 | typedef unsigned int dc_word_t; | |
49 | ||
50 | ||
51 | /* These bit operations number bits from 0 at the least significant end. */ | |
52 | #define bit_test(word,bit) ((word) & (1 << (bit))) /* returns 0 or other */ | |
53 | #define bit_value(word,bit) (((word) >> (bit)) & 1) /* returns 0 or 1 */ | |
54 | #define bit_set(word,bit) ((word) |= (1 << (bit))) | |
55 | #define bit_clear(word,bit) ((word) &= ~(1 << (bit))) | |
56 | #define bit_assign(word, bit, bool) \ | |
57 | if (bool) bit_set(word, bit); else bit_clear(word, bit) | |
58 | ||
59 | ||
60 | /*----------------*/ | |
61 | ||
62 | ||
63 | /* The exactness of locations may not be certainly known. */ | |
64 | typedef dc_tristate_t dc_exactness_t; | |
65 | ||
66 | ||
67 | /* | |
68 | The model includes five kinds of contexts. Because each context | |
69 | has an associated region and frame, these describe region kinds | |
70 | and frame kinds as well. | |
71 | [more description needed] | |
72 | Currently, only call contexts exist. | |
73 | */ | |
74 | ||
75 | typedef int dc_kind_t; /* range 0 .. 4 */ | |
76 | #define DC_CALL_KIND 0 | |
77 | #define DC_SAVE_KIND 1 | |
78 | #define DC_EXCEPTION_KIND 2 | |
79 | #define DC_PROTECTION_KIND 3 | |
80 | #define DC_SPECIAL_KIND 4 | |
81 | #define DC_NUM_KINDS 5 | |
82 | ||
83 | #define DC_MIO_ENTRY_POINT (1<< 0) | |
84 | #define DC_MIO_PROLOGUE_END (1<< 1) | |
85 | #define DC_MIO_EPILOGUE_START (1<< 2) | |
86 | #define DC_MIO_IMPLICIT_PROLOGUE_END (1<<16) | |
87 | #define DC_MIO_LITERAL_ENTRY_POINT (1<<17) | |
88 | #define DC_MIO_LITERAL_EPILOGUE_START (1<<18) | |
89 | ||
90 | #define DC_MII_PRECEDING_TDESC_END (1<<0) | |
91 | #define DC_MII_FOLLOWING_TDESC_START (1<<1) | |
92 | ||
93 | typedef struct dc_debug_info { | |
94 | unsigned int protocol; /* 1 for this structure */ | |
95 | dc_word_t tdesc_ptr; | |
96 | unsigned int text_words_count; | |
97 | dc_word_t text_words_ptr; | |
98 | unsigned int data_words_count; | |
99 | dc_word_t data_words_ptr; | |
100 | } dc_debug_info_t; | |
101 | ||
102 | ||
103 | typedef struct tdesc_hdr { | |
104 | unsigned int map_protocol; /* 1 for this structure */ | |
105 | unsigned int end; /* address beyond end */ | |
106 | } tdesc_hdr_t; | |
107 | ||
108 | ||
109 | typedef struct tdesc_chunk_hdr { | |
110 | int zeroes : 8; | |
111 | int info_length : 22; | |
112 | int info_alignment : 2; | |
113 | unsigned int info_protocol; | |
114 | dc_word_t start_address; | |
115 | dc_word_t end_address; | |
116 | } tdesc_chunk_hdr_t; | |
117 | ||
118 | ||
119 | typedef struct tdesc_chunk_info1 { | |
120 | int variant : 8; /* 1 for this structure */ | |
121 | int register_save_mask : 17; | |
122 | int pad1 : 1; | |
123 | int return_address_info_discriminant : 1; | |
124 | int frame_address_register : 5; | |
125 | unsigned int frame_address_offset; | |
126 | unsigned int return_address_info; | |
127 | unsigned int register_save_offset; | |
128 | } tdesc_chunk_info1_t; | |
129 | ||
130 | ||
131 | typedef struct tdesc_chunk1 { | |
132 | tdesc_chunk_hdr_t hdr; | |
133 | tdesc_chunk_info1_t info; | |
134 | } tdesc_chunk1_t; | |
135 | ||
136 | ||
137 | typedef struct dc_mstate { | |
138 | dc_word_t reg[32]; /* general registers */ | |
139 | dc_word_t xip; | |
140 | dc_word_t nip; | |
141 | dc_word_t fip; | |
142 | dc_word_t fpsr; | |
143 | dc_word_t fpcr; | |
144 | dc_word_t psr; | |
145 | } dc_mstate_t; | |
146 | ||
147 | ||
148 | typedef struct dc_map_info_in { | |
149 | dc_word_t flags; | |
150 | dc_word_t preceding_tdesc_end; | |
151 | dc_word_t following_tdesc_start; | |
152 | } dc_map_info_in_t; | |
153 | ||
154 | ||
155 | typedef struct dc_map_info_out { | |
156 | dc_word_t flags; | |
157 | dc_word_t entry_point; | |
158 | dc_word_t prologue_end; | |
159 | dc_word_t epilogue_start; | |
160 | } dc_map_info_out_t; | |
161 | ||
162 | ||
163 | #if 0 | |
164 | ||
165 | void error_fcn (env, continuable, message) | |
166 | dc_word_t env; /* environment (arbitrary datum) */ | |
167 | dc_boolean_t continuable; /* whether error function may return */ | |
168 | char *message; /* string (no trailing newline) */ | |
169 | ||
170 | /* In the future, we probably want the error_fcn to be: */ | |
171 | void error_fcn (env, continuable, code, ...) | |
172 | dc_word_t env; /* environment (arbitrary datum) */ | |
173 | dc_boolean_t continuable; /* whether error function may return */ | |
174 | int code; /* error code */ | |
175 | ... /* parameters to message associated | |
176 | with the code */ | |
177 | ||
178 | void read_fcn (env, memory, length, buffer) | |
179 | dc_word_t env; /* environment (arbitrary datum) */ | |
180 | dc_word_t memory; /* start address in image */ | |
181 | int length; /* in bytes */ | |
182 | char *buffer; /* start address of buffer */ | |
183 | /* There are no alignment assumptions for the read function. */ | |
184 | ||
185 | void write_fcn (env, memory, length, buffer) | |
186 | dc_word_t env; /* environment (arbitrary datum) */ | |
187 | dc_word_t memory; /* start address in image */ | |
188 | int length; /* in bytes */ | |
189 | char *buffer; /* start address of buffer */ | |
190 | /* There are no alignment assumptions for the write function. */ | |
191 | /* The write function is optional. It must be provided if changes | |
192 | to writable registers are to be made. */ | |
193 | ||
194 | void exec_fcn (env, mstate) | |
195 | dc_word_t env; /* environment (arbitrary datum) */ | |
196 | dc_mstate_t *mstate; /* machine state (read-write) */ | |
197 | /* The execute function is optional. It would be used (in the future) | |
198 | by the implementation of a procedurally specified tdesc mechanism. */ | |
199 | ||
200 | #endif | |
201 | ||
202 | /*----------------*/ | |
203 | ||
204 | ||
205 | #ifndef NULL | |
206 | #define NULL ((void *) 0) | |
207 | #endif | |
208 | ||
209 | extern char *malloc(); | |
210 | extern char *calloc(); | |
211 | extern void qsort(); | |
212 | ||
213 | ||
214 | /* | |
215 | At initialization, create a tdesc table from the tdesc info. | |
216 | A tdesc table is simply a sorted array of tdesc elements. | |
217 | A tdesc element is the last 6 words of the tdesc chunk. | |
218 | We require that all tdesc chunks have info protocol 1. | |
219 | */ | |
220 | ||
221 | typedef struct tdesc_elem { | |
222 | dc_word_t start_address; | |
223 | dc_word_t end_address; | |
224 | tdesc_chunk_info1_t info; | |
225 | } tdesc_elem_t; | |
226 | ||
227 | typedef tdesc_elem_t *tdesc_table_t; | |
228 | ||
229 | void dc_correct_cr_data(); | |
230 | ||
231 | int dc_compare_tdesc_elems (elem1, elem2) | |
232 | char *elem1, *elem2; | |
233 | { | |
234 | dc_word_t s1, s2, e1, e2; | |
235 | s1 = ((tdesc_elem_t *) elem1)->start_address; | |
236 | s2 = ((tdesc_elem_t *) elem2)->start_address; | |
237 | if (s1 < s2) return -1; | |
238 | if (s1 > s2) return +1; | |
239 | e1 = ((tdesc_elem_t *) elem1)->end_address; | |
240 | e2 = ((tdesc_elem_t *) elem2)->end_address; | |
241 | if (e1 < e2) return -1; | |
242 | if (e1 > e2) return +1; | |
243 | return 0; | |
244 | } | |
245 | ||
246 | ||
247 | typedef struct handle_info { | |
248 | dc_word_t debug_info_ptr; | |
249 | void (*error_fcn)(); | |
250 | dc_word_t error_env; | |
251 | void (*read_fcn)(); | |
252 | dc_word_t read_env; | |
253 | void (*write_fcn)(); /* NULL => absent */ | |
254 | dc_word_t write_env; | |
255 | void (*exec_fcn)(); /* NULL => absent */ | |
256 | dc_word_t exec_env; | |
257 | void (*map_fcn)(); /* NULL => absent */ | |
258 | dc_word_t map_env; | |
259 | tdesc_table_t tdesc_table; | |
260 | int tdesc_table_size; | |
261 | } handle_info_t; | |
262 | ||
263 | typedef handle_info_t *dc_handle_t; | |
264 | ||
265 | ||
266 | /* | |
267 | Errors detected in this module are funnelled through dc_error or dc_warn, | |
268 | as appropriate. Both routines call dc_exception, which invokes the error | |
269 | handler supplied by the user. | |
270 | ||
271 | Currently, dc_exception substitutes parameters into the message given | |
272 | it and passes the resulting string to the user error handler. | |
273 | In the future, dc_exception should simply pass an error code and | |
274 | the parameters on to the user error handler. | |
275 | */ | |
276 | ||
277 | #include <varargs.h> | |
278 | extern int vsprintf(); | |
279 | ||
280 | /* Exit status for exception-processing machinery failure */ | |
281 | #define DC_EXCEPTION_FAILURE 250 | |
282 | ||
283 | void dc_exception(continuable, args) | |
284 | dc_boolean_t continuable; | |
285 | va_list args; | |
286 | { | |
287 | dc_handle_t handle; | |
288 | char *format; | |
289 | char buffer[1024]; | |
290 | ||
291 | handle = va_arg(args, dc_handle_t); | |
292 | format = va_arg(args, char *); | |
293 | (void) vsprintf(buffer, format, args); | |
294 | (*(handle->error_fcn)) (handle->error_env, continuable, buffer); | |
295 | if (!continuable) | |
296 | exit(DC_EXCEPTION_FAILURE); /* User error handler should never return in this case. */ | |
297 | } | |
298 | ||
299 | ||
300 | void dc_error(va_alist) /* (handle, format, args... ) */ | |
301 | va_dcl | |
302 | { | |
303 | va_list args; | |
304 | ||
305 | va_start(args); | |
306 | dc_exception(DC_FALSE, args); | |
307 | va_end(args); | |
308 | } | |
309 | ||
310 | ||
311 | void dc_warn(va_alist) /* (handle, format, args... ) */ | |
312 | va_dcl | |
313 | { | |
314 | va_list args; | |
315 | ||
316 | va_start(args); | |
317 | dc_exception(DC_TRUE, args); | |
318 | va_end(args); | |
319 | } | |
320 | ||
321 | ||
322 | ||
323 | #define MALLOC_FAILURE_MESSAGE "Heap space exhausted (malloc failed)." | |
324 | #define CALLOC_FAILURE_MESSAGE "Heap space exhausted (Calloc failed)." | |
325 | ||
326 | ||
327 | /* Commonize memory allocation call so failure diagnosis is easier */ | |
328 | ||
329 | char* dc_malloc( handle, size ) | |
330 | dc_handle_t handle; | |
331 | int size; | |
332 | { | |
333 | char* space = malloc( size ); | |
334 | if (space == (char *)NULL) | |
335 | dc_error( handle, MALLOC_FAILURE_MESSAGE ); | |
336 | ||
337 | return space; | |
338 | } | |
339 | ||
340 | ||
341 | /* Commonize memory allocation call so failure diagnosis is easier */ | |
342 | ||
343 | char* dc_calloc( handle,nelem, size ) | |
344 | dc_handle_t handle; | |
345 | int nelem; | |
346 | int size; | |
347 | { | |
348 | char* space = calloc( nelem, size ); | |
349 | if (space == (char *)NULL) | |
350 | dc_error( handle, CALLOC_FAILURE_MESSAGE ); | |
351 | ||
352 | return space; | |
353 | } | |
354 | ||
355 | ||
356 | dc_word_t dc_read_word (handle, address) | |
357 | dc_handle_t handle; | |
358 | dc_word_t address; | |
359 | { | |
360 | dc_word_t word; | |
361 | (*(handle->read_fcn)) (handle->read_env, address, | |
362 | sizeof(dc_word_t), (char *)(&(word))); | |
363 | return word; | |
364 | } | |
365 | ||
366 | ||
367 | void dc_write_word (handle, address, value) | |
368 | dc_handle_t handle; | |
369 | dc_word_t address; | |
370 | dc_word_t value; | |
371 | { | |
372 | dc_word_t word; | |
373 | word = value; | |
374 | if (handle->write_fcn) { | |
375 | (*(handle->write_fcn)) (handle->write_env, address, | |
376 | sizeof(dc_word_t), (char *)(&(word))); | |
377 | } else { | |
378 | dc_error (handle, "Writing is disabled."); | |
379 | } | |
380 | } | |
381 | ||
382 | ||
383 | void dc_write_masked_word (handle, address, mask, value) | |
384 | dc_handle_t handle; | |
385 | dc_word_t address; | |
386 | dc_word_t mask; | |
387 | dc_word_t value; | |
388 | { | |
389 | dc_write_word (handle, address, | |
390 | (value & mask) | (dc_read_word(handle, address) & ~mask)); | |
391 | } | |
392 | ||
393 | ||
394 | dc_handle_t dc_initiate (debug_info_ptr, | |
395 | error_fcn, error_env, | |
396 | read_fcn, read_env, | |
397 | write_fcn, write_env, | |
398 | exec_fcn, exec_env, | |
399 | map_fcn, map_env) | |
400 | dc_word_t debug_info_ptr; | |
401 | void (*error_fcn)(); | |
402 | dc_word_t error_env; | |
403 | void (*read_fcn)(); | |
404 | dc_word_t read_env; | |
405 | void (*write_fcn)(); /* NULL => absent */ | |
406 | dc_word_t write_env; | |
407 | void (*exec_fcn)(); /* NULL => absent */ | |
408 | dc_word_t exec_env; | |
409 | void (*map_fcn)(); /* NULL => absent */ | |
410 | dc_word_t map_env; | |
411 | /* write_fcn may be given as NULL if no writing is required. */ | |
412 | /* exec_fcn may be given as NULL if no execution is required. | |
413 | Currently, no execution is required. It would be if the | |
414 | implementation needed to invoke procedures in the debugged process. */ | |
415 | { | |
416 | dc_handle_t handle; | |
417 | unsigned int debug_info_protocol; | |
418 | dc_debug_info_t debug_info; | |
419 | unsigned int tdesc_map_protocol; | |
420 | tdesc_hdr_t tdesc_hdr; | |
421 | dc_word_t tdesc_info_start; | |
422 | dc_word_t tdesc_info_end; | |
423 | dc_word_t tdesc_info_length; | |
424 | ||
425 | /* Set up handle enough for dc_error. */ | |
426 | handle = (dc_handle_t) malloc(sizeof(handle_info_t)); | |
427 | /* Cant use dc_malloc() as handle is being created ... */ | |
428 | /* if (handle == NULL) (*error_fcn)( error_env, MALLOC_FAILURE_MESSAGE ) */ | |
429 | handle->error_fcn = error_fcn; | |
430 | handle->error_env = error_env; | |
431 | handle->read_fcn = read_fcn; | |
432 | handle->read_env = read_env; | |
433 | handle->write_fcn = write_fcn; | |
434 | handle->write_env = write_env; | |
435 | handle->exec_fcn = exec_fcn; | |
436 | handle->exec_env = exec_env; | |
437 | /****************************************************************/ | |
438 | /* BUG 9/19/89 Found by hls. Map functions not initialized. */ | |
439 | /****************************************************************/ | |
440 | handle->map_fcn = map_fcn; | |
441 | handle->map_env = map_env; | |
442 | handle->debug_info_ptr = debug_info_ptr; | |
443 | handle->tdesc_table = (tdesc_table_t)NULL; | |
444 | ||
445 | /* Find tdesc info. */ | |
446 | if (debug_info_ptr) { | |
447 | (*read_fcn) (read_env, debug_info_ptr, sizeof(unsigned int), | |
448 | (char *)(&debug_info_protocol)); | |
449 | if (debug_info_protocol != 1) | |
450 | dc_error (handle, "Unrecognized debug info protocol: %d", | |
451 | debug_info_protocol); | |
452 | (*read_fcn) (read_env, debug_info_ptr, sizeof(dc_debug_info_t), | |
453 | (char *)(&debug_info)); | |
454 | (*read_fcn) (read_env, debug_info.tdesc_ptr, sizeof(unsigned int), | |
455 | (char *)(&tdesc_map_protocol)); | |
456 | if (tdesc_map_protocol != 1) | |
457 | dc_error (handle, "Unrecognized tdesc map protocol: %d", | |
458 | tdesc_map_protocol); | |
459 | (*read_fcn) (read_env, debug_info.tdesc_ptr, sizeof(tdesc_hdr_t), | |
460 | (char *)(&tdesc_hdr)); | |
461 | tdesc_info_start = debug_info.tdesc_ptr + sizeof(tdesc_hdr_t); | |
462 | tdesc_info_end = tdesc_hdr.end; | |
463 | tdesc_info_length = tdesc_info_end - tdesc_info_start; | |
464 | ||
465 | /* Create tdesc table from tdesc info. */ | |
466 | { | |
467 | /* Over-allocate in order to avoid second pass over tdesc info. */ | |
468 | tdesc_table_t tt = (tdesc_table_t) dc_malloc(handle, tdesc_info_length); | |
469 | dc_word_t p = tdesc_info_start; | |
470 | dc_word_t q = tdesc_info_end - sizeof(tdesc_chunk1_t); | |
471 | int n = 0; | |
472 | tdesc_chunk1_t chunk; | |
473 | dc_word_t start_address, end_address; | |
474 | int i; | |
475 | ||
476 | for (; p <= q; ) { | |
477 | (*read_fcn) (read_env, p, sizeof(tdesc_chunk1_t), (char *)(&chunk)); | |
478 | if (chunk.hdr.zeroes != 0) { | |
479 | /* Skip padding. */ | |
480 | p += sizeof(dc_word_t); | |
481 | continue; | |
482 | } | |
483 | if (chunk.hdr.info_protocol != 1) { | |
484 | dc_warn (handle, "Unrecognized tdesc info protocol: %d", | |
485 | chunk.hdr.info_protocol); | |
486 | goto next_chunk; | |
487 | } | |
488 | if (chunk.hdr.info_length != 16) { | |
489 | dc_warn (handle, "Incorrect tdesc info length: %d", | |
490 | chunk.hdr.info_length); | |
491 | goto next_chunk; | |
492 | } | |
493 | if (chunk.hdr.info_alignment > 2) { | |
494 | dc_warn (handle, "Incorrect tdesc info alignment: %d", | |
495 | chunk.hdr.info_alignment); | |
496 | goto next_chunk; | |
497 | } | |
498 | start_address = chunk.hdr.start_address; | |
499 | end_address = chunk.hdr.end_address; | |
500 | if ((start_address&3)!=0) { | |
501 | dc_warn (handle, | |
502 | "Tdesc start address is not word-aligned: %#.8X", | |
503 | start_address); | |
504 | goto next_chunk; | |
505 | } | |
506 | if ((end_address&3)!=0) { | |
507 | dc_warn (handle, | |
508 | "Tdesc end address is not word-aligned: %#.8X", | |
509 | end_address); | |
510 | goto next_chunk; | |
511 | } | |
512 | if (start_address > end_address) { | |
513 | /* Note that the range may be null. */ | |
514 | dc_warn (handle, | |
515 | "Tdesc start address (%#.8X) follows end address (%#.8X).", | |
516 | start_address, end_address); | |
517 | goto next_chunk; | |
518 | } | |
519 | if (chunk.info.variant != 1) { | |
520 | dc_warn (handle, "Invalid tdesc chunk variant: %d", | |
521 | chunk.info.variant); | |
522 | goto next_chunk; | |
523 | } | |
524 | if (chunk.info.pad1 != 0) { | |
525 | dc_warn (handle, "Tdesc chunk padding is not zero."); | |
526 | goto next_chunk; | |
527 | } | |
528 | if (chunk.info.return_address_info_discriminant != 0) { | |
529 | if ((chunk.info.return_address_info & 3) != 0) { | |
530 | dc_warn (handle, | |
531 | "Tdesc return address offset is not word-aligned: %#.8X", | |
532 | chunk.info.return_address_info); | |
533 | goto next_chunk; | |
534 | } | |
535 | } else { | |
536 | if ((chunk.info.return_address_info & ~31) != 0) { | |
537 | dc_warn (handle, | |
538 | "Invalid tdesc return address register: %d", | |
539 | chunk.info.return_address_info); | |
540 | goto next_chunk; | |
541 | } | |
542 | } | |
543 | if ((chunk.info.register_save_offset & 3) != 0) { | |
544 | dc_warn (handle, | |
545 | "Tdesc register save offset is not word-aligned: %#.8X", | |
546 | chunk.info.register_save_offset); | |
547 | goto next_chunk; | |
548 | } | |
549 | ||
550 | tt[n].start_address = start_address; | |
551 | tt[n].end_address = end_address; | |
552 | tt[n].info = chunk.info; | |
553 | n++; | |
554 | ||
555 | next_chunk: | |
556 | p += sizeof(tdesc_chunk1_t); | |
557 | } | |
558 | /* Leftover (less than a tdesc_chunk1_t in size) is padding or | |
559 | in error. Ignore it in either case. */ | |
560 | ||
561 | if (n != 0) { | |
562 | ||
563 | /* Sort table by start address. */ | |
564 | qsort ((char *)tt, n, sizeof(tdesc_elem_t), dc_compare_tdesc_elems); | |
565 | ||
566 | /* Check for overlap among tdesc chunks. */ | |
567 | for (i=0; i<(n-1); i++) { | |
568 | if (tt[i].end_address > tt[i+1].start_address) | |
569 | dc_error (handle, "Text chunks overlap."); | |
570 | } | |
571 | } | |
572 | ||
573 | /* Finish setting up handle. */ | |
574 | handle->tdesc_table = tt; | |
575 | handle->tdesc_table_size = n; | |
576 | } | |
577 | } else { | |
578 | handle->tdesc_table_size = 0; | |
579 | } | |
580 | ||
581 | return (dc_handle_t) handle; | |
582 | } | |
583 | ||
584 | ||
585 | void dc_terminate (handle) | |
586 | dc_handle_t handle; | |
587 | { | |
588 | if (((dc_handle_t)handle)->tdesc_table) { | |
589 | free((char *)(((dc_handle_t)handle)->tdesc_table)); | |
590 | } | |
591 | free((char *)handle); | |
592 | } | |
593 | ||
594 | ||
595 | ||
596 | /* | |
597 | ||
598 | Dcontext Model | |
599 | ||
600 | For each interesting register (word-sized piece of machine state), | |
601 | a word of value information is kept. This word may | |
602 | be either the value of the register, or the address in | |
603 | subject memory where the value can be found (and changed). In | |
604 | addition, the register may be invalid (in which case the value | |
605 | information is undefined). These three cases are encoded for | |
606 | a given register in the same-numbered bit of two words of flags: | |
607 | ||
608 | flags[0] bit flags[1] bit meaning | |
609 | ------------ ------------ ------- | |
610 | 0 0 register is invalid; info is undefined | |
611 | 0 1 register is readable; info is value | |
612 | 1 0 register is writable; info is address | |
613 | 1 1 (reserved) | |
614 | ||
615 | The general registers (r0-r31) are handled by reg_info and | |
616 | reg_flags. The bit number for a register is that register's number. | |
617 | The other registers are grouped together for convenience and are | |
618 | handled by aux_info and aux_flags. The bit numbers for these | |
619 | registers are: | |
620 | ||
621 | bit number register | |
622 | ---------- -------- | |
623 | 0 location | |
624 | 1 SXIP | |
625 | 2 SNIP | |
626 | 3 SFIP | |
627 | 4 FPSR | |
628 | 5 FPCR | |
629 | ||
630 | The SXIP, SNIP, and SFIP are the exception-time values of the | |
631 | XIP, NIP, and FIP registers. They are valid only in the topmost frame. | |
632 | (That is, in any context obtained from dc_previous_context, they | |
633 | are invalid.) | |
634 | ||
635 | "location" is a pseudo-register of this model and represents the | |
636 | location of the context. It is always valid. It also has an | |
637 | exactness associated with it. The location and its exactness of a | |
638 | context obtained from dc_previous_context are taken from the | |
639 | return address and its exactness of the context given as an argument | |
640 | to dc_previous_context. | |
641 | ||
642 | The following model is recommended for dealing with the partial | |
643 | redundancy between location and the SXIP, SNIP, and SFIP values | |
644 | in the topmost frame. The location should be set to either the | |
645 | SNIP or SXIP value, and its exactness should be set to DC_NO. A | |
646 | change to the register whose value the location is set to should | |
647 | be accompanied by an identical change to the location. | |
648 | ||
649 | The PSR is handled separately, because it is a diverse collection | |
650 | of flags. The PSR, as a whole, is always valid. A separate | |
651 | psr_ind flag tells whether the psr_info data is a value or | |
652 | an address. Each bit of the PSR has its own pair of flag bits to | |
653 | mark validity and writability. | |
654 | ||
655 | */ | |
656 | ||
657 | ||
658 | /* The following value means "other", because state is stored in 2 bits. */ | |
659 | #define DC_RESERVED 3 | |
660 | ||
661 | ||
662 | #define RSTATE(flags, bit) \ | |
663 | ((bit_value((flags)[0], bit) << 1) + bit_value((flags)[1], bit)) | |
664 | ||
665 | #define REG_STATE(dcontext, reg) RSTATE(dcontext->reg_flags, reg) | |
666 | #define AUX_STATE(dcontext, reg) RSTATE(dcontext->aux_flags, reg) | |
667 | #define PSR_STATE(dcontext, reg) RSTATE(dcontext->psr_flags, reg) | |
668 | ||
669 | ||
670 | #define SET_INVALID(flags, bit) \ | |
671 | { bit_clear ((flags)[0], bit); bit_clear ((flags)[1], bit); } | |
672 | ||
673 | #define SET_READABLE(flags, bit) \ | |
674 | { bit_clear ((flags)[0], bit); bit_set ((flags)[1], bit); } | |
675 | ||
676 | #define SET_WRITABLE(flags, bit) \ | |
677 | { bit_set ((flags)[0], bit); bit_clear ((flags)[1], bit); } | |
678 | ||
679 | #define ASSIGN_RSTATE(to_flags, to_bit, from_flags, from_bit) \ | |
680 | { bit_assign ((to_flags)[0], to_bit, bit_value((from_flags)[0], from_bit));\ | |
681 | bit_assign ((to_flags)[1], to_bit, bit_value((from_flags)[1], from_bit));} | |
682 | ||
683 | ||
684 | #define CHECK_REG_READ(dcontext, reg) \ | |
685 | if (REG_STATE(dcontext, reg) == DC_INVALID) \ | |
686 | dc_error (dcontext->handle, \ | |
687 | "General register %d is not readable.", reg) | |
688 | ||
689 | #define CHECK_REG_WRITE(dcontext, reg) \ | |
690 | if (REG_STATE(dcontext, reg) != DC_WRITABLE) \ | |
691 | dc_error (dcontext->handle, \ | |
692 | "General register %d is not writable.", reg) | |
693 | ||
694 | #define CHECK_AUX_READ(dcontext, reg) \ | |
695 | if (AUX_STATE(dcontext, reg) == DC_INVALID) \ | |
696 | dc_error (dcontext->handle, \ | |
697 | "Auxiliary register %d is not readable.", reg) | |
698 | ||
699 | #define CHECK_AUX_WRITE(dcontext, reg) \ | |
700 | if (AUX_STATE(dcontext, reg) != DC_WRITABLE) \ | |
701 | dc_error (dcontext->handle, \ | |
702 | "Auxiliary register %d is not writable.", reg) | |
703 | ||
704 | ||
705 | ||
706 | #define DC_REG_RA 1 | |
707 | #define DC_REG_FP 30 | |
708 | #define DC_REG_SP 31 | |
709 | #define DC_NUM_REG 32 | |
710 | ||
711 | #define DC_AUX_LOC 0 | |
712 | /* DC_AUX_LOC must be first, with value 0 */ | |
713 | #define DC_AUX_SXIP 1 | |
714 | #define DC_AUX_SNIP 2 | |
715 | #define DC_AUX_SFIP 3 | |
716 | #define DC_AUX_FPSR 4 | |
717 | #define DC_AUX_FPCR 5 | |
718 | #define DC_NUM_AUX 6 | |
719 | ||
720 | ||
721 | ||
722 | #define CHECK_REG(dcontext, reg) \ | |
723 | if ((reg < 0) || (reg >= DC_NUM_REG)) \ | |
724 | dc_error (dcontext->handle, \ | |
725 | "Bad general register number: %d", reg) | |
726 | ||
727 | #define CHECK_AUX(dcontext, reg) \ | |
728 | if ((reg < 1) || (reg >= DC_NUM_AUX)) \ | |
729 | dc_error (dcontext->handle, \ | |
730 | "Bad auxiliary register number: %d", reg) | |
731 | /* CHECK_AUX is not used for location pseudo-register. */ | |
732 | ||
733 | #define CHECK_BIT(dcontext, bit) \ | |
734 | if ((bit < 0) || (bit >= 32)) \ | |
735 | dc_error (dcontext->handle, \ | |
736 | "Bad bit number: %d", bit) | |
737 | ||
738 | ||
739 | ||
740 | typedef struct cr_value { | |
741 | int reg; | |
742 | unsigned int off; | |
743 | } dc_cr_value_t; | |
744 | ||
745 | #define DC_UNDEF 32 | |
746 | ||
747 | /* | |
748 | A "dc_cr_value" represents an execution-time value symbolically, in | |
749 | terms of the initial value of a register (the value on entry to | |
750 | the procedure being analyzed) and a known offset. A value with | |
751 | a 'reg' field value of 0 through 31 represents the value obtained | |
752 | by summing (using 32-bit modulus arithmetic) the initial value of | |
753 | register 'reg' and the value 'off'. Note that the value (0,k) | |
754 | represents the constant value k, that (31,0) represents the CFA, and | |
755 | that (1,0) represents the return address. A value with a 'reg' field | |
756 | of DC_UNDEF represents an indeterminable value; in this case the | |
757 | 'off' field is undefined. Other values of 'reg' are erroneous. | |
758 | */ | |
759 | ||
760 | typedef struct cr_data { | |
761 | dc_cr_value_t reg_val[DC_NUM_REG]; | |
762 | dc_word_t saved; | |
763 | dc_word_t how; | |
764 | unsigned int where[DC_NUM_REG]; | |
765 | } dc_cr_data_t; | |
766 | ||
767 | /* | |
768 | 'cr_data' collects all the information needed to represent the | |
769 | symbolic machine state during code reading. | |
770 | ||
771 | The 'reg_val' array gives the current dc_cr_value for each register. | |
772 | ||
773 | The 'saved', 'how', and 'where' fields combine to describe what | |
774 | registers have been saved, and where. The 'saved' and 'how' fields | |
775 | are implicitly bit arrays over 0..31, where the numbering is from | |
776 | 0 on the right. (Hence, 1<<r gives the mask for register r.) | |
777 | If saved[r] is 0, the register is not saved, and how[r] and where[r] | |
778 | are undefined. If saved[r] is 1, then how[r] tells whether register r | |
779 | was saved in another register (how[r]==0) or in the frame (how[r]==1). | |
780 | In the former case, where[r] gives the register number; in the latter | |
781 | case, where[r] gives the frame position. | |
782 | */ | |
783 | ||
784 | ||
785 | typedef int dc_register_state_t; /* range 0 to 2 */ | |
786 | ||
787 | #define DC_INVALID 0 | |
788 | #define DC_READABLE 1 | |
789 | #define DC_WRITABLE 2 | |
790 | ||
791 | ||
792 | ||
793 | ||
794 | typedef struct dcontext_info { | |
795 | dc_handle_t handle; /* environment of context */ | |
796 | dc_word_t reg_info[DC_NUM_REG]; | |
797 | dc_word_t reg_flags[2]; | |
798 | dc_word_t aux_info[DC_NUM_AUX]; | |
799 | dc_word_t aux_flags[2]; | |
800 | dc_exactness_t loc_exact; | |
801 | dc_word_t psr_info; /* value or address */ | |
802 | dc_word_t psr_ind; /* DC_TRUE iff address */ | |
803 | dc_word_t psr_flags[2]; /* per-PSR-bit flags */ | |
804 | unsigned int code_reading; /* no tdesc therefore must read code*/ | |
805 | union { | |
806 | tdesc_elem_t *tdesc_elem_ptr; /* locates tdesc chunk */ | |
807 | dc_cr_data_t *cr_data_ptr; /* or code reading data */ | |
808 | } info_ptr; | |
809 | } dcontext_info_t; | |
810 | ||
811 | typedef dcontext_info_t *dc_dcontext_t; | |
812 | ||
813 | dc_word_t dc_get_value (handle, info, flags, pos) | |
814 | dc_handle_t handle; | |
815 | dc_word_t info[]; | |
816 | dc_word_t flags[2]; | |
817 | int pos; | |
818 | /* Assumes either DC_READABLE or DC_WRITABLE. */ | |
819 | { | |
820 | if (bit_test(flags[0], pos)) { | |
821 | /* DC_WRITABLE case */ | |
822 | return dc_read_word(handle, info[pos]); | |
823 | } else { | |
824 | /* DC_READABLE case */ | |
825 | return info[pos]; | |
826 | } | |
827 | } | |
828 | ||
829 | void dc_set_value (handle, info, flags, pos, value) | |
830 | dc_handle_t handle; | |
831 | dc_word_t info[]; | |
832 | dc_word_t flags[2]; | |
833 | int pos; | |
834 | dc_word_t value; | |
835 | /* Assumes DC_WRITABLE. */ | |
836 | { | |
837 | dc_write_word(handle, info[pos], value); | |
838 | } | |
839 | ||
840 | ||
841 | #define GET_REG_VALUE(dcontext, reg) \ | |
842 | dc_get_value(dcontext->handle, dcontext->reg_info, dcontext->reg_flags, reg) | |
843 | ||
844 | #define SET_REG_VALUE(dcontext, reg, value) \ | |
845 | dc_set_value(dcontext->handle, dcontext->reg_info, dcontext->reg_flags, reg, \ | |
846 | value) | |
847 | ||
848 | #define GET_AUX_VALUE(dcontext, reg) \ | |
849 | dc_get_value(dcontext->handle, dcontext->aux_info, dcontext->aux_flags, reg) | |
850 | ||
851 | #define SET_AUX_VALUE(dcontext, reg, value) \ | |
852 | dc_set_value(dcontext->handle, dcontext->aux_info, dcontext->aux_flags, reg, \ | |
853 | value) | |
854 | ||
855 | ||
856 | ||
857 | void dc_check_dcontext (dc) | |
858 | dc_dcontext_t dc; | |
859 | /* Check consistency of information supplied to make a dcontext. */ | |
860 | { | |
861 | int i; | |
862 | ||
863 | if ((REG_STATE(dc, 0) != DC_READABLE) || (dc->reg_info[0] != 0)) | |
864 | dc_error (dc->handle, "Register 0 is misspecified"); | |
865 | for (i = 1; i < DC_NUM_REG; i++) | |
866 | if (REG_STATE(dc, i) == DC_RESERVED) | |
867 | dc_error (dc->handle, | |
868 | "State for general register %d is incorrect", i); | |
869 | for (i = 0; i < DC_NUM_AUX; i++) | |
870 | if (AUX_STATE(dc, i) == DC_RESERVED) | |
871 | dc_error (dc->handle, | |
872 | "State for auxiliary register %d is incorrect", i); | |
873 | if (AUX_STATE(dc, DC_AUX_LOC) == DC_INVALID) | |
874 | dc_error (dc->handle, "Location is specified as invalid"); | |
875 | if (GET_AUX_VALUE(dc, DC_AUX_LOC) == 0) | |
876 | dc_error (dc->handle, "Location is zero."); | |
877 | if (dc->loc_exact >= 3) | |
878 | dc_error (dc->handle, "Location exactness is incorrectly specified: %d", | |
879 | dc->loc_exact); | |
880 | if (dc->psr_ind >= 2) | |
881 | dc_error (dc->handle, | |
882 | "PSR indirection flag is incorrectly specified: %d", | |
883 | dc->psr_ind); | |
884 | for (i = 0; i < 32; i++) | |
885 | if (PSR_STATE(dc, i) == DC_RESERVED) | |
886 | dc_error (dc->handle, "State for PSR bit %d is incorrect", i); | |
887 | } | |
888 | ||
889 | ||
890 | ||
891 | tdesc_elem_t * dc_tdesc_lookup (loc, tt, tt_size, map_info_in_ptr) | |
892 | dc_word_t loc; | |
893 | tdesc_table_t tt; | |
894 | int tt_size; | |
895 | dc_map_info_in_t *map_info_in_ptr; | |
896 | /* Return address of tdesc_elem_t for given location, or NULL if | |
897 | there is no tdesc chunk for the location. | |
898 | */ | |
899 | { | |
900 | int l = 0; | |
901 | int h = tt_size; | |
902 | int m; | |
903 | ||
904 | if (tt_size == 0) { | |
905 | map_info_in_ptr->flags = 0; | |
906 | return (tdesc_elem_t *)NULL; | |
907 | } | |
908 | for (;;) { | |
909 | m = (l + h) / 2; | |
910 | if (m == l) break; | |
911 | if (loc >= tt[m].start_address) | |
912 | l = m; | |
913 | else | |
914 | h = m; | |
915 | } | |
916 | if (loc >= tt[m].end_address) { | |
917 | map_info_in_ptr->preceding_tdesc_end = tt[m].end_address; | |
918 | if (m+1 < tt_size) { | |
919 | map_info_in_ptr->following_tdesc_start = tt[m+1].start_address; | |
920 | map_info_in_ptr->flags = DC_MII_PRECEDING_TDESC_END | | |
921 | DC_MII_FOLLOWING_TDESC_START; | |
922 | } else { | |
923 | map_info_in_ptr->flags = DC_MII_PRECEDING_TDESC_END; | |
924 | } | |
925 | return (tdesc_elem_t *)NULL; | |
926 | } else if (loc < tt[m].start_address) { | |
927 | map_info_in_ptr->following_tdesc_start = tt[m].start_address; | |
928 | map_info_in_ptr->flags = DC_MII_FOLLOWING_TDESC_START; | |
929 | return (tdesc_elem_t *)NULL; | |
930 | } else { | |
931 | return (&tt[m]); | |
932 | } | |
933 | } | |
934 | ||
935 | ||
936 | ||
937 | dc_dcontext_t dc_make_dcontext (handle, | |
938 | reg_info, reg_flags, | |
939 | aux_info, aux_flags, loc_exact, | |
940 | psr_info, psr_ind, psr_flags) | |
941 | dc_handle_t handle; | |
942 | dc_word_t reg_info[DC_NUM_REG]; | |
943 | dc_word_t reg_flags[2]; | |
944 | dc_word_t aux_info[DC_NUM_AUX]; | |
945 | dc_word_t aux_flags[2]; | |
946 | dc_exactness_t loc_exact; | |
947 | dc_word_t psr_info; | |
948 | dc_boolean_t psr_ind; | |
949 | dc_word_t psr_flags[2]; | |
950 | { | |
951 | dc_dcontext_t dc = (dc_dcontext_t) dc_malloc (handle, sizeof(dcontext_info_t)); | |
952 | int i; | |
953 | dc_map_info_in_t map_info_in; | |
954 | ||
955 | /* Fill in supplied content. */ | |
956 | dc->handle = ((dc_handle_t)handle); | |
957 | for (i = 0; i < DC_NUM_REG; i++) dc->reg_info[i] = reg_info[i]; | |
958 | for (i = 0; i < 2; i++) dc->reg_flags[i] = reg_flags[i]; | |
959 | for (i = 0; i < DC_NUM_AUX; i++) dc->aux_info[i] = aux_info[i]; | |
960 | for (i = 0; i < 2; i++) dc->aux_flags[i] = aux_flags[i]; | |
961 | dc->loc_exact = loc_exact; | |
962 | dc->psr_info = psr_info; | |
963 | dc->psr_ind = psr_ind; | |
964 | for (i = 0; i < 2; i++) dc->psr_flags[i] = psr_flags[i]; | |
965 | ||
966 | dc_check_dcontext(dc); | |
967 | ||
968 | /* Find tdesc information for the text chunk. */ | |
969 | { | |
970 | /***************************************************************/ | |
971 | /* BUG 8/16/89 Found by hls. Not zeroing EV bits of location. */ | |
972 | /* SHOULD USE dc_location()! */ | |
973 | /* dc_word_t loc = GET_AUX_VALUE(dc, DC_AUX_LOC); */ | |
974 | /***************************************************************/ | |
975 | dc_word_t loc = GET_AUX_VALUE(dc, DC_AUX_LOC) & ~3; | |
976 | tdesc_elem_t *tep = | |
977 | dc_tdesc_lookup(loc, ((dc_handle_t)handle)->tdesc_table, | |
978 | ((dc_handle_t)handle)->tdesc_table_size,&map_info_in); | |
979 | if (tep) { | |
980 | dc->code_reading = 0; | |
981 | dc->info_ptr.tdesc_elem_ptr = tep; | |
982 | } else { | |
983 | dc->code_reading = 1; | |
984 | if (!dc->handle->map_fcn) { | |
985 | dc_error (dc->handle, "No tdesc information for %#.8X and no map function supplied.",loc); | |
986 | } | |
987 | /****************************************************************/ | |
988 | /* BUG 9/18/89 Found by hls. Not using dc_malloc() */ | |
989 | /* dc->info_ptr.cr_data_ptr= (dc_cr_data_t *)malloc(sizeof(dc_cr_data_t )); */ | |
990 | /****************************************************************/ | |
991 | dc->info_ptr.cr_data_ptr= (dc_cr_data_t *)dc_calloc(dc->handle,1,sizeof(dc_cr_data_t )); | |
992 | dc_read_code(loc,dc,map_info_in,dc->info_ptr.cr_data_ptr); | |
993 | } | |
994 | } | |
995 | ||
996 | return (dc_dcontext_t) dc; | |
997 | } | |
998 | ||
999 | ||
1000 | ||
1001 | void dc_free_dcontext (dcontext) | |
1002 | dc_dcontext_t dcontext; | |
1003 | { | |
1004 | /****************************************************************/ | |
1005 | /* BUG 9/19/89 Found by hls. Freeing non-pointer value. */ | |
1006 | /* free((char *)dcontext->code_reading); */ | |
1007 | /****************************************************************/ | |
1008 | if (dcontext->code_reading) | |
1009 | free((char *)dcontext->info_ptr.cr_data_ptr); | |
1010 | free((char *)dcontext); | |
1011 | } | |
1012 | ||
1013 | ||
1014 | ||
1015 | dc_register_state_t dc_location_state (dcontext) | |
1016 | dc_dcontext_t dcontext; | |
1017 | { | |
1018 | return AUX_STATE(((dc_dcontext_t)dcontext), DC_AUX_LOC); | |
1019 | } | |
1020 | ||
1021 | ||
1022 | dc_exactness_t dc_location_exactness (dcontext) | |
1023 | dc_dcontext_t dcontext; | |
1024 | { | |
1025 | return ((dc_dcontext_t)dcontext)->loc_exact; | |
1026 | } | |
1027 | ||
1028 | ||
1029 | dc_word_t dc_location (dcontext) | |
1030 | dc_dcontext_t dcontext; | |
1031 | /* Return high 30 bits only. */ | |
1032 | { | |
1033 | /* Don't need: CHECK_AUX_READ (((dc_dcontext_t)dcontext), DC_AUX_LOC); */ | |
1034 | return GET_AUX_VALUE (((dc_dcontext_t)dcontext), DC_AUX_LOC) & ~3; | |
1035 | } | |
1036 | ||
1037 | ||
1038 | dc_boolean_t dc_location_in_text_chunk( dcontext, value ) | |
1039 | dc_dcontext_t dcontext; | |
1040 | dc_word_t value; | |
1041 | { | |
1042 | /* Check that new location is still within same text chunk. */ | |
1043 | tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; | |
1044 | /********************************************************************/ | |
1045 | /* Bug in predicate -- LS adjusted according to OCS documentation.. */ | |
1046 | /* if ((value < tep->start_address) || (value >= tep->end_address))*/ | |
1047 | /********************************************************************/ | |
1048 | if ((value >= tep->start_address) && (value < tep->end_address)) | |
1049 | return DC_TRUE; | |
1050 | else | |
1051 | return DC_FALSE; | |
1052 | ||
1053 | } | |
1054 | ||
1055 | ||
1056 | void dc_set_location (dcontext, value) | |
1057 | dc_dcontext_t dcontext; | |
1058 | dc_word_t value; | |
1059 | /* Set high 30 bits only. */ | |
1060 | { | |
1061 | if (dc_location_in_text_chunk( dcontext, value ) != DC_TRUE) | |
1062 | dc_warn (((dc_dcontext_t)dcontext)->handle, | |
1063 | "New location is not in same text chunk."); | |
1064 | ||
1065 | CHECK_AUX_WRITE (((dc_dcontext_t)dcontext), DC_AUX_LOC); | |
1066 | dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, | |
1067 | ((dc_dcontext_t)dcontext)->aux_info[DC_AUX_LOC], ~3, value); | |
1068 | } | |
1069 | ||
1070 | ||
1071 | ||
1072 | dc_register_state_t dc_general_register_state (dcontext, reg) | |
1073 | dc_dcontext_t dcontext; | |
1074 | int reg; | |
1075 | { | |
1076 | CHECK_REG (((dc_dcontext_t)dcontext), reg); | |
1077 | return REG_STATE(((dc_dcontext_t)dcontext), reg); | |
1078 | } | |
1079 | ||
1080 | ||
1081 | dc_word_t dc_general_register (dcontext, reg) | |
1082 | dc_dcontext_t dcontext; | |
1083 | int reg; | |
1084 | { | |
1085 | CHECK_REG (((dc_dcontext_t)dcontext), reg); | |
1086 | CHECK_REG_READ (((dc_dcontext_t)dcontext), reg); | |
1087 | return GET_REG_VALUE(((dc_dcontext_t)dcontext), reg); | |
1088 | } | |
1089 | ||
1090 | ||
1091 | void dc_set_general_register (dcontext, reg, value) | |
1092 | dc_dcontext_t dcontext; | |
1093 | int reg; | |
1094 | dc_word_t value; | |
1095 | { | |
1096 | CHECK_REG (((dc_dcontext_t)dcontext), reg); | |
1097 | CHECK_REG_WRITE (((dc_dcontext_t)dcontext), reg); | |
1098 | SET_REG_VALUE (((dc_dcontext_t)dcontext), reg, value); | |
1099 | } | |
1100 | ||
1101 | ||
1102 | ||
1103 | dc_register_state_t dc_auxiliary_register_state (dcontext, reg) | |
1104 | dc_dcontext_t dcontext; | |
1105 | int reg; | |
1106 | { | |
1107 | CHECK_AUX (((dc_dcontext_t)dcontext), reg); | |
1108 | return AUX_STATE(((dc_dcontext_t)dcontext), reg); | |
1109 | } | |
1110 | ||
1111 | ||
1112 | dc_word_t dc_auxiliary_register (dcontext, reg) | |
1113 | dc_dcontext_t dcontext; | |
1114 | int reg; | |
1115 | { | |
1116 | CHECK_AUX (((dc_dcontext_t)dcontext), reg); | |
1117 | CHECK_AUX_READ (((dc_dcontext_t)dcontext), reg); | |
1118 | return GET_AUX_VALUE(((dc_dcontext_t)dcontext), reg); | |
1119 | } | |
1120 | ||
1121 | ||
1122 | void dc_set_auxiliary_register (dcontext, reg, value) | |
1123 | dc_dcontext_t dcontext; | |
1124 | int reg; | |
1125 | dc_word_t value; | |
1126 | { | |
1127 | CHECK_AUX (((dc_dcontext_t)dcontext), reg); | |
1128 | CHECK_AUX_WRITE (((dc_dcontext_t)dcontext), reg); | |
1129 | SET_AUX_VALUE (((dc_dcontext_t)dcontext), reg, value); | |
1130 | } | |
1131 | ||
1132 | ||
1133 | ||
1134 | dc_register_state_t dc_psr_register_bit_state (dcontext, bit) | |
1135 | dc_dcontext_t dcontext; | |
1136 | int bit; | |
1137 | { | |
1138 | CHECK_BIT (((dc_dcontext_t)dcontext), bit); | |
1139 | return PSR_STATE(((dc_dcontext_t)dcontext), bit); | |
1140 | } | |
1141 | ||
1142 | ||
1143 | dc_word_t dc_psr_register (dcontext) | |
1144 | dc_dcontext_t dcontext; | |
1145 | { | |
1146 | if (((dc_dcontext_t)dcontext)->psr_ind) { | |
1147 | return dc_read_word(((dc_dcontext_t)dcontext)->handle, | |
1148 | ((dc_dcontext_t)dcontext)->psr_info); | |
1149 | } else { | |
1150 | return ((dc_dcontext_t)dcontext)->psr_info; | |
1151 | } | |
1152 | } | |
1153 | ||
1154 | ||
1155 | void dc_set_psr_register (dcontext, mask, value) | |
1156 | dc_dcontext_t dcontext; | |
1157 | dc_word_t mask; | |
1158 | dc_word_t value; | |
1159 | /* Set bits of PSR corresponding to 1 bits in mask. */ | |
1160 | { | |
1161 | if (((dc_dcontext_t)dcontext)->psr_ind) { | |
1162 | if (((((dc_dcontext_t)dcontext)->psr_flags[0] & mask) != mask) || | |
1163 | ((((dc_dcontext_t)dcontext)->psr_flags[1] & mask) != 0)) | |
1164 | dc_error (((dc_dcontext_t)dcontext)->handle, | |
1165 | "Some PSR bits specified are not writable."); | |
1166 | dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, | |
1167 | ((dc_dcontext_t)dcontext)->psr_info, mask, value); | |
1168 | } else { | |
1169 | dc_error (((dc_dcontext_t)dcontext)->handle, "PSR is not writable."); | |
1170 | } | |
1171 | } | |
1172 | ||
1173 | ||
1174 | ||
1175 | dc_word_t dc_frame_address (dcontext) | |
1176 | dc_dcontext_t dcontext; | |
1177 | { | |
1178 | if (!dcontext->code_reading) { | |
1179 | tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; | |
1180 | return dc_general_register(dcontext, | |
1181 | tep->info.frame_address_register) + tep->info.frame_address_offset; | |
1182 | } else { | |
1183 | if (dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_FP].reg == DC_REG_SP) { | |
1184 | return (dc_general_register(dcontext,DC_REG_FP) | |
1185 | - dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_FP].off); | |
1186 | } | |
1187 | if (dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_SP].reg == DC_REG_SP) { | |
1188 | return (dc_general_register(dcontext,DC_REG_SP) | |
1189 | - dcontext->info_ptr.cr_data_ptr->reg_val[DC_REG_SP].off); | |
1190 | } | |
1191 | dc_error (((dc_dcontext_t)dcontext)->handle, "Cannot locate frame pointer."); | |
1192 | } | |
1193 | } | |
1194 | ||
1195 | ||
1196 | ||
1197 | dc_kind_t dc_context_kind (dcontext) | |
1198 | dc_dcontext_t dcontext; | |
1199 | { | |
1200 | return DC_CALL_KIND; | |
1201 | } | |
1202 | ||
1203 | ||
1204 | ||
1205 | ||
1206 | /* operations valid for call contexts only */ | |
1207 | ||
1208 | ||
1209 | dc_register_state_t dc_return_address_state (dcontext) | |
1210 | dc_dcontext_t dcontext; | |
1211 | { | |
1212 | tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; | |
1213 | int reg; | |
1214 | ||
1215 | if (!dcontext->code_reading) { | |
1216 | if (tep->info.return_address_info_discriminant) { | |
1217 | return DC_WRITABLE; | |
1218 | } else { | |
1219 | return REG_STATE(((dc_dcontext_t)dcontext), tep->info.return_address_info); | |
1220 | } | |
1221 | } else { | |
1222 | reg= DC_REG_RA; | |
1223 | if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,DC_REG_RA)) { | |
1224 | if (bit_test(dcontext->info_ptr.cr_data_ptr->how,DC_REG_RA)) { | |
1225 | return DC_WRITABLE; | |
1226 | } else { | |
1227 | reg= dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]; | |
1228 | } | |
1229 | } | |
1230 | return REG_STATE(((dc_dcontext_t)dcontext),reg); | |
1231 | ||
1232 | ||
1233 | } | |
1234 | } | |
1235 | ||
1236 | ||
1237 | dc_exactness_t dc_return_address_exactness (dcontext) | |
1238 | dc_dcontext_t dcontext; | |
1239 | { | |
1240 | return DC_MAYBE; | |
1241 | } | |
1242 | ||
1243 | ||
1244 | dc_word_t dc_return_address (dcontext) | |
1245 | dc_dcontext_t dcontext; | |
1246 | /* Return high 30 bits only. */ | |
1247 | { | |
1248 | tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; | |
1249 | dc_word_t rai = tep->info.return_address_info; | |
1250 | dc_word_t val; | |
1251 | int reg; | |
1252 | ||
1253 | if (!dcontext->code_reading) { | |
1254 | if (tep->info.return_address_info_discriminant) { | |
1255 | val = dc_read_word (((dc_dcontext_t)dcontext)->handle, | |
1256 | dc_frame_address(dcontext) + rai); | |
1257 | } else { | |
1258 | val = dc_general_register (dcontext, rai); | |
1259 | } | |
1260 | } else { | |
1261 | reg=DC_REG_RA; | |
1262 | if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,reg)) { | |
1263 | if (bit_test(dcontext->info_ptr.cr_data_ptr->how,reg)) { | |
1264 | val = dc_read_word (((dc_dcontext_t)dcontext)->handle, | |
1265 | dc_frame_address(dcontext) + | |
1266 | (dcontext->info_ptr.cr_data_ptr->where[reg])); | |
1267 | } else { | |
1268 | reg= dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]; | |
1269 | val = dc_general_register (dcontext, reg); | |
1270 | } | |
1271 | } else { | |
1272 | val = dc_general_register (dcontext, reg); | |
1273 | } | |
1274 | } | |
1275 | return val & ~3; | |
1276 | } | |
1277 | ||
1278 | ||
1279 | void dc_set_return_address (dcontext, value) | |
1280 | dc_dcontext_t dcontext; | |
1281 | dc_word_t value; | |
1282 | /* Set high 30 bits only. */ | |
1283 | { | |
1284 | if (!dcontext->code_reading) { | |
1285 | tdesc_elem_t *tep = ((dc_dcontext_t)dcontext)->info_ptr.tdesc_elem_ptr; | |
1286 | dc_word_t rai = tep->info.return_address_info; | |
1287 | ||
1288 | if (tep->info.return_address_info_discriminant) { | |
1289 | dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, | |
1290 | dc_frame_address(dcontext) + rai, ~3, value); | |
1291 | } else { | |
1292 | dc_set_general_register (dcontext, rai, | |
1293 | (value & ~3) | (dc_general_register(dcontext, rai) & 3)); | |
1294 | } | |
1295 | } else { | |
1296 | if (bit_test(dcontext->info_ptr.cr_data_ptr->saved,DC_REG_RA)) { | |
1297 | if (bit_test(dcontext->info_ptr.cr_data_ptr->how,DC_REG_RA)) { | |
1298 | dc_write_masked_word (((dc_dcontext_t)dcontext)->handle, | |
1299 | dc_frame_address(dcontext) | |
1300 | + dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA], ~3, value); | |
1301 | } else { | |
1302 | dc_set_general_register( dcontext, | |
1303 | dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]); | |
1304 | } | |
1305 | } else { | |
1306 | dc_set_general_register( dcontext, | |
1307 | dcontext->info_ptr.cr_data_ptr->where[DC_REG_RA]); | |
1308 | } | |
1309 | } | |
1310 | } | |
1311 | ||
1312 | ||
1313 | ||
1314 | /* operations valid for save contexts only */ | |
1315 | ||
1316 | /* (none) */ | |
1317 | ||
1318 | ||
1319 | ||
1320 | /* operations valid for exception contexts only */ | |
1321 | ||
1322 | ||
1323 | void dc_get_exception_info (dcontext, handler, datum) | |
1324 | dc_dcontext_t dcontext; | |
1325 | dc_word_t *handler; | |
1326 | dc_word_t *datum; | |
1327 | { | |
1328 | dc_error (((dc_dcontext_t)dcontext)->handle, | |
1329 | "dc_get_exception_info is not yet implemented."); | |
1330 | } | |
1331 | ||
1332 | ||
1333 | ||
1334 | /* operations valid for protection contexts only */ | |
1335 | ||
1336 | ||
1337 | void dc_get_protection_info (dcontext, handler, datum) | |
1338 | dc_dcontext_t dcontext; | |
1339 | dc_word_t *handler; | |
1340 | dc_word_t *datum; | |
1341 | { | |
1342 | dc_error (((dc_dcontext_t)dcontext)->handle, | |
1343 | "dc_get_protection_info is not yet implemented."); | |
1344 | } | |
1345 | ||
1346 | ||
1347 | ||
1348 | /* operations valid for special contexts only */ | |
1349 | ||
1350 | ||
1351 | void dc_get_special_info (dcontext, kind, datum) | |
1352 | dc_dcontext_t dcontext; | |
1353 | dc_word_t *kind; | |
1354 | dc_word_t *datum; | |
1355 | { | |
1356 | dc_error (((dc_dcontext_t)dcontext)->handle, | |
1357 | "dc_get_special_info is not yet implemented."); | |
1358 | } | |
1359 | ||
1360 | ||
1361 | ||
1362 | /* operations valid for all contexts (again) */ | |
1363 | ||
1364 | ||
1365 | dc_dcontext_t dc_previous_dcontext (dcontext) | |
1366 | dc_dcontext_t dcontext; | |
1367 | /* Return NULL if there is no previous context. */ | |
1368 | { | |
1369 | dc_dcontext_t old = (dc_dcontext_t) dcontext; | |
1370 | dcontext_info_t new; /* to serve as temporary storage only */ | |
1371 | tdesc_elem_t *tep; | |
1372 | dc_cr_data_t *cdp; | |
1373 | dc_word_t cfa; | |
1374 | int rsm; | |
1375 | dc_word_t offset; | |
1376 | dc_word_t rai; | |
1377 | int r; | |
1378 | ||
1379 | if (dc_return_address_state((dc_dcontext_t)old) == DC_INVALID) | |
1380 | dc_error (old->handle, "Return address is invalid."); | |
1381 | ||
1382 | if (dc_return_address((dc_dcontext_t)old) == 0) | |
1383 | return (dc_dcontext_t)NULL; /* end of the chain */ | |
1384 | ||
1385 | /* Copy over old contents. */ | |
1386 | new = *old; | |
1387 | ||
1388 | cfa = dc_frame_address(old); | |
1389 | /* Restore stack pointer. */ | |
1390 | new.reg_info[DC_REG_SP] = cfa; | |
1391 | SET_READABLE (new.reg_flags, DC_REG_SP); | |
1392 | ||
1393 | /* Invalidate temporary registers. */ | |
1394 | for (r = 1; r <= 13; r++) SET_INVALID (new.reg_flags, r); | |
1395 | ||
1396 | if (!old->code_reading) { | |
1397 | tep = old->info_ptr.tdesc_elem_ptr; | |
1398 | /* Restore preserved registers. */ | |
1399 | rsm = tep->info.register_save_mask; | |
1400 | offset = cfa + tep->info.register_save_offset; | |
1401 | for (r = 14; r <= 30; r++) { | |
1402 | if (bit_test(rsm, 30-r)) { | |
1403 | new.reg_info[r] = offset; | |
1404 | SET_WRITABLE (new.reg_flags, r); | |
1405 | offset += sizeof(dc_word_t); | |
1406 | } | |
1407 | } | |
1408 | ||
1409 | /* Set location from old return address. */ | |
1410 | rai = tep->info.return_address_info; | |
1411 | if (tep->info.return_address_info_discriminant) { | |
1412 | new.aux_info[DC_AUX_LOC] = cfa + rai; | |
1413 | SET_WRITABLE (new.aux_flags, DC_AUX_LOC); | |
1414 | } else { | |
1415 | new.aux_info[DC_AUX_LOC] = old->reg_info[rai]; | |
1416 | ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, old->reg_flags, rai); | |
1417 | } | |
1418 | } else { | |
1419 | cdp = old->info_ptr.cr_data_ptr; | |
1420 | ||
1421 | /* Restore preserved registers. */ | |
1422 | for (r = 14; r <= 30; r++) { | |
1423 | if (bit_test(cdp->saved,r)) { | |
1424 | if (bit_test(cdp->how,r)){ /* saved in the frame */ | |
1425 | new.reg_info[r] = cfa+cdp->where[r]; | |
1426 | SET_WRITABLE (new.reg_flags, r); | |
1427 | } else { /* saved in the in a register */ | |
1428 | new.reg_info[r] = dc_general_register(old,cdp->where[r]); | |
1429 | ASSIGN_RSTATE (new.aux_flags, r, old->reg_flags, cdp->where[r]); | |
1430 | } | |
1431 | } /* not saved, therefore, already valid , no else*/ | |
1432 | } | |
1433 | ||
1434 | /* Set location from old return address. */ | |
1435 | if (bit_test(cdp->saved,DC_REG_RA)) { | |
1436 | if (bit_test(cdp->how,DC_REG_RA)){ /* saved in the frame */ | |
1437 | new.aux_info[DC_AUX_LOC] = | |
1438 | new.reg_info[DC_REG_RA] = cfa+cdp->where[DC_REG_RA]; | |
1439 | SET_WRITABLE (new.reg_flags, DC_REG_RA); | |
1440 | SET_WRITABLE (new.aux_flags, DC_AUX_LOC); | |
1441 | } else { /* saved in the in a register */ | |
1442 | new.reg_info[DC_REG_RA] = | |
1443 | new.aux_info[DC_AUX_LOC] = | |
1444 | dc_general_register(old,cdp->where[DC_REG_RA]); | |
1445 | ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, | |
1446 | old->reg_flags, cdp->where[DC_REG_RA]); | |
1447 | } | |
1448 | } else { /* not saved, therefore, already valid , set DC_AUX_LOC only*/ | |
1449 | new.aux_info[DC_AUX_LOC] = | |
1450 | dc_general_register(old,DC_REG_RA); | |
1451 | ASSIGN_RSTATE (new.aux_flags, DC_AUX_LOC, | |
1452 | old->reg_flags, DC_REG_RA); | |
1453 | } | |
1454 | } | |
1455 | ||
1456 | /* Invalidate instruction pointers. */ | |
1457 | SET_INVALID (new.aux_flags, DC_AUX_SXIP); | |
1458 | SET_INVALID (new.aux_flags, DC_AUX_SNIP); | |
1459 | SET_INVALID (new.aux_flags, DC_AUX_SFIP); | |
1460 | ||
1461 | /* No change to FCR registers. */ | |
1462 | ||
1463 | /* No change to PSR register. */ | |
1464 | ||
1465 | return dc_make_dcontext ((dc_handle_t)new.handle, | |
1466 | new.reg_info, new.reg_flags, | |
1467 | new.aux_info, new.aux_flags, new.loc_exact, | |
1468 | new.psr_info, new.psr_ind, new.psr_flags); | |
1469 | } | |
1470 | ||
1471 | ||
1472 | ||
1473 | /* extensions for nonlocal goto */ | |
1474 | ||
1475 | #if 0 | |
1476 | ||
1477 | typedef | |
1478 | struct label { | |
1479 | ??? | |
1480 | } label_t; | |
1481 | ||
1482 | ||
1483 | label_t dc_make_label (dcontext, location) | |
1484 | dc_dcontext_t dcontext; | |
1485 | dc_word_t location; | |
1486 | { | |
1487 | } | |
1488 | ||
1489 | #endif | |
1490 | ||
1491 | /* procedure for reading code */ | |
1492 | ||
1493 | dc_read_code(loc,dc,map_info_in,cdp) | |
1494 | dc_word_t loc; | |
1495 | dc_dcontext_t dc; | |
1496 | dc_cr_data_t *cdp; | |
1497 | dc_map_info_in_t map_info_in; | |
1498 | { | |
1499 | dc_map_info_out_t map_info_out; | |
1500 | dc_word_t pc; | |
1501 | dc_boolean_t found_branch=DC_FALSE; | |
1502 | dc_word_t instr; | |
1503 | ||
1504 | (*dc->handle->map_fcn)(dc->handle->map_env,loc,map_info_in,&map_info_out); | |
1505 | if (map_info_out.flags & DC_MIO_ENTRY_POINT | |
1506 | && (!(map_info_in.flags & DC_MII_PRECEDING_TDESC_END) | |
1507 | || map_info_out.entry_point >= map_info_in.preceding_tdesc_end | |
1508 | || map_info_out.flags & DC_MIO_LITERAL_ENTRY_POINT)) { | |
1509 | dc_init_cr_data(cdp,(tdesc_elem_t *)NULL); | |
1510 | pc= map_info_out.entry_point; | |
1511 | } else if (map_info_in.flags & DC_MII_PRECEDING_TDESC_END) { | |
1512 | /**/ | |
1513 | /* tdesc_lookup gets the tep for the preceeding tdesc information | |
1514 | /* so we call it with one less than the preceding tdesc end since | |
1515 | /* tdesc information is exclusive of the ending address | |
1516 | /**/ | |
1517 | dc_init_cr_data(cdp, | |
1518 | dc_tdesc_lookup(map_info_in.preceding_tdesc_end-1, | |
1519 | ((dc_handle_t)dc->handle)->tdesc_table, | |
1520 | ((dc_handle_t)dc->handle)->tdesc_table_size, | |
1521 | &map_info_in)); | |
1522 | pc= map_info_in.preceding_tdesc_end; | |
1523 | } else { | |
1524 | dc_error (dc->handle, "Insufficient information for code reading."); | |
1525 | } | |
1526 | for (;;pc+=4) { | |
1527 | if (pc==loc) { | |
1528 | return (DC_TRUE); | |
1529 | } | |
1530 | instr= dc_read_word(dc->handle,pc); | |
1531 | found_branch= dc_decode_finds_branch(dc,instr); | |
1532 | if ((map_info_out.flags & DC_MIO_PROLOGUE_END) | |
1533 | && (pc==map_info_out.prologue_end)) { | |
1534 | break; | |
1535 | } | |
1536 | if (found_branch) { | |
1537 | if (DC_MIO_IMPLICIT_PROLOGUE_END & map_info_out.flags) { | |
1538 | break; | |
1539 | } else { | |
1540 | dc_error (dc->handle, "Found branch before end of prologue."); | |
1541 | } | |
1542 | } | |
1543 | } | |
1544 | if (!(map_info_out.flags & DC_MIO_LITERAL_EPILOGUE_START) | |
1545 | && (map_info_out.epilogue_start >= loc | |
1546 | || !(map_info_out.flags & DC_MIO_EPILOGUE_START))) { | |
1547 | return (DC_TRUE); | |
1548 | } | |
1549 | dc_correct_cr_data(cdp,dc->handle); | |
1550 | for (pc=map_info_out.epilogue_start;pc<loc;pc+=4) { | |
1551 | instr= dc_read_word(dc->handle,pc); | |
1552 | if (dc_decode_finds_branch(dc,instr)) { | |
1553 | return (DC_FALSE); | |
1554 | } | |
1555 | } | |
1556 | return (DC_TRUE); | |
1557 | ||
1558 | } | |
1559 | ||
1560 | ||
1561 | ||
1562 | dc_init_cr_data(cdp,tep) | |
1563 | dc_cr_data_t *cdp; | |
1564 | tdesc_elem_t *tep; | |
1565 | { | |
1566 | int reg; | |
1567 | dc_word_t rai; | |
1568 | dc_word_t raid; | |
1569 | dc_word_t rsm; | |
1570 | dc_word_t frpos; | |
1571 | ||
1572 | if (tep){ | |
1573 | ||
1574 | /* Start off with all registers undefined and none saved. */ | |
1575 | for (reg = 0; reg < DC_NUM_REG; reg++) { | |
1576 | cdp->reg_val[reg].reg = DC_UNDEF; | |
1577 | } | |
1578 | cdp->saved = 0; | |
1579 | ||
1580 | /* Overwrite with what tdesc element says. */ | |
1581 | ||
1582 | cdp->reg_val[tep->info.frame_address_register].reg = DC_REG_SP; | |
1583 | cdp->reg_val[tep->info.frame_address_register].off = | |
1584 | - tep->info.frame_address_offset; | |
1585 | ||
1586 | rai = tep->info.return_address_info; | |
1587 | raid = tep->info.return_address_info_discriminant; | |
1588 | if (raid || rai != DC_REG_RA) { | |
1589 | bit_set(cdp->saved,DC_REG_RA); | |
1590 | bit_assign(cdp->how,DC_REG_RA,raid); | |
1591 | cdp->where[DC_REG_RA] = rai; | |
1592 | } | |
1593 | ||
1594 | rsm = tep->info.register_save_mask; | |
1595 | frpos = tep->info.register_save_offset; | |
1596 | for (reg = 14; reg <= 30; reg++) { | |
1597 | if (bit_test(rsm, 30-reg)) { | |
1598 | bit_set(cdp->saved,reg); | |
1599 | bit_set(cdp->how,reg); | |
1600 | cdp->where[reg] = frpos; | |
1601 | frpos += sizeof(dc_word_t); | |
1602 | } else { | |
1603 | cdp->reg_val[reg].reg = reg; | |
1604 | cdp->reg_val[reg].off = 0; | |
1605 | } | |
1606 | } | |
1607 | ||
1608 | cdp->reg_val[0].reg = 0; /* guarantee what hardware does */ | |
1609 | cdp->reg_val[0].off = 0; | |
1610 | ||
1611 | } else { | |
1612 | /* Each register has its own initial value. */ | |
1613 | for (reg = 0; reg < DC_NUM_REG; reg++) { | |
1614 | cdp->reg_val[reg].reg = reg; | |
1615 | cdp->reg_val[reg].off = 0; | |
1616 | } | |
1617 | /* No register is yet saved. */ | |
1618 | cdp->saved = 0; | |
1619 | cdp->how = 0; | |
1620 | } | |
1621 | } | |
1622 | void dc_correct_cr_data(cdp,handle) | |
1623 | dc_cr_data_t *cdp; | |
1624 | dc_handle_t handle; | |
1625 | { | |
1626 | long sr,r; | |
1627 | dc_word_t save_regs = 0; /* registers used to save others */ | |
1628 | for (r = 1; r < DC_REG_SP; r++) { | |
1629 | if (bit_test(cdp->saved,r) && !bit_test(cdp->how,r)) { | |
1630 | sr = cdp->where[r]; | |
1631 | if (bit_test(save_regs,sr)) { | |
1632 | dc_error(handle, "Same register used to save two others."); | |
1633 | } | |
1634 | bit_set(save_regs,sr); | |
1635 | } | |
1636 | } | |
1637 | for (r = 1; r < DC_REG_FP; r++) { | |
1638 | if ((r < 14 || bit_test(cdp->saved,r)) && !bit_test(save_regs,r)) { | |
1639 | cdp->reg_val[r].reg = DC_UNDEF; | |
1640 | } | |
1641 | } | |
1642 | if (bit_test(cdp->saved,DC_REG_FP) && | |
1643 | cdp->reg_val[DC_REG_FP].reg == DC_REG_SP) { /* is r30 the far? */ | |
1644 | cdp->reg_val[DC_REG_SP].reg = DC_UNDEF; /* trash sp */ | |
1645 | } else if (cdp->reg_val[DC_REG_SP].reg == DC_REG_SP) { /* is r31 the far? */ | |
1646 | if (bit_test(cdp->saved,DC_REG_FP) && !bit_test(save_regs,DC_REG_FP)) { | |
1647 | cdp->reg_val[DC_REG_FP].reg = DC_UNDEF; /* trash r30 */ | |
1648 | } | |
1649 | } | |
1650 | } |