📄 engine.cpp
字号:
int offs,bit_offs,bit_size, mask;
unpack_bitfield(ppcode->data,offs,bit_offs,bit_size);
mask = (1 << bit_size)-1;
data = mOP + offs;
if (opcode == PUSHIF) {
val = *(unsigned int *)data;
val >>= bit_offs;
push(val & mask);
} else {
unsigned word = *(unsigned *)data;
val = pop();
mask <<= bit_offs;
mask = ~ mask;
word &= mask;
val <<= bit_offs;
word |= val;
*(unsigned *)data = word;
}
} break;
//...Miscelaneous (not likely to remain forever!)
case SHOWI:
case SHOWV:
{
Type t, te;
PEntry ve;
if (opcode==SHOWI) {
t = *(Type *)data; ve = NULL;
te = t;
} else {
t = t_void; ve = *(PEntry *)data;
te = ve->type;
}
bool is_double = te.is_double() && !te.is_pointer();
void *ptr = is_double ? (void *)&tos2() : (void *)&tos();
Parser::dump_expression(t,ptr,ve);
if(is_double) pop2(); else pop();
} break;
case HALT:
// *change 1.2.4 if the operand is out of range, it's a NOP instruction!
if (ppcode->data < MAX_BREAKPOINTS) {
if (Breakpoint::from_id(ppcode->data)->execute()) return false;
continue; // don't move to next instruction!
}
break;
case SHOWD: cout << "(double) " << (rmode ? *(double *)data : pop2()) << endl; break;
} // switch(opcode)
ppcode++;
CHECK_ODS;
if (s_stepping) {
// *add 1.2.4 Profiling support
if (s_stepping == STEP_PROFILE) { instr_count++; continue; }
if (ppcode == end_of_code) return true; // finished...
// *add 1.2.7 working single-stepping
// while in this state, we're just looking for the current function block fb
// to switch back to the initial fb
if (s_stepping==STEPPING_OVER) {
if (s_initial_fb == fb) {
s_stepping = 0;
s_current_exec_line = get_current_exec_line();
if (s_current_exec_line != -1 && s_current_exec_line != s_old_exec_line) return false;
// it's possible we're back in the original fn, but at its end. So keep going.
else s_stepping = STEPPING;
}
} else
// normal state while we're single-stepping; jump out if the current line num
// changes.
if (s_stepping==STEPPING) {
int nl = get_current_exec_line();
/// cout << "l = " << nl << " ip = " << current_ip() << "fb = " << fb << endl;
if (nl != -1 && nl != s_current_exec_line) {
s_old_exec_line = s_current_exec_line;
s_current_exec_line = nl;
// we want to step over; has the current function changed?
if (s_initial_fb && s_initial_fb != fb) {
int sdepth = stack_frame_depth();
if (sdepth > s_initial_stack_depth) {
// we're entering a new function - let's step over it
s_stepping = STEPPING_OVER;
} else {
// we're leaving a function; continue single-stepping
s_stepping = STEPPING;
s_initial_fb = fb;
s_initial_stack_depth = sdepth;
}
} else {
s_stepping = 0;
return false; // we are halted on the next line
}
}
} else if (s_stepping == STEP_WAIT) {
s_current_exec_line = get_current_exec_line();
s_stepping = STEPPING;
}
}
} // while(true)
return true; // cool, everything ok.
}
bool Engine::set_single_stepping(bool single_step)
{
Function* mfn = Function::lookup("main");
s_main_fb = mfn->fun_block();
// check to see if we are already halted at a breakpoint....
if (paused() && s_brk != NULL) {
s_stepping = STEPPING; //STEP_WAIT;
s_current_exec_line = get_current_exec_line();
} else s_stepping = STEPPING;
s_initial_stack_depth = stack_frame_depth();
if (single_step) s_initial_fb = NULL;
else if (paused()) s_initial_fb = resume_state.m_fb;
else { // we're starting afresh w/ main
s_initial_fb = s_main_fb;
s_stepping = STEPPING_OVER;
}
return true;
}
//*fix 1.2.8 must explicitly reset single stepping
void Engine::reset_single_stepping()
{
s_stepping = 0;
}
FBlock *mStartFB;
extern FBlock mCodeBlock;
Instruction *old_immediate_code;
namespace Parser {
Instruction *immediate_code_ptr();
void immediate_code_ptr(Instruction *pi);
FBlock *immediate_code_block();
};
void dissemble(PFBlock fb); // in DISSEM
bool Engine::paused() { return resume_state.m_fb != NULL; }
bool Engine::running() { return fb != START_FB; }
bool get_current_exec_pos(int& ip_offs, string& fname, LineInfo& li)
{
FunctionContext *fcxt = NULL;
if (fb) {
fcxt = (FunctionContext *)fb->context;
fname = fname_from_fblock(fb); // *change 1.2.4
}
ip_offs = current_ip();
if (! fcxt) return false;
li.ip_offset = ip_offs;
return fcxt->ip_to_line(li);
}
Table* context_of_function(LocalContext* lc)
{
FunctionEntry* pfe = lc->function()->fun_entry();
return pfe->reference()->context;
}
bool function_is_in_std(LocalContext* lc)
{
return context_of_function(lc) == Parser::std_namespace();
}
// add 1.2.7 when single-stepping, we can avoid going
// into any function w/in the std namespace.
// *NOTE*
// 1. wd it apply to methods of classes w/in std?
// 2. shd be a Function method - need it elsewhere.
int get_current_exec_line()
{
LineInfo li;
int ip_offs;
string fname;
bool ret = get_current_exec_pos(ip_offs,fname,li);
if (ret && !(Parser::debug.no_trace_std
&& function_is_in_std((LocalContext*)li.cntxt))) return li.line;
else return -1;
}
void exec_message(char *msg, bool was_error, bool dont_unwind_error)
{
if (fb == START_FB) {
cerr << msg << endl << "poppped!!" << endl;
return;
}
int ip_offs;
string fname;
LineInfo li;
bool trace_function = Parser::debug.function_trace;
bool tracing_lines = true; // !trace_function;
bool back_trace = false;
if (trace_function && Parser::debug.verbose) {
cerr << "*CRASH " << (void *)mOP << ' ' << (void *)mSP
<< ' ' << (void *)baseSP << endl;
}
// set the error state!
int kount = 0; // limit the number of trace back levels...
try {
do {
bool have_info = get_current_exec_pos(ip_offs,fname,li);
if (back_trace && ppcode != NULL) {
if (have_info) cerr << li.file << ' ' << li.line << ": " << fname << endl;
else cerr << "(" << ip_offs << ") " << fname << endl;
if (++kount > 50) {
cerr << "Too many trace messages" << endl;
reset_stacks();
return;
}
} else
if(tracing_lines && have_info) {
if (!was_error || dont_unwind_error) {
// *fix 1.2.8 set the local context _before_ we tell the IDE it's a break....
Parser::state.push_context(li.cntxt);
resume_state.save(ppcode,true);
old_immediate_code = Parser::immediate_code_ptr();
Errors::set_halt_state(msg,fname,li.file,li.line, was_error);
return;
}
Errors::set_halt_state(msg,fname,li.file,li.line, was_error);
// Halted at breakpoint - prepare to resume, set up context
// *add 1.2.8 or an error, but we want to preserve the context...
// *add 0.9.2 Can stop as soon as we have a line no, unless we're tracing...
mODS.clear();
if (! trace_function) { reset_stacks(); return; }
else {
cerr << "in " << fname << ":\n";
back_trace = true;
}
}
if (fs.depth()==0) break; // *fix 0.9.6 Function Stack Overflow has already cleared this
end_function();
check_fun_block(fb);
} while (fb != START_FB);
reset_stacks();
// *fix 1.2.4 Dump out final error message if we haven't found a line number...
if (! tracing_lines || ! back_trace)
Errors::set_halt_state(msg,fname,"",ip_offs,true);
} catch(...) {
cerr << "Unknown crash" << endl;
// *add 0.9.4 Must restore execution stack, esp. for stack overflow errors
reset_stacks();
}
}
// *change 1.2.9 the 'static ODS' has been retired.
void Engine::global_unwind()
{
//do_unwind(NULL,mStaticODS);
LoadedModuleList::run_global_finalization();
}
int handle_exception(PEntry epe, char *msg);
// *add 1.2.8 this is the entry point used by native code to call the interpreter
// so that we can pause the thread for debugging.
int __STDCALL Engine::stub_execute(FBlock* _fb, int flags, ArgBlock *xargs)
//-------------------------------------------------------------------------
{
int ret;
do {
ret = execute(_fb,flags | FROM_OUTSIDE,xargs);
if (ret == HALTED) {
if (! Program::in_main_thread()) {
Program::pause_thread();
flags = RESUME;
}
else ret = OK;
}
} while (ret == HALTED);
return ret;
}
int __STDCALL Engine::execute(FBlock *_fb, int flags, ArgBlock *xargs)
//--------------------------------------------------------------------
{
FBlock * old_fb = fb;
Instruction *old_ppcode = ppcode;
int *old_mSP = mSP;
PEntry epe;
char *except_msg;
resume_execution:
try {
if (flags & ARGS_PASSED) { // only if execute() is called from outside UC
xargs->flags = flags; // *fix 1.1.1 save flags and arg block so we can resume properly!
resume_state.m_xargs = xargs;
if (flags & METHOD_CALL) opush(xargs->OPtr); // the 'this' pointer
for(int i=0,n = xargs->no; i < n; i++) // these are set by the native stub!!
push(xargs->values[i]);
}
if (flags & RESUME) {
bool context_pushed;
set_frame(0,false); // *fix 1.1.1 ensure we're in proper frame!
resume_state.restore(context_pushed,xargs);
if (xargs) flags = xargs->flags; // *fix 1.1.1 restore flags and arg block as well!
if (context_pushed) Parser::state.pop_context(); // i.e, we were halted by a breakpoint, which pushed the context..
resume_state.m_fb = NULL; // flag us as NOT paused
Parser::immediate_code_ptr(old_immediate_code); // and restore immediate execution context!
} else {
mStartFB = _fb;
// *fix 1.2.8 we only push START_FB if execute() is called from
// w/in UCW; its only purpose is to give a 'false bottom' to
// the function stack.
if (flags & FROM_OUTSIDE) {
fs.push(ppcode);
fs.push(fb);
fs.push(mSP);
}
fb = START_FB;
ppcode = NULL;
start_function(_fb);
}
// *fix 1.0.0L Some platforms need this to translate signals into C++ exceptions
// See hard_except.h for the definition and hard_except.cpp for explanation
CATCH_SIGNALS
for(;;) {
if (! start_exec()) { exec_message("halted at ",false); return HALTED; }
else {
if (flags & FROM_OUTSIDE) {
old_mSP = (int*)fs.pop();
old_fb = (FBlock*)fs.pop();
old_ppcode = (Instruction*)fs.pop();
}
fb = old_fb;
ppcode = old_ppcode;
if (flags & ARGS_PASSED) {
if (flags & METHOD_CALL) opop();
if (flags & RETURN_32) xargs->ret1 = pop(); else
if (flags & RETURN_64) xargs->ret2 = pop2();
} else mSP = old_mSP;
return OK;
}
}
}
catch(Exception& e) {
// map onto the corresp UC exception types. Note that uc_except.h
// must be included for these to operate properly. (see Parser::init_lib())
switch (e.type()) {
case Exception::INT_DIV0: epe = Parser::mEIntDivByZero; break;
case Exception::ACCESS: epe = Parser::mEAccessViolation; break;
case Exception::FLOAT_DIV0: epe = Parser::mEFloatDivByZero; break;
case Exception::RANGE_ERROR: epe = Parser::mERangeError; break;
case Exception::UNKNOWN: epe = Parser::mEException; break;
default: epe = NULL;
}
except_msg = strdup(e.what()); //*??
}
catch(...) {
// *fix 1.1.0 Translate as an unknown exception....
epe = Parser::mEException;
except_msg = "unknown";
}
// managing exceptions
// *add 1.2.8 evaluating stuff which explodes during a debug session
if (Engine::paused()) return HALTED;
int ip = -1;
if (epe != NULL) ip = throw_exception(epe->type,epe->global_ptr());
if (ip == -1) { // plain uncaught exception message...
// *add 1.2.8 treating errors as a break is now an option (doesn't unwind fun stack)
bool break_on_error = Parser::debug.errors_as_break;
exec_message(except_msg,true,break_on_error);
return break_on_error ? HALTED : CRASHED;
} else { // force execution to resume in catch block...!
// *fix 0.9.4 Point is that throw_exception() will have dropped us
// into the right function context...
// *fix 1.1.0 In this case we are _not_ pushing the local context!
resume_state.save(fb->pstart+ip,false);
flags = Engine::RESUME;
goto resume_execution;
}
}
int handle_exception(PEntry epe, char *msg)
{
int ip = -1;
if (epe != NULL) ip = throw_exception(epe->type,epe->global_ptr());
if (ip == -1) { // plain uncaught exception message...
try {
exec_message(msg,true); return CRASHED;
} catch(...) {
cerr << "Disturbed....\n"; return CRASHED;
}
} else { // force execution to resume in catch block...!
// *fix 0.9.4 Point is that throw_exception() will have dropped us
// into the right function context...
// *fix 1.1.0 In this case we are _not_ pushing the local context!
resume_state.save(fb->pstart+ip,false);
return Engine::execute(NULL,Engine::RESUME);
}
}
CatchHandler::CatchHandler(FBlock *fb)
: m_fb(fb)
{
m_end_label = new Label(&Parser::code());
}
void CatchHandler::add_catch_block(Type t, int ip_offs)
{
CatchBlock *pcb = new CatchBlock;
pcb->type = t;
pcb->ip_offset = ip_offs;
m_catch_blocks.push_back(pcb);
}
int CatchHandler::match_thrown_object(Type t, void *obj)
{
CatchBlockList::iterator cbli;
FORALL(cbli,m_catch_blocks) {
Type ct = (*cbli)->type;
// *fix 0.9.5. Catch-block must match any derived class..
if (ct == t || ct == t_void || t.inherits_from(ct)) {
m_thrown_object = obj;
m_thrown_type = t;
*(void **)(Parser::mExceptObj->global_ptr()) = obj;
return (*cbli)->ip_offset;
}
}
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -