|
|
1.1 ! root 1: #include "task.h" ! 2: #include <assert.h> ! 3: #include <stdio.h> ! 4: ! 5: // 3B frame fudger ! 6: ! 7: //Frames not self-describing! ! 8: //STACK GROWS UP ! 9: ! 10: typedef unsigned char MACHINE_BYTE; ! 11: ! 12: #ifdef u3b ! 13: ! 14: #define OLD_FP(fp) ( *( (int*)(fp) - 11 ) ) ! 15: #define OLD_AP(fp) ( *( (int*)(fp) - 12 ) ) ! 16: #define OLD_PC(fp) ( *( (int*)(fp) - 13 ) ) ! 17: #define FIRST_SAVED_REG_P(fp) ( (int*)(fp) - 6 ) ! 18: ! 19: const CALL_OPCODE = ((MACHINE_BYTE)0x78); ! 20: /* SAK: really: 0x78 | 0x79 | 0xB9 | 0x77 */ ! 21: const SAVE_OPCODE = ((MACHINE_BYTE)0x7A); ! 22: const BYTE_DISPL = 0xC0; /* SAK: WRONG for u3b! */ ! 23: const HALFWORD_DISPL = 0xA0; /* SAK: WRONG for u3b! */ ! 24: const WORD_DISPL = 0x80; /* SAK: WRONG for u3b! */ ! 25: const ABSOLUTE = 0x70; /* SAK: WRONG for u3b! */ ! 26: ! 27: const N_CALL_INSTR_SIZES = 6; /* SAK: WRONG for u3b! */ ! 28: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11}; /* SAK: WRONG for u3b! */ ! 29: ! 30: /* SAK: SAVE_OPERAND(instr) not needed for u3b */ ! 31: ! 32: /* Given a pointer to a save instruction, yield the number of registers saved */ ! 33: #define N_SAVED_REGS(instr) (((char *)(instr))[1] >> 4) ! 34: ! 35: /* CALL's src operand descriptor needed to determine size of src operand */ ! 36: #define SRC_OP_DESC(instr) (((char *)(instr))[1] & 0xf0) ! 37: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\ ! 38: (((desc) == BYTE_DISPL) ? 2 : \ ! 39: ((desc) == HALFWORD_DISPL) ? 3 : \ ! 40: ((desc) == WORD_DISPL) ? 5 : \ ! 41: ((((object*)0)->task_error(E_FRAMES))) \ ! 42: ) ! 43: const OPCODE_SIZE = 1; ! 44: const DESC_SIZE = 1; ! 45: ! 46: /* SAK: WRONG for u3b! */ ! 47: #define DST_OP_DESC(instr) \ ! 48: (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0) ! 49: ! 50: /* SAK: WRONG for u3b! */ ! 51: #define IS_LEGAL_SRC_OP(desc) \ ! 52: (((desc) == BYTE_DISPL) || \ ! 53: ((desc) == HALFWORD_DISPL) || \ ! 54: ((desc) == WORD_DISPL) \ ! 55: ) ! 56: /* SAK: WRONG for u3b! */ ! 57: #define IS_LEGAL_DST_OP(desc) \ ! 58: (((desc) == BYTE_DISPL) || \ ! 59: ((desc) == HALFWORD_DISPL) || \ ! 60: ((desc) == WORD_DISPL) || \ ! 61: ((desc) == ABSOLUTE) \ ! 62: ) ! 63: ! 64: ! 65: #else /* m32: u3b2, u3b5, u3b15 */ ! 66: #define OLD_FP(fp) ( *( (int*)(fp) - 7 ) ) ! 67: #define OLD_AP(fp) ( *( (int*)(fp) - 8 ) ) ! 68: #define OLD_PC(fp) ( *( (int*)(fp) - 9 ) ) ! 69: #define FIRST_SAVED_REG_P(fp) ( (int*)(fp) - 6 ) ! 70: /* ! 71: * On the 3B2, the call instruction is CALL src,dst ! 72: * where src is the address of the new ap (where the args were ! 73: * already pushed on the stack) and dst is the address of the ! 74: * called function. src and dst can be various lengths: ! 75: * src will be a byte, halfword, or word displacement ! 76: * and dst will be absolute, or be a byte, halfword, or word displacement. ! 77: * Byte displacement = 2 bytes, halfword = 3, word = 5; the opcode = 1 byte; ! 78: * absolute = 5 bytes--12 possible combinations and 6 possible instr lengths. ! 79: */ ! 80: ! 81: ! 82: const CALL_OPCODE = ((MACHINE_BYTE)0x2c); ! 83: const SAVE_OPCODE = ((MACHINE_BYTE)0x10); ! 84: const BYTE_DISPL = 0xC0; ! 85: const HALFWORD_DISPL = 0xA0; ! 86: const WORD_DISPL = 0x80; ! 87: const ABSOLUTE = 0x70; ! 88: ! 89: const N_CALL_INSTR_SIZES = 6; ! 90: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11}; ! 91: ! 92: #define SAVE_OPERAND(instr) (((char *)(instr))[1] & 0xf) ! 93: ! 94: /* Given a pointer to a save instruction, yield the number of registers saved */ ! 95: #define N_SAVED_REGS(instr) (8 - SAVE_OPERAND(instr) + 1) ! 96: ! 97: /* CALL's src operand descriptor needed to determine size of src operand */ ! 98: #define SRC_OP_DESC(instr) (((char *)(instr))[1] & 0xf0) ! 99: #define SRC_OP_SIZE(desc) /* assumes sp-relative displacement */\ ! 100: (((desc) == BYTE_DISPL) ? 2 : \ ! 101: ((desc) == HALFWORD_DISPL) ? 3 : \ ! 102: ((desc) == WORD_DISPL) ? 5 : \ ! 103: ((((object*)0)->task_error(E_FRAMES))) \ ! 104: ) ! 105: const OPCODE_SIZE = 1; ! 106: const DESC_SIZE = 1; ! 107: ! 108: #define DST_OP_DESC(instr) \ ! 109: (((char *)(instr))[OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))] & 0xf0) ! 110: ! 111: #define IS_LEGAL_SRC_OP(desc) \ ! 112: (((desc) == BYTE_DISPL) || \ ! 113: ((desc) == HALFWORD_DISPL) || \ ! 114: ((desc) == WORD_DISPL) \ ! 115: ) ! 116: #define IS_LEGAL_DST_OP(desc) \ ! 117: (((desc) == BYTE_DISPL) || \ ! 118: ((desc) == HALFWORD_DISPL) || \ ! 119: ((desc) == WORD_DISPL) || \ ! 120: ((desc) == ABSOLUTE) \ ! 121: ) ! 122: ! 123: /* Given a pointer to a call instruction, yield a pointer to the called function */ ! 124: unsigned int ! 125: call_dst_ptr(unsigned char* callp) ! 126: { ! 127: int sop_size = SRC_OP_SIZE(SRC_OP_DESC(callp)); ! 128: unsigned char* dst_op_p = /* points past the dst desc, to addr or offset */ ! 129: callp + OPCODE_SIZE + sop_size + DESC_SIZE; ! 130: int offset; // offset for displacement modes ! 131: switch(DST_OP_DESC(callp)) { ! 132: case BYTE_DISPL: ! 133: offset = dst_op_p[0]; ! 134: if(*dst_op_p & 0x80) { /* negative--do sign extension for offset */ ! 135: offset |= 0xffffff00; ! 136: } ! 137: return (unsigned int)(callp + offset); ! 138: case HALFWORD_DISPL: ! 139: // bytes are in reverse order, must flip positions ! 140: offset = dst_op_p[0] | dst_op_p[1] << 8; ! 141: if(dst_op_p[1] & 0x80) { /* negative--do sign extension for offset */ ! 142: offset |= 0xffff0000; ! 143: } ! 144: return (unsigned int)(callp + offset); ! 145: case WORD_DISPL: ! 146: // bytes are in reverse order, must flip positions ! 147: offset = dst_op_p[0] | ! 148: dst_op_p[1] << 8 | ! 149: dst_op_p[2] << 16 | ! 150: dst_op_p[3] << 24; ! 151: /* don't need sign extension */ ! 152: return (unsigned int)(callp + offset); ! 153: case ABSOLUTE: ! 154: return ! 155: dst_op_p[0] | ! 156: dst_op_p[1] << 8 | ! 157: dst_op_p[2] << 16 | ! 158: dst_op_p[3] << 24; ! 159: default: ! 160: ((object*)0)->task_error(E_FRAMES); ! 161: } ! 162: } ! 163: ! 164: ! 165: #endif ! 166: ! 167: ! 168: struct FrameLayout { ! 169: short n_saved; // number of registers saved in this frame. ! 170: // (3B's don't have masks of regs saved) ! 171: FrameLayout(int*); // called with frame pointer ! 172: }; ! 173: ! 174: FrameLayout::FrameLayout(int* fp) ! 175: { ! 176: /* ! 177: * Given a frame pointer, find the number of regs saved in the frame. ! 178: * The idea is that the instruction immediately before the return pc ! 179: * is the function call, and contains a pointer to the first instruction ! 180: * in the function denoted by the fp, which will be a save instruction. ! 181: * We can decode the save instruction to find how many registers ! 182: * were saved. ! 183: */ ! 184: ! 185: int* return_pc = (int*)OLD_PC(fp); ! 186: ! 187: char* callp = NULL; ! 188: /* Because this method is nondeterministic, try all combinations ! 189: instead of stopping when one fits */ ! 190: for(int i = 0; i < N_CALL_INSTR_SIZES; i++) { ! 191: char* poss_callp = (char *)return_pc - call_size[i]; ! 192: if ((*poss_callp == CALL_OPCODE) ! 193: && IS_LEGAL_SRC_OP((SRC_OP_DESC(poss_callp))) ! 194: && IS_LEGAL_DST_OP((DST_OP_DESC(poss_callp)))) { ! 195: if(!callp) callp = poss_callp; ! 196: else ((object*)0)->task_error(E_FRAMES); //ambiguous; can't tell which ! 197: //is real call. ! 198: } ! 199: } ! 200: if (callp == NULL) ((object*)0)->task_error(E_FRAMES); //No match! ! 201: assert( *(char *)(call_dst_ptr(callp)) == SAVE_OPCODE); ! 202: n_saved = N_SAVED_REGS(call_dst_ptr(callp)); ! 203: } ! 204: ! 205: /* ! 206: * fix a frame so that it returns like the arg ! 207: * The idea is that task_fp points to the task::task() stack frame which ! 208: * contains all the saved registers. t_framep points to the stack frame ! 209: * that contains the return address and old fp (and perhaps some registers). ! 210: * fill the frame pointed to by t_framep with the registers from task_fp. ! 211: */ ! 212: void ! 213: task::fudge_return(int* task_fp, int offset, task* next) ! 214: { ! 215: int* fp = t_framep + offset; ! 216: task_fp += offset; // in case this is SHARED ! 217: FrameLayout this_lo(fp); ! 218: FrameLayout task_lo(task_fp); ! 219: if (task_lo.n_saved != 6) // task::task() saves all regs ! 220: task_error(E_FUDGE); ! 221: // copy any saved registers from this to task frame ! 222: register int* task_rp = FIRST_SAVED_REG_P(task_fp) + ! 223: task_lo.n_saved - this_lo.n_saved; ! 224: register int* this_rp = FIRST_SAVED_REG_P(fp); ! 225: register int count; ! 226: for (count = this_lo.n_saved; count--; ) ! 227: *task_rp++ = *this_rp++; ! 228: // next copy all the registers from the task frame to this ! 229: task_rp = FIRST_SAVED_REG_P(task_fp); ! 230: this_rp = FIRST_SAVED_REG_P(fp); ! 231: for (count = task_lo.n_saved; count--; ) ! 232: *this_rp++ = *task_rp++; ! 233: if (next) next->restore(); ! 234: } ! 235: ! 236:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.