|
|
1.1 ! root 1: /*ident "%W%" */ ! 2: /************************************************************************** ! 3: Copyright (c) 1984 AT&T ! 4: All Rights Reserved ! 5: ! 6: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T ! 7: ! 8: The copyright notice above does not evidence any ! 9: actual or intended publication of such source code. ! 10: ! 11: *****************************************************************************/ ! 12: #include <task.h> ! 13: #include <stdio.h> ! 14: #include "hw_stack.h" ! 15: ! 16: // 3B frame fudger ! 17: ! 18: //Frames not self-describing! ! 19: //STACK GROWS UP ! 20: ! 21: #ifdef u3b ! 22: /* ! 23: * On the 3B20, the call instruction is call num,dst ! 24: * where num is the number of arguments to the function ! 25: * and dst is the address of the called function. ! 26: * There are 4 possible opcodes for the call instruction: ! 27: * 3 are optimizations possible when num can be represented in 4 bits ! 28: * (the usual case), and further depend on the addressing mode used. ! 29: * This code assumes that destination addresses will only be ! 30: * pc-relative, absolute, or absolute deferred. ! 31: */ ! 32: ! 33: const GEN_CALL = 0x78; ! 34: const OPT_GEN_CALL = 0x79; ! 35: const PC_REL_CALL = 0x77; ! 36: const IMM_CALL = 0xB9; ! 37: ! 38: const ABSOLUTE_DESC = 0x08; ! 39: const PC_REL_DESC = 0x06; ! 40: const ABSOLUTE_DEF_DESC = 0x09; ! 41: ! 42: #define IS_CALL_OPCODE(instr) \ ! 43: (((MACHINE_BYTE)(instr) == (MACHINE_BYTE)GEN_CALL) || \ ! 44: ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)OPT_GEN_CALL) || \ ! 45: ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)PC_REL_CALL) || \ ! 46: ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)IMM_CALL)) ! 47: ! 48: const N_CALL_INSTR_SIZES = 3; ! 49: short call_size[N_CALL_INSTR_SIZES] = {4, 6, 7}; ! 50: ! 51: #undef SAVE_OPERAND /* not needed for u3b */ ! 52: ! 53: /* src op is not important in decoding the call instruction on u3b */ ! 54: #define SRC_OP_DESC(instr) /* not needed for u3b */ ! 55: #define IS_LEGAL_SRC_OP() 1 ! 56: #undef SRC_OP_SIZE /* not needed for u3b */ ! 57: const OPCODE_SIZE = 1; ! 58: const OPERAND1_SIZE = 1; ! 59: ! 60: #define DST_OP_DESC(instr) \ ! 61: (((unsigned char *)(instr))[OPCODE_SIZE] & 0x0f) ! 62: ! 63: #define IS_LEGAL_DST_OP(desc) \ ! 64: (((desc) == ABSOLUTE_DESC) || \ ! 65: ((desc) == PC_REL_DESC) || \ ! 66: ((desc) == ABSOLUTE_DEF_DESC) \ ! 67: ) ! 68: #define HAS_LEGAL_OPERANDS(call_instr) \ ! 69: (IS_LEGAL_DST_OP((DST_OP_DESC(poss_callp))) || \ ! 70: (call_instr[0] == PC_REL_CALL)) ! 71: ! 72: ! 73: /* Given a pointer to a call instruction, ! 74: * yield a pointer to the called function */ ! 75: unsigned int ! 76: call_dst_ptr(unsigned char* callp) ! 77: { ! 78: int offset = 0; ! 79: // points past operand1 and/or descriptor to address or offset ! 80: unsigned char* dst_op_p = callp + OPCODE_SIZE + OPERAND1_SIZE; ! 81: switch(*callp) { ! 82: case PC_REL_CALL: // 16-bit pc-relative address ! 83: offset = dst_op_p[0] << 8 | dst_op_p[1]; ! 84: if (callp[1] & 0x80) // negative offset ! 85: offset = -(offset); ! 86: unsigned char* next_pc = callp + 4; // relative to NEXT pc ! 87: return (unsigned int)((short*)next_pc + offset); ! 88: case GEN_CALL: ! 89: case OPT_GEN_CALL: ! 90: switch(DST_OP_DESC(callp)) { ! 91: case ABSOLUTE_DESC: // 24-bit absolute address ! 92: return (dst_op_p[0] << 20 | ! 93: dst_op_p[1] << 12 | ! 94: dst_op_p[2] << 4 | ! 95: dst_op_p[3] >> 4 ) & 0x00ffffff; ! 96: case ABSOLUTE_DEF_DESC: // 24-bit absolute deferred address ! 97: int* addr_p = ! 98: (int*) ((dst_op_p[0] << 20 | ! 99: dst_op_p[1] << 12 | ! 100: dst_op_p[2] << 4 | ! 101: dst_op_p[3] >> 4 ) & 0x00ffffff); ! 102: return (unsigned int)(*addr_p); ! 103: case PC_REL_DESC: // 24-bit pc-relative address ! 104: offset = (dst_op_p[0] << 20 | ! 105: dst_op_p[1] << 12 | ! 106: dst_op_p[2] << 4 | ! 107: dst_op_p[3] >> 4 ); ! 108: if (dst_op_p[0] & 0x08) // negative offset ! 109: offset |= 0xff000000; ! 110: else // positive offset ! 111: offset &= 0x00ffffff; ! 112: return (unsigned int)(callp + offset); ! 113: default: // illegal descriptor ! 114: object::task_error(E_FUNCS, (object*)0); ! 115: } ! 116: case IMM_CALL: // 24-bit immediate address ! 117: return (dst_op_p[0] << 20 | ! 118: dst_op_p[1] << 12 | ! 119: dst_op_p[2] << 4 | ! 120: dst_op_p[3] >> 4 ) & 0x00ffffff; ! 121: default: // illegal call instruction ! 122: object::task_error(E_FUNCS, (object*)0); ! 123: } ! 124: } /* call_dst_ptr */ ! 125: ! 126: ! 127: #else /* m32: u3b2, u3b5, u3b15 */ ! 128: ! 129: /* ! 130: * On the 3B2, the call instruction is CALL src,dst ! 131: * where src is the address of the new ap (where the args were ! 132: * already pushed on the stack) and dst is the address of the ! 133: * called function. src and dst can be various lengths: ! 134: * src will be a byte, halfword, or word displacement ! 135: * and dst will be absolute, or be a byte, halfword, or word displacement. ! 136: * Byte displacement = 2 bytes, halfword = 3, word = 5; ! 137: * the opcode = 1 byte; absolute = 5 bytes--12 possible combinations ! 138: * and 6 possible instr lengths. ! 139: */ ! 140: ! 141: ! 142: #define IS_CALL_OPCODE(instr) ((MACHINE_BYTE)(instr) == (MACHINE_BYTE)0x2c) ! 143: ! 144: const BYTE_DISPL = 0xC0; ! 145: const HALFWORD_DISPL = 0xA0; ! 146: const WORD_DISPL = 0x80; ! 147: const ABSOLUTE = 0x70; ! 148: const REG_SP = 0x0C; ! 149: const REG_PC = 0x0F; ! 150: ! 151: const N_CALL_INSTR_SIZES = 6; ! 152: short call_size[N_CALL_INSTR_SIZES] = {5, 6, 7, 8, 9, 11}; ! 153: ! 154: /* CALL's src operand descriptor needed to determine size of src operand */ ! 155: #define SRC_OP_DESC(instr) (((unsigned char *)(instr))[1]) ! 156: #define SRC_OP_SIZE(desc) \ ! 157: ((MODE_FIELD(desc) == BYTE_DISPL) ? 2 : \ ! 158: (MODE_FIELD(desc) == HALFWORD_DISPL) ? 3 : \ ! 159: (MODE_FIELD(desc) == WORD_DISPL) ? 5 : \ ! 160: ((object::task_error(E_FUNCS, (object*)0))) \ ! 161: ) ! 162: const OPCODE_SIZE = 1; ! 163: const DESC_SIZE = 1; ! 164: ! 165: #define DST_OP_DESC(instr) \ ! 166: (((unsigned char *)(instr)) \ ! 167: [OPCODE_SIZE + SRC_OP_SIZE(SRC_OP_DESC(instr))]) ! 168: #define MODE_FIELD(desc) ((desc) & 0xf0) ! 169: #define REG_FIELD(desc) ((desc) & 0x0f) ! 170: ! 171: #define IS_LEGAL_SRC_OP(desc) /* assumes sp-relative displ */ \ ! 172: (((MODE_FIELD(desc) == BYTE_DISPL) || \ ! 173: (MODE_FIELD(desc) == HALFWORD_DISPL) || \ ! 174: (MODE_FIELD(desc) == WORD_DISPL) \ ! 175: ) && (REG_FIELD(desc) == REG_SP) \ ! 176: ) ! 177: /* destination displacement is probably pc-relative, but we don't ! 178: * make that assumption. It could be a call through a function pointer. ! 179: */ ! 180: #define IS_LEGAL_DST_OP(desc) \ ! 181: ((MODE_FIELD(desc) == BYTE_DISPL) || \ ! 182: (MODE_FIELD(desc) == HALFWORD_DISPL) || \ ! 183: (MODE_FIELD(desc) == WORD_DISPL) || \ ! 184: ((MODE_FIELD(desc) == ABSOLUTE) && (REG_FIELD(desc) == REG_PC))\ ! 185: ) ! 186: #define HAS_LEGAL_OPERANDS(call_instr) \ ! 187: (IS_LEGAL_SRC_OP((SRC_OP_DESC(call_instr))) \ ! 188: && IS_LEGAL_DST_OP((DST_OP_DESC(call_instr)))) ! 189: ! 190: ! 191: /* Given a pointer to a call instruction, yield a pointer to ! 192: * the called function */ ! 193: unsigned int ! 194: call_dst_ptr(unsigned char* callp) ! 195: { ! 196: int sop_size = SRC_OP_SIZE(SRC_OP_DESC(callp)); ! 197: unsigned char* dst_op_p = ! 198: /* points past the dst desc, to addr or offset */ ! 199: callp + OPCODE_SIZE + sop_size + DESC_SIZE; ! 200: int offset = 0; // offset for displacement modes ! 201: switch(MODE_FIELD(DST_OP_DESC(callp))) { ! 202: case BYTE_DISPL: ! 203: offset = dst_op_p[0]; ! 204: if(*dst_op_p & 0x80) { ! 205: /* negative--do sign extension for offset */ ! 206: offset |= 0xffffff00; ! 207: } ! 208: return (unsigned int)(callp + offset); ! 209: case HALFWORD_DISPL: ! 210: // bytes are in reverse order, must flip positions ! 211: offset = dst_op_p[0] | dst_op_p[1] << 8; ! 212: if(dst_op_p[1] & 0x80) { ! 213: /* negative--do sign extension for offset */ ! 214: offset |= 0xffff0000; ! 215: } ! 216: return (unsigned int)(callp + offset); ! 217: case WORD_DISPL: ! 218: // bytes are in reverse order, must flip positions ! 219: offset = dst_op_p[0] | ! 220: dst_op_p[1] << 8 | ! 221: dst_op_p[2] << 16 | ! 222: dst_op_p[3] << 24; ! 223: /* don't need sign extension */ ! 224: return (unsigned int)(callp + offset); ! 225: case ABSOLUTE: ! 226: return ! 227: dst_op_p[0] | ! 228: dst_op_p[1] << 8 | ! 229: dst_op_p[2] << 16 | ! 230: dst_op_p[3] << 24; ! 231: default: ! 232: object::task_error(E_FUNCS, (object*)0); ! 233: } ! 234: } /* call_dst_ptr */ ! 235: ! 236: #endif /* m32: u3b2, u3b5, u3b15 */ ! 237: ! 238: FrameLayout::FrameLayout(int* fp) ! 239: { ! 240: /* ! 241: * Given a frame pointer, find the number of regs saved in the frame. ! 242: * The idea is that the instruction immediately before the return pc ! 243: * is the function call, and contains a pointer to the first ! 244: * instruction in the function denoted by the fp, which will be a save ! 245: * instruction. We can decode the save instruction to find how many ! 246: * registers were saved. ! 247: */ ! 248: ! 249: int* return_pc = (int*)OLD_PC(fp); ! 250: ! 251: unsigned char* callp = NULL; ! 252: /* Because this method is nondeterministic, try all combinations ! 253: instead of stopping when one fits */ ! 254: for(int i = 0; i < N_CALL_INSTR_SIZES; i++) { ! 255: unsigned char* poss_callp = ! 256: (unsigned char *)return_pc - call_size[i]; ! 257: if ((IS_CALL_OPCODE(*poss_callp)) ! 258: && HAS_LEGAL_OPERANDS(poss_callp)) { ! 259: if(!callp) callp = poss_callp; ! 260: else { // try some heuristics to disambiguate ! 261: // (Don't try to dereference dst ptr ! 262: // until sure, or necessary to disambiguate, ! 263: // to avoid unnecessary core dumps.) ! 264: // If first callp dst points to a save, ! 265: // assume that is the instruction we want. ! 266: if (!IS_SAVE_OPCODE( ! 267: *(unsigned char *)(call_dst_ptr(callp))) ) { ! 268: if (IS_SAVE_OPCODE( ! 269: *(unsigned char *)(call_dst_ptr(poss_callp))) ) { ! 270: callp = poss_callp; ! 271: } else { ! 272: // neither is right, go on ! 273: callp = 0; ! 274: } ! 275: ! 276: } ! 277: } ! 278: } ! 279: } ! 280: if (callp == NULL) object::task_error(E_FUNCS, (object*)0); //No match! ! 281: unsigned int func_addr = call_dst_ptr(callp); ! 282: if (!(IS_SAVE_OPCODE( *(unsigned char *)func_addr) )) ! 283: object::task_error(E_FUNCS, (object*)0); ! 284: n_saved = N_SAVED_REGS(func_addr); ! 285: } ! 286: ! 287: /* ! 288: * Fudge frame of function-defined-by-f_fp (called "f" below) ! 289: * so that that function returns to its grandparent, ! 290: * in particular, so a parent task returns to the function that ! 291: * called the derived constructor (de_ctor), skipping de_ctor; ! 292: * the child will return to the derived constructor, which is its "main." ! 293: * To do this we will overwrite the old fp, ap, and pc (those saved by ! 294: * f) with the old-old ones (those saved by f's caller), ! 295: * and we will overwrite the register save area with registers saved by ! 296: * f's caller (referred to as "skip" below). ! 297: * ! 298: * There are 2 register-save cases to deal with: ! 299: * 1. skip_n_saved <= f_n_saved ! 300: * 2. skip_n_saved > f_n_saved ! 301: * ! 302: * These are handled as follows: ! 303: * 1. copy the saved skip_regs over the corresponding f_regs, ! 304: * leaving any additional saved f_regs intact. ! 305: * f's restore instruction will be correct. ! 306: * 2. f's restore instruction will restore too few regs, must take special ! 307: * care to see that the extras are restored properly. ! 308: * -Copy saved skip_regs over any corresponding f_regs, ! 309: * -If fudge_return saved more regs than f did, then ! 310: * copy saved extra saved skip_regs over any corresponding fudge_regs, ! 311: * -If more extra skip_regs (not saved by either f or fudge_return, ! 312: * and therefore not used by either) remain, restore them explicitly. ! 313: * They will not be disturbed by the return from fudge_return or f, ! 314: */ ! 315: void ! 316: task::fudge_return(int* f_fp) ! 317: { ! 318: register int* fp = f_fp; // fp of frame-to-be-fudged ! 319: FrameLayout lo(fp); // frame to be fudged ! 320: register int* skip_fp = (int*)OLD_FP(fp); // fp for f's caller (skip) ! 321: FrameLayout skip_lo(skip_fp); // frame for skip ! 322: ! 323: OLD_PC(fp) = OLD_PC(skip_fp); ! 324: OLD_AP(fp) = OLD_AP(skip_fp); ! 325: OLD_FP(fp) = OLD_FP(skip_fp); ! 326: ! 327: // finally copy saved regs ! 328: register int* from = LAST_SAVED_REG_P(skip_fp, skip_lo.n_saved); ! 329: register int* to = LAST_SAVED_REG_P(fp, lo.n_saved); ! 330: register int i; ! 331: if(lo.n_saved >= skip_lo.n_saved) { ! 332: // copy the saved skip regs over the corresponding f regs, ! 333: // leaving any additional saved f regs intact. ! 334: for(i = skip_lo.n_saved; i > 0; i--) { ! 335: *to-- = *from--; ! 336: } ! 337: } else { // lo.n_saved < skip_lo.n_saved--take care! ! 338: // copy the saved skip regs over any corresponding ! 339: // f regs. ! 340: for(i = lo.n_saved; i > 0; i--) { ! 341: *to-- = *from--; ! 342: } ! 343: int extra = skip_lo.n_saved - lo.n_saved; ! 344: // If fudge_return saved more regs than f, extra skip_regs ! 345: // should be copied over any corresponding fudge_return regs. ! 346: int* fr_fp = FP(); // fp for fudge_return ! 347: FrameLayout fr_lo(fr_fp); // frame for fudge_return ! 348: if (fr_lo.n_saved >= lo.n_saved) { ! 349: to = LAST_SAVED_REG_P(fr_fp, fr_lo.n_saved) - lo.n_saved; ! 350: int n; ! 351: int d = fr_lo.n_saved - lo.n_saved; ! 352: if (d >= extra) { // room for all extra skip_regs ! 353: n = extra; ! 354: } else { ! 355: n = d; ! 356: } ! 357: for(i = n; i > 0; i--) { ! 358: *to-- = *from--; ! 359: extra--; ! 360: } ! 361: } ! 362: if (extra) { // Remaining skip regs must be explicitly restored. ! 363: int r = skip_lo.n_saved - extra + 1; ! 364: for (i = extra; i > 0; i--) { ! 365: switch (r++) { ! 366: case 6: ! 367: set_r3(from); ! 368: from--; ! 369: break; ! 370: case 5: ! 371: set_r4(from); ! 372: from--; ! 373: break; ! 374: case 4: ! 375: set_r5(from); ! 376: from--; ! 377: break; ! 378: case 3: ! 379: set_r6(from); ! 380: from--; ! 381: break; ! 382: case 2: ! 383: set_r7(from); ! 384: from--; ! 385: break; ! 386: case 1: ! 387: set_r8(from); ! 388: from--; ! 389: break; ! 390: } ! 391: } ! 392: } ! 393: } ! 394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.