void Runtime::Debugger::EvaluateReference(Reference* &reference, MemoryContext context) { StackMethod* method = cur_frame->method; // // instance reference // if(context != LOCL) { if(ref_mem && ref_klass) { // check reference name bool found; StackDclr dclr_value; if(context == INST) { found = ref_klass->GetInstanceDeclaration(reference->GetVariableName(), dclr_value); } else { found = ref_klass->GetClassDeclaration(reference->GetVariableName(), dclr_value); } // set reference if(found) { reference->SetDeclaration(dclr_value); switch(dclr_value.type) { case CHAR_PARM: case INT_PARM: reference->SetIntValue(ref_mem[dclr_value.id]); break; case FUNC_PARM: reference->SetIntValue(ref_mem[dclr_value.id]); reference->SetIntValue2(ref_mem[dclr_value.id + 1]); break; case FLOAT_PARM: { FLOAT_VALUE value; memcpy(&value, &ref_mem[dclr_value.id], sizeof(FLOAT_VALUE)); reference->SetFloatValue(value); } break; case OBJ_PARM: EvaluateInstanceReference(reference, dclr_value.id); break; case BYTE_ARY_PARM: EvaluateByteReference(reference, dclr_value.id); break; case CHAR_ARY_PARM: EvaluateCharReference(reference, dclr_value.id); break; case INT_ARY_PARM: EvaluateIntFloatReference(reference, dclr_value.id, false); break; case OBJ_ARY_PARM: EvaluateIntFloatReference(reference, dclr_value.id, false); break; case FLOAT_ARY_PARM: EvaluateIntFloatReference(reference, dclr_value.id, true); break; } } else { wcout << L"unknown variable (or no debug information available)." << endl; is_error = true; } } else { wcout << L"unable to find reference." << endl; is_error = true; } } // // method reference // else { ref_mem = cur_frame->mem; if(ref_mem) { StackDclr dclr_value; // process explicit '@self' reference if(reference->IsSelf()) { dclr_value.name = L"@self"; dclr_value.type = OBJ_PARM; reference->SetDeclaration(dclr_value); EvaluateInstanceReference(reference, 0); } // process method reference else { // check reference name bool found = method->GetLocalDeclaration(reference->GetVariableName(), dclr_value); reference->SetDeclaration(dclr_value); if(found) { if(method->HasAndOr()) { dclr_value.id++; } switch(dclr_value.type) { case CHAR_PARM: case INT_PARM: reference->SetIntValue(ref_mem[dclr_value.id + 1]); break; case FUNC_PARM: reference->SetIntValue(ref_mem[dclr_value.id + 1]); reference->SetIntValue2(ref_mem[dclr_value.id + 2]); break; case FLOAT_PARM: { FLOAT_VALUE value; memcpy(&value, &ref_mem[dclr_value.id + 1], sizeof(FLOAT_VALUE)); reference->SetFloatValue(value); } break; case OBJ_PARM: EvaluateInstanceReference(reference, dclr_value.id + 1); break; case BYTE_ARY_PARM: EvaluateByteReference(reference, dclr_value.id + 1); break; case CHAR_ARY_PARM: EvaluateCharReference(reference, dclr_value.id + 1); break; case INT_ARY_PARM: EvaluateIntFloatReference(reference, dclr_value.id + 1, false); break; case OBJ_ARY_PARM: EvaluateIntFloatReference(reference, dclr_value.id + 1, false); break; case FLOAT_ARY_PARM: EvaluateIntFloatReference(reference, dclr_value.id + 1, true); break; } } else { // class for class reference StackClass* klass = cur_program->GetClass(reference->GetVariableName()); if(klass) { dclr_value.name = klass->GetName(); dclr_value.type = OBJ_PARM; reference->SetDeclaration(dclr_value); EvaluateClassReference(reference, klass, 0); } else { // process implicit '@self' reference Reference* next_reference = TreeFactory::Instance()->MakeReference(); next_reference->SetReference(reference); reference = next_reference; // set declaration dclr_value.name = L"@self"; dclr_value.type = OBJ_PARM; reference->SetDeclaration(dclr_value); EvaluateInstanceReference(reference, 0); } } } } else { wcout << L"unable to de-reference empty frame." << endl; is_error = true; } } }
void Runtime::Debugger::ProcessInfo(Info* info) { const wstring &cls_name = info->GetClassName(); const wstring &mthd_name = info->GetMethodName(); #ifdef _DEBUG wcout << L"--- info class=" << cls_name << L", method=" << mthd_name << L" ---" << endl; #endif if(interpreter) { // method info if(cls_name.size() > 0 && mthd_name.size() > 0) { StackClass* klass = cur_program->GetClass(cls_name); if(klass && klass->IsDebug()) { vector<StackMethod*> methods = klass->GetMethods(mthd_name); if(methods.size() > 0) { for(size_t i = 0; i < methods.size(); i++) { StackMethod* method = methods[i]; wcout << L" class: type=" << klass->GetName() << L", method=" << PrintMethod(method) << endl; if(method->GetNumberDeclarations() > 0) { wcout << L" parameters:" << endl; PrintDeclarations(method->GetDeclarations(), method->GetNumberDeclarations()); } } } else { wcout << L"unable to find method." << endl; is_error = true; } } else { wcout << L"unable to find class." << endl; is_error = true; } } // class info else if(cls_name.size() > 0) { StackClass* klass = cur_program->GetClass(cls_name); if(klass && klass->IsDebug()) { wcout << L" class: type=" << klass->GetName() << endl; // print wcout << L" parameters:" << endl; if(klass->GetNumberInstanceDeclarations() > 0) { PrintDeclarations(klass->GetInstanceDeclarations(), klass->GetNumberInstanceDeclarations()); } } else { wcout << L"unable to find class." << endl; is_error = true; } } // general info else { wcout << L"general info:" << endl; wcout << L" program executable: file='" << program_file << L"'" << endl; // parse method and class names const wstring &long_name = cur_frame->method->GetName(); int end_index = long_name.find_last_of(':'); const wstring &cls_mthd_name = long_name.substr(0, end_index); int mid_index = cls_mthd_name.find_last_of(':'); const wstring &cls_name = cls_mthd_name.substr(0, mid_index); const wstring &mthd_name = cls_mthd_name.substr(mid_index + 1); // print wcout << L" current file='" << cur_file_name << L":" << cur_line_num << L"', method='" << cls_name << L"->" << mthd_name << L"(..)'" << endl; } } else { wcout << L"program is not running." << endl; } }
Command* Runtime::Debugger::ProcessCommand(const wstring &line) { #ifdef _DEBUG wcout << L"input: |" << line << L"|" << endl; #endif // parser input is_next = is_next_line = false; Parser parser; Command* command = parser.Parse(L"?" + line); if(command) { switch(command->GetCommandType()) { case EXE_COMMAND: ProcessExe(static_cast<Load*>(command)); break; case SRC_COMMAND: ProcessSrc(static_cast<Load*>(command)); break; case ARGS_COMMAND: ProcessArgs(static_cast<Load*>(command)); break; case QUIT_COMMAND: ClearBreaks(); ClearProgram(); wcout << L"goodbye." << endl; exit(0); break; case LIST_COMMAND: { FilePostion* file_pos = static_cast<FilePostion*>(command); wstring file_name; if(file_pos->GetFileName().size() > 0) { file_name = file_pos->GetFileName(); } else { file_name = cur_file_name; } int line_num; if(file_pos->GetLineNumber() > 0) { line_num = file_pos->GetLineNumber(); } else { line_num = cur_line_num; } const wstring &path = base_path + file_name; if(FileExists(path) && line_num > 0) { SourceFile src_file(path, cur_line_num); if(!src_file.Print(line_num)) { wcout << L"invalid line number." << endl; is_error = true; } } else { wcout << L"source file or line number doesn't exist, ensure the program is running." << endl; is_error = true; } } break; case BREAK_COMMAND: ProcessBreak(static_cast<FilePostion*>(command)); break; case BREAKS_COMMAND: ProcessBreaks(); break; case PRINT_COMMAND: ProcessPrint(static_cast<Print*>(command)); break; case RUN_COMMAND: if(!cur_program) { ProcessRun(); } else { wcout << L"instance already running." << endl; is_error = true; } break; case CLEAR_COMMAND: { wcout << L" are sure you want to clear all breakpoints? [y/n] "; wstring line; getline(wcin, line); if(line == L"y" || line == L"yes") { ClearBreaks(); } } break; case DELETE_COMMAND: ProcessDelete(static_cast<FilePostion*>(command)); break; case NEXT_COMMAND: if(interpreter) { is_next = true; } else { wcout << L"program is not running." << endl; } break; case NEXT_LINE_COMMAND: if(interpreter) { is_next_line = true; } else { wcout << L"program is not running." << endl; } break; case JUMP_OUT_COMMAND: if(interpreter) { is_jmp_out = true; } else { wcout << L"program is not running." << endl; } break; case CONT_COMMAND: if(!interpreter) { wcout << L"program is not running." << endl; } cur_line_num = -2; break; case INFO_COMMAND: ProcessInfo(static_cast<Info*>(command)); break; case STACK_COMMAND: if(interpreter) { wcout << L"stack:" << endl; StackMethod* method = cur_frame->method; wcerr << L" frame: pos=" << cur_call_stack_pos << L", class=" << method->GetClass()->GetName() << L", method=" << PrintMethod(method); const long ip = cur_frame->ip; if(ip > -1) { StackInstr* instr = cur_frame->method->GetInstruction(ip); wcerr << L", file=" << method->GetClass()->GetFileName() << L":" << instr->GetLineNumber() << endl; } else { wcerr << endl; } long pos = cur_call_stack_pos - 1; do { StackMethod* method = cur_call_stack[pos]->method; wcerr << L" frame: pos=" << pos << L", class=" << method->GetClass()->GetName() << L", method=" << PrintMethod(method); const long ip = cur_call_stack[pos]->ip; if(ip > -1) { StackInstr* instr = cur_call_stack[pos]->method->GetInstruction(ip); wcerr << L", file=" << method->GetClass()->GetFileName() << L":" << instr->GetLineNumber() << endl; } else { wcerr << endl; } } while(--pos); } else { wcout << L"program is not running." << endl; } break; default: break; } is_error = false; ref_mem = NULL; return command; } else { wcout << L"-- Unable to process command --" << endl; } is_error = false; ref_mem = NULL; return NULL; }
int main(const int argc, const char* argv[]) { const char* prgm_path = FCGX_GetParam("PROGRAM_PATH", environ); if(!prgm_path) { cerr << "Unable to find program, please ensure the 'PROGRAM_PATH' variable has been set correctly." << endl; exit(1); } // load program srand(time(NULL)); rand(); Loader loader(prgm_path); loader.Load(); // ignore web applications if(!loader.IsWeb()) { cerr << "Please recompile the code to be a web application." << endl; exit(1); } #ifdef _TIMING clock_t start = clock(); #endif // locate starting class and method StackMethod* mthd = loader.GetStartMethod(); if(!mthd) { cerr << "Unable to locate the 'Request(args)' function." << endl; exit(1); } #ifdef _DEBUG cerr << "### Loaded method: " << mthd->GetName() << " ###" << endl; #endif Runtime::StackInterpreter intpr(Loader::GetProgram()); // go into accept loop... FCGX_Stream*in; FCGX_Stream* out; FCGX_Stream* err; FCGX_ParamArray envp; while(mthd && (FCGX_Accept(&in, &out, &err, &envp) >= 0)) { // execute method long* op_stack = new long[CALC_STACK_SIZE]; long* stack_pos = new long; // create request long* req_obj = MemoryManager::Instance()->AllocateObject("FastCgi.Request", op_stack, *stack_pos, false); if(req_obj) { req_obj[0] = (long)in; req_obj[1] = (long)envp; // create response long* res_obj = MemoryManager::Instance()->AllocateObject("FastCgi.Response", op_stack, *stack_pos, false); if(res_obj) { res_obj[0] = (long)out; res_obj[1] = (long)err; // set calling parameters op_stack[0] = (long)req_obj; op_stack[1] = (long)res_obj; *stack_pos = 2; // execute method intpr.Execute((long*)op_stack, (long*)stack_pos, 0, mthd, NULL, false); } else { cerr << ">>> DLL call: Unable to allocate object FastCgi.Response <<" << endl; // TODO: error return 1; } } else { cerr << ">>> DLL call: Unable to allocate object FastCgi.Request <<<" << endl; // TODO: error return 1; } #ifdef _DEBUG cout << "# final stack: pos=" << (*stack_pos) << " #" << endl; if((*stack_pos) > 0) { for(int i = 0; i < (*stack_pos); i++) { cout << "dump: value=" << (void*)(*stack_pos) << endl; } } #endif // clean up delete[] op_stack; op_stack = NULL; delete stack_pos; stack_pos = NULL; #ifdef _DEBUG PrintEnv(out, "Request environment", envp); PrintEnv(out, "Initial environment", environ); #endif } return 0; }
uintptr_t WINAPI MemoryManager::CheckPdaRoots(void* arg) { #ifndef _GC_SERIAL EnterCriticalSection(&pda_frame_cs); #endif #ifdef _DEBUG wcout << L"----- PDA frames(s): num=" << pda_frames.size() << L"; thread=" << GetCurrentThread()<< L" -----" << endl; wcout << L"memory types:" << endl; #endif set<StackFrame**, StackFrame**>::iterator iter; for(iter = pda_frames.begin(); iter != pda_frames.end(); ++iter) { StackFrame** frame = *iter; StackMethod* mthd = (*frame)->method; long* mem = (*frame)->mem; #ifdef _DEBUG wcout << L"\t===== PDA method: name=" << mthd->GetName() << L", addr=" << mthd << L", num=" << mthd->GetNumberDeclarations() << L" =====" << endl; #endif // mark self CheckObject((long*)(*mem), true, 1); if(mthd->HasAndOr()) { mem += 2; } else { mem++; } // mark rest of memory CheckMemory(mem, mthd->GetDeclarations(), mthd->GetNumberDeclarations(), 0); } #ifndef _GC_SERIAL LeaveCriticalSection(&pda_frame_cs); #endif #ifndef GC_SERIAL EnterCriticalSection(&pda_monitor_cs); #endif #ifdef _DEBUG wcout << L"----- PDA method root(s): num=" << pda_monitors.size() << L"; thread=" << GetCurrentThread()<< L" -----" << endl; wcout << L"memory types:" << endl; #endif // look at pda methods unordered_map<StackFrameMonitor*, StackFrameMonitor*>::iterator pda_iter; for(pda_iter = pda_monitors.begin(); pda_iter != pda_monitors.end(); ++pda_iter) { // gather stack frames StackFrameMonitor* monitor = pda_iter->first; long call_stack_pos = *(monitor->call_stack_pos); if (call_stack_pos > 0) { StackFrame** call_stack = monitor->call_stack; StackFrame* cur_frame = *(monitor->cur_frame); // copy frames locally vector<StackFrame*> frames; frames.push_back(cur_frame); while (--call_stack_pos > -1) { frames.push_back(call_stack[call_stack_pos]); } for (size_t i = 0; i < frames.size(); ++i) { StackMethod* mthd = frames[i]->method; long* mem = frames[i]->mem; #ifdef _DEBUG wcout << L"\t===== PDA method: name=" << mthd->GetName() << L", addr=" << mthd << L", num=" << mthd->GetNumberDeclarations() << L" =====" << endl; #endif // mark self CheckObject((long*)(*mem), true, 1); if (mthd->HasAndOr()) { mem += 2; } else { mem++; } // mark rest of memory CheckMemory(mem, mthd->GetDeclarations(), mthd->GetNumberDeclarations(), 0); } } } #ifndef GC_SERIAL LeaveCriticalSection(&pda_monitor_cs); #endif return 0; }
uintptr_t WINAPI MemoryManager::CheckJitRoots(void* arg) { #ifndef GC_SERIAL EnterCriticalSection(&jit_cs); #endif #ifdef _DEBUG wcout << L"---- Marking JIT method root(s): num=" << jit_roots.size() << L"; thread=" << GetCurrentThread() << L" ------" << endl; wcout << L"memory types: " << endl; #endif unordered_map<long*, ClassMethodId*>::iterator jit_iter; for(jit_iter = jit_roots.begin(); jit_iter != jit_roots.end(); ++jit_iter) { ClassMethodId* id = jit_iter->second; long* mem = id->mem; StackMethod* mthd = prgm->GetClass(id->cls_id)->GetMethod(id->mthd_id); const long dclrs_num = mthd->GetNumberDeclarations(); #ifdef _DEBUG wcout << L"\t===== JIT method: name=" << mthd->GetName() << L", id=" << id->cls_id << L"," << id->mthd_id << L"; addr=" << mthd << L"; num=" << mthd->GetNumberDeclarations() << L" =====" << endl; #endif // check self CheckObject(id->self, true, 1); StackDclr** dclrs = mthd->GetDeclarations(); for(int j = dclrs_num - 1; j > -1; j--) { // update address based upon type switch(dclrs[j]->type) { case FUNC_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": FUNC_PARM: value=" << (*mem) << L"," << *(mem + 1) << endl; #endif // update mem += 2; break; case CHAR_PARM: case INT_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": CHAR_PARM/INT_PARM: value=" << (*mem) << endl; #endif // update mem++; break; case FLOAT_PARM: { #ifdef _DEBUG FLOAT_VALUE value; memcpy(&value, mem, sizeof(FLOAT_VALUE)); wcout << L"\t" << j << L": FLOAT_PARM: value=" << value << endl; #endif // update mem += 2; } break; case BYTE_ARY_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": BYTE_ARY_PARM: addr=" << (long*)(*mem) << L"(" << (long)(*mem) << L"), size=" << ((*mem) ? ((long*)(*mem))[SIZE_OR_CLS] : 0) << L" byte(s)" << endl; #endif // mark data MarkMemory((long*)(*mem)); // update mem++; break; case CHAR_ARY_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": CHAR_ARY_PARM: addr=" << (long*)(*mem) << L"(" << (long)(*mem) << L"), size=" << ((*mem) ? ((long*)(*mem))[SIZE_OR_CLS] : 0) << L" byte(s)" << endl; #endif // mark data MarkMemory((long*)(*mem)); // update mem++; break; case INT_ARY_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": INT_ARY_PARM: addr=" << (long*)(*mem) << L"(" << (long)(*mem) << L"), size=" << ((*mem) ? ((long*)(*mem))[SIZE_OR_CLS] : 0) << L" byte(s)" << endl; #endif // mark data MarkMemory((long*)(*mem)); // update mem++; break; case FLOAT_ARY_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": FLOAT_ARY_PARM: addr=" << (long*)(*mem) << L"(" << (long)(*mem) << L"), size=" << L" byte(s)" << ((*mem) ? ((long*)(*mem))[SIZE_OR_CLS] : 0) << endl; #endif // mark data MarkMemory((long*)(*mem)); // update mem++; break; case OBJ_PARM: { #ifdef _DEBUG wcout << L"\t" << j << L": OBJ_PARM: addr=" << (long*)(*mem) << L"(" << (long)(*mem) << L"), id="; if(*mem) { StackClass* tmp = (StackClass*)((long*)(*mem))[SIZE_OR_CLS]; wcout << L"'" << tmp->GetName() << L"'" << endl; } else { wcout << L"Unknown" << endl; } #endif // check object CheckObject((long*)(*mem), true, 1); // update mem++; } break; // TODO: test the code below case OBJ_ARY_PARM: #ifdef _DEBUG wcout << L"\t" << j << L": OBJ_ARY_PARM: addr=" << (long*)(*mem) << L"(" << (long)(*mem) << L"), size=" << ((*mem) ? ((long*)(*mem))[SIZE_OR_CLS] : 0) << L" byte(s)" << endl; #endif // mark data if(MarkValidMemory((long*)(*mem))) { long* array = (long*)(*mem); const long size = array[0]; const long dim = array[1]; long* objects = (long*)(array + 2 + dim); for(long k = 0; k < size; k++) { CheckObject((long*)objects[k], true, 2); } } // update mem++; break; default: break; } } // NOTE: this marks temporary variables that are stored in JIT memory // during some method calls. there are 3 integer temp addresses for(int i = 0; i < 8; i++) { CheckObject((long*)mem[i], false, 1); } } #ifndef GC_SERIAL LeaveCriticalSection(&jit_cs); #endif return 0; }