예제 #1
0
/* 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;
}
예제 #2
0
static inline char*
nextInsn(uint32_t* insn) 
{ return INSN(insn + 1); }
예제 #3
0
// 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++;
    }
}