/* Copy instruction from instruction to internal format. Return 0 on success, * 1 on error. Assume, that both arguments are not NULL. */ u32_t get_instruction94(PyObject *src, insn_t *insn) { PyObject *tmp; u32_t opcode; u32_t modifier; u32_t amode; u32_t bmode; tmp = PyObject_GetAttrString(src, "opcode"); if (tmp == NULL) { return 1; } if (!check_py3long_or_py2int(tmp)) { Py_DECREF(tmp); return 1; } opcode = py3long_or_py2int_as_long(tmp); Py_DECREF(tmp); tmp = PyObject_GetAttrString(src, "modifier"); if (tmp == NULL) { return 1; } if (!check_py3long_or_py2int(tmp)) { Py_DECREF(tmp); return 1; } modifier = py3long_or_py2int_as_long(tmp); Py_DECREF(tmp); tmp = PyObject_GetAttrString(src, "amode"); if (tmp == NULL) { return 1; } if (!check_py3long_or_py2int(tmp)) { Py_DECREF(tmp); return 1; } amode = py3long_or_py2int_as_long(tmp); Py_DECREF(tmp); tmp = PyObject_GetAttrString(src, "bmode"); if (tmp == NULL) { return 1; } if (!check_py3long_or_py2int(tmp)) { Py_DECREF(tmp); return 1; } bmode = py3long_or_py2int_as_long(tmp); Py_DECREF(tmp); insn->insn = INSN(opcode, modifier, amode, bmode); tmp = PyObject_GetAttrString(src, "afield"); if (tmp == NULL) { return 1; } if (!check_py3long_or_py2int(tmp)) { Py_DECREF(tmp); return 1; } insn->a = py3long_or_py2int_as_long(tmp); Py_DECREF(tmp); tmp = PyObject_GetAttrString(src, "bfield"); if (tmp == NULL) { return 1; } if (!check_py3long_or_py2int(tmp)) { Py_DECREF(tmp); return 1; } insn->b = py3long_or_py2int_as_long(tmp); Py_DECREF(tmp); return 0; }
static inline char* nextInsn(uint32_t* insn) { return INSN(insn + 1); }
// mips_build_intervals: build intervals for the range [beg_insn, // end_insn). Returns the first interval if retFirst is true, // otherwise returns the last. static UNW_INTERVAL_t mips_build_intervals(uint32_t* beg_insn, uint32_t* end_insn, bool retFirst, int verbose) { UNW_INTERVAL_t beg_ui = NEW_UI(INSN(beg_insn), FrmTy_SP, FrmFlg_RAReg, 0, unwarg_NULL, MIPS_REG_RA, NULL); UNW_INTERVAL_t ui = beg_ui; UNW_INTERVAL_t nxt_ui = UNW_INTERVAL_NULL; // canonical intervals UNW_INTERVAL_t canon_ui = beg_ui; UNW_INTERVAL_t canonSP_ui = beg_ui; UNW_INTERVAL_t canonFP_ui = UNW_INTERVAL_NULL; // currently not needed int fp_saved_reg = 0; uint32_t* cur_insn = beg_insn; while (cur_insn < end_insn) { //TMSG(INTV, "insn: 0x%x [%p,%p)", *cur_insn, cur_insn, end_insn); //-------------------------------------------------- // 1. SP-frames // // SP-frame --> SP-frame: alloc/dealloc constant-sized frame // FP-frame --> FP-frame: additional storage [UNCOMMON] //-------------------------------------------------- if (isAdjustSPByConst(*cur_insn)) { int sp_arg, ra_arg; if (UI_FLD(ui,ty) == FrmTy_SP) { //checkUI(UI_ARG(ui), FrmTy_SP, cur_insn); int amnt = getAdjustSPByConstAmnt(*cur_insn); sp_arg = UI_FLD(ui,sp_arg) + amnt; checkSPOfst(&sp_arg, UI_FLD(ui,sp_arg)); ra_arg = UI_FLD(ui,ra_arg); if (!frameflg_isset(UI_FLD(ui,flgs), FrmFlg_RAReg)) { ra_arg += amnt; checkSPOfst(&ra_arg, UI_FLD(ui,ra_arg)); } } else { sp_arg = UI_FLD(ui,sp_arg); ra_arg = UI_FLD(ui,ra_arg); } nxt_ui = NEW_UI(nextInsn(cur_insn), UI_FLD(ui,ty), UI_FLD(ui,flgs), sp_arg, UI_FLD(ui,fp_arg), ra_arg, ui); ui = nxt_ui; } //-------------------------------------------------- // SP-frame --> SP-frame: store RA/FP // *** canonical frame *** //-------------------------------------------------- else if (isStoreRegInFrame(*cur_insn, MIPS_REG_SP, MIPS_REG_RA)) { checkUI(UI_ARG(ui), FrmTy_SP, cur_insn); // store return address int ra_arg = getStoreRegInFrameOffset(*cur_insn); int16_t flgs = UI_FLD(ui,flgs); frameflg_unset(&flgs, FrmFlg_RAReg); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_SP, flgs, UI_FLD(ui,sp_arg), UI_FLD(ui,fp_arg), ra_arg, ui); ui = nxt_ui; canon_ui = canonSP_ui = nxt_ui; } else if (isStoreRegInFrame(*cur_insn, MIPS_REG_SP, MIPS_REG_FP)) { checkUI(UI_ARG(ui), FrmTy_SP, cur_insn); // store frame pointer (N.B. fp may be used as saved reg s8) int fp_arg = getStoreRegInFrameOffset(*cur_insn); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_SP, UI_FLD(ui,flgs), UI_FLD(ui,sp_arg), fp_arg, UI_FLD(ui,ra_arg), ui); ui = nxt_ui; canon_ui = canonSP_ui = nxt_ui; } //-------------------------------------------------- // SP-frame --> SP-frame: load RA by SP //-------------------------------------------------- else if (isLoadRegFromFrame(*cur_insn, MIPS_REG_SP, MIPS_REG_RA)) { checkUI(UI_ARG(ui), FrmTy_SP, cur_insn); // sanity check: sp_arg must be positive! // TODO: apply this check to other SP-relative ops. Fix prior intervals int sp_arg = UI_FLD(ui,sp_arg); if ( !(sp_arg > 0) ) { sp_arg = UI_FLD(canonSP_ui,sp_arg); } nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_SP, FrmFlg_RAReg, sp_arg, UI_FLD(ui,fp_arg), MIPS_REG_RA, ui); ui = nxt_ui; } //-------------------------------------------------- // 2. General: interior epilogues before returns //-------------------------------------------------- else if (isJumpToReg(*cur_insn, MIPS_REG_RA) && ((cur_insn + 1/*delay slot*/ + 1) < end_insn)) { // An interior return. Restore the canonical interval if necessary. // // N.B.: Although the delay slot instruction may affect the // frame, because of the return, we will never see its effect // within this procedure. Therefore, it is harmless to skip // processing of this delay slot. if (!ui_cmp(UI_ARG(ui), UI_ARG(canon_ui))) { nxt_ui = NEW_UI(nextInsn(cur_insn + 1/*delay slot*/), UI_FLD(canon_ui,ty), UI_FLD(canon_ui,flgs), UI_FLD(canon_ui,sp_arg), UI_FLD(canon_ui,fp_arg), UI_FLD(canon_ui,ra_arg), ui); ui = nxt_ui; cur_insn++; // skip delay slot and align new interval } } //-------------------------------------------------- // General: interior epilogues before callsites //-------------------------------------------------- else if (isCall(*cur_insn) && frameflg_isset(UI_FLD(ui,flgs), FrmFlg_RAReg)) { // The callsite (jalr) is clobbering r31, but RA is in r31. We // assume this is an inconsistency arising from control flow // jumping around an interior epilogue before the callsite. // Restore the canonical interval. if (!ui_cmp(UI_ARG(ui), UI_ARG(canon_ui))) { nxt_ui = NEW_UI(nextInsn(cur_insn), UI_FLD(canon_ui,ty), UI_FLD(canon_ui,flgs), UI_FLD(canon_ui,sp_arg), UI_FLD(canon_ui,fp_arg), UI_FLD(canon_ui,ra_arg), ui); ui = nxt_ui; } } //-------------------------------------------------- // 3. Basic support for FP frames. // // *-frame --> FP-frame: store RA by FP // *** canonical frame *** //-------------------------------------------------- else if (isStoreRegInFrame(*cur_insn, MIPS_REG_FP, MIPS_REG_RA)) { int sp_arg, fp_arg; if (UI_FLD(ui,ty) == FrmTy_SP) { sp_arg = unwarg_NULL; fp_arg = convertSPToFPOfst(UI_FLD(ui,sp_arg), UI_FLD(ui,fp_arg)); } else { sp_arg = UI_FLD(ui,sp_arg); fp_arg = UI_FLD(ui,fp_arg); } int ra_arg = getStoreRegInFrameOffset(*cur_insn); int16_t flgs = UI_FLD(ui,flgs); frameflg_unset(&flgs, FrmFlg_RAReg); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_FP, flgs, sp_arg, fp_arg, ra_arg, ui); ui = nxt_ui; canon_ui = canonFP_ui = nxt_ui; } //-------------------------------------------------- // *-frame --> FP-frame: store parent FP (saved in reg) by FP // *** canonical frame *** //-------------------------------------------------- else if (isMoveReg(*cur_insn, MIPS_REG_V0, MIPS_REG_FP)) { frameflg_set(&UI_FLD(ui,flgs), FrmFlg_FPInV); fp_saved_reg = MIPS_REG_V0; } else if (isMoveReg(*cur_insn, MIPS_REG_V1, MIPS_REG_FP)) { frameflg_set(&UI_FLD(ui,flgs), FrmFlg_FPInV); fp_saved_reg = MIPS_REG_V1; } else if (frameflg_isset(UI_FLD(ui,flgs), FrmFlg_FPInV) && isStoreRegInFrame(*cur_insn, MIPS_REG_FP, fp_saved_reg)) { int sp_arg, ra_arg; if (UI_FLD(ui,ty) == FrmTy_SP) { sp_arg = unwarg_NULL; ra_arg = convertSPToFPOfst(UI_FLD(ui,sp_arg), UI_FLD(ui,ra_arg)); } else { sp_arg = UI_FLD(ui,sp_arg); ra_arg = UI_FLD(ui,ra_arg); } int fp_arg = getStoreRegInFrameOffset(*cur_insn); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_FP, UI_FLD(ui,flgs), sp_arg, fp_arg, ra_arg, ui); ui = nxt_ui; canon_ui = canonFP_ui = nxt_ui; } /* else if (store-parent's-SP): useless */ //-------------------------------------------------- // *-frame --> FP-frame: allocate variable-sized frame // *** canonical frame *** //-------------------------------------------------- else if (isMoveReg(*cur_insn, MIPS_REG_FP, MIPS_REG_SP)) { // FP is set to SP, likely meaning it will point to the middle // of the frame (pos. offsets) rather than the top (neg. offsets) // ??? test that the canonical FP frame has not been set ??? frameflg_set(&UI_FLD(ui,flgs), FrmFlg_FPOfstPos); } else if (isAdjustSPByVar(*cur_insn)) { // TODO: ensure "daddu sp,sp,v0" is allocation rather than deallocation // if canonical interval has been set and it is an SP-frame... if (!UI_CMP_OPT(canon_ui, beg_ui) && UI_FLD(canon_ui,ty) == FrmTy_SP) { int16_t flgs = UI_FLD(ui,flgs); int sp_arg, fp_arg, ra_arg; if (frameflg_isset(flgs, FrmFlg_FPOfstPos)) { sp_arg = UI_FLD(canon_ui,sp_arg); fp_arg = UI_FLD(canon_ui,fp_arg); ra_arg = UI_FLD(canon_ui,ra_arg); } else { sp_arg = unwarg_NULL; fp_arg = convertSPToFPOfst(UI_FLD(canon_ui,sp_arg), UI_FLD(canon_ui,fp_arg)); ra_arg = convertSPToFPOfst(UI_FLD(canon_ui,sp_arg), UI_FLD(canon_ui,ra_arg)); } frameflg_set(&flgs, FrmFlg_FrmSzUnk); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_FP, flgs, sp_arg, fp_arg, ra_arg, ui); ui = nxt_ui; canon_ui = canonFP_ui = nxt_ui; } } //-------------------------------------------------- // FP-frame --> FP-frame: load RA by FP //-------------------------------------------------- else if (isLoadRegFromFrame(*cur_insn, MIPS_REG_FP, MIPS_REG_RA)) { checkUI(UI_ARG(ui), FrmTy_FP, cur_insn); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_FP, FrmFlg_RAReg, UI_FLD(ui,sp_arg), UI_FLD(ui,fp_arg), MIPS_REG_RA, ui); ui = nxt_ui; } /* else if (load-parent's-FP): not needed */ /* else if (load-parent's-SP): useless */ //-------------------------------------------------- // FP-frame --> SP-frame: deallocate (all/part of) frame by restoring SP //-------------------------------------------------- else if (isMoveReg(*cur_insn, MIPS_REG_SP, MIPS_REG_FP)) { if (UI_FLD(ui,ty) == FrmTy_FP) { bool isFullDealloc = (!frameflg_isset(UI_FLD(canon_ui,flgs), FrmFlg_RAReg) && frameflg_isset(UI_FLD(ui,flgs), FrmFlg_RAReg)); int flgs = (isFullDealloc) ? FrmFlg_RAReg : UI_FLD(canonSP_ui,flgs); int sp_arg, fp_arg, ra_arg; sp_arg = (isFullDealloc) ? 0 : UI_FLD(canonSP_ui,sp_arg); fp_arg = (isFullDealloc) ? unwarg_NULL : UI_FLD(canonSP_ui,fp_arg); ra_arg = (isFullDealloc) ? MIPS_REG_RA : UI_FLD(canonSP_ui,ra_arg); nxt_ui = NEW_UI(nextInsn(cur_insn), FrmTy_SP, flgs, sp_arg, fp_arg, ra_arg, ui); ui = nxt_ui; } else { // wierd code, e.g., monitor_main! Assume rest of frame will // be deallocated normally. Could restore a canonical frame // (FIXME). } } cur_insn++; } HPC_IFNO_UNW_LITE( UI_FLD(ui,common).end = INSN(end_insn); ) #if (!HPC_UNW_LITE) if (verbose) {
Executable::Executable(const std::string &path) { auto in = FileOpenIn(path); std::vector<std::vector<std::string>> lines; std::string line; while (std::getline(in, line)) { lines.resize(lines.size() + 1); std::size_t i = 0; std::size_t d; do { std::string s; d = line.find(' ', i); if (d == s.npos) s = std::string(line, i); else s = std::string(line, i, d - i); if (s.length()) lines.back().push_back(s); i = d + 1; } while (d != std::string::npos); } int n = 0; std::vector<Word> jmp = {0}; for (auto &line : lines) { std::unordered_map<std::string, Word> sizes = { {"eat", 2}, {"go", 2}, {"clon", 1}, {"str", 2}, {"left", 1}, {"right", 1}, {"back", 1}, {"turn", 1}, {"jg", 3}, {"jl", 3}, {"j", 2}, {"je", 2} }; try { jmp.push_back(jmp.back() + sizes.at(line.front())); } catch (const std::logic_error &) { throw ExecutableError(path, n); } } n = 0; for (auto &insn : lines) { auto parseOpN = [this, insn, path, n] { switch (insn.size()) { case 1: bytecode.push_back(1); break; case 2: try { bytecode.push_back((Word)std::stoul(insn[1])); break; } catch (const std::invalid_argument &) {} default: throw ExecutableError(path, n); } }; auto parseOpR = [this, insn, path, n] { if (insn.size() != 2 || insn[1] != "r") throw ExecutableError(path, n); }; auto parseOpNR = [this, insn, path, n] { switch (insn.size()) { case 1: bytecode.push_back(1); break; case 2: if (insn[1] == "r") bytecode.push_back(0); else { try { bytecode.push_back(static_cast<Word>(std::stoul(insn[1]))); } catch (const std::invalid_argument &) { throw ExecutableError(path, n); } if (bytecode.back() < 2 || bytecode.back() > 99) throw ExecutableError(path, n); } break; default: throw ExecutableError(path, n); } }; auto parseOpNN = [this, insn, path, n] { try { bytecode.push_back(static_cast<Word>(std::stoul(insn.at(1)))); bytecode.push_back(static_cast<Word>(std::stoul(insn.at(2)))); } catch (const std::logic_error &) { throw ExecutableError(path, n); } }; auto parseOpNone = [this, insn, path, n] { if (insn.size() != 1) throw ExecutableError(path, n); }; auto leaveJumpAddr = [this, jmp, path, n](Word pc) { if (pc >= jmp.size()) throw ExecutableError(path, n); bytecode.push_back(jmp[pc]); }; auto parseOpNJ = [this, insn, path, n, leaveJumpAddr] { try { bytecode.push_back((Word)std::stoul(insn.at(1))); leaveJumpAddr((Word)std::stoul(insn[2])); } catch (const std::logic_error &) { throw ExecutableError(path, n); } }; auto parseOpJ = [this, insn, path, n, leaveJumpAddr] { try { leaveJumpAddr((Word)std::stoul(insn.at(1))); } catch (const std::logic_error &) { throw ExecutableError(path, n); } }; std::unordered_map<std::string, std::function<void()>> handle = { #define INSN(n, i, o) \ {#n, [this, parseOp ## o] {\ bytecode.push_back(Insn ## i);\ parseOp ## o();\ }} INSN(eat, Eat, NR), INSN(go, Go, NR), INSN(clon, Clon, None), INSN(str, Str, N), INSN(left, Left, None), INSN(right, Right, None), INSN(back, Back, None), INSN(turn, Turn, R), INSN(jg, JG, NJ), INSN(jl, JL, NJ), INSN(j, J, J), INSN(je, JE, J) #undef INSN }; try { handle.at(insn[0])(); } catch (const std::out_of_range &) { throw ExecutableError(path, n); } n++; } }