add detail crash info

This commit is contained in:
ValKmjolnir 2021-10-17 22:57:45 +08:00
parent 1bfa7d2638
commit bbee31ea55
4 changed files with 93 additions and 65 deletions

View File

@ -5,6 +5,7 @@ constexpr uint32_t VM_CODEINFO =4;
constexpr uint32_t VM_EXECTIME =8; constexpr uint32_t VM_EXECTIME =8;
constexpr uint32_t VM_OPCALLNUM=16; constexpr uint32_t VM_OPCALLNUM=16;
constexpr uint32_t VM_EXEC =32; constexpr uint32_t VM_EXEC =32;
constexpr uint32_t VM_DBGINFO =64;
void help() void help()
{ {
std::cout std::cout
@ -25,6 +26,7 @@ void help()
<<" -c, --code | view bytecode.\n" <<" -c, --code | view bytecode.\n"
<<" -t, --time | execute and get the running time.\n" <<" -t, --time | execute and get the running time.\n"
<<" -o, --opcnt | count operands while running.\n" <<" -o, --opcnt | count operands while running.\n"
<<" -d, --detail | get detail crash info.\n"
<<"file:\n" <<"file:\n"
<<" input file name to execute script file.\n"; <<" input file name to execute script file.\n";
} }
@ -59,7 +61,7 @@ void err()
std::exit(1); std::exit(1);
} }
void execute(const std::string& file,const uint16_t cmd) void execute(const std::string& file,const uint32_t cmd)
{ {
nasal_lexer lexer; nasal_lexer lexer;
nasal_parse parse; nasal_parse parse;
@ -96,11 +98,11 @@ void execute(const std::string& file,const uint16_t cmd)
if(cmd&VM_EXECTIME) if(cmd&VM_EXECTIME)
{ {
clock_t t=clock(); clock_t t=clock();
vm.run(gen,linker,cmd&VM_OPCALLNUM); vm.run(gen,linker,cmd&VM_OPCALLNUM,cmd&VM_DBGINFO);
std::cout<<"process exited after "<<((double)(clock()-t))/CLOCKS_PER_SEC<<"s.\n"; std::cout<<"process exited after "<<((double)(clock()-t))/CLOCKS_PER_SEC<<"s.\n";
} }
else if(cmd&VM_EXEC) else if(cmd&VM_EXEC)
vm.run(gen,linker,cmd&VM_OPCALLNUM); vm.run(gen,linker,cmd&VM_OPCALLNUM,cmd&VM_DBGINFO);
} }
int main(int argc,const char* argv[]) int main(int argc,const char* argv[])
@ -113,7 +115,7 @@ int main(int argc,const char* argv[])
execute(argv[1],VM_EXEC); execute(argv[1],VM_EXEC);
else if(argc>=3) else if(argc>=3)
{ {
uint16_t cmd=0; uint32_t cmd=0;
for(int i=1;i<argc-1;++i) for(int i=1;i<argc-1;++i)
{ {
std::string s(argv[i]); std::string s(argv[i]);
@ -127,6 +129,8 @@ int main(int argc,const char* argv[])
cmd|=VM_OPCALLNUM|VM_EXEC; cmd|=VM_OPCALLNUM|VM_EXEC;
else if(s=="--time" || s=="-t") else if(s=="--time" || s=="-t")
cmd|=VM_EXECTIME; cmd|=VM_EXECTIME;
else if(s=="--detail" || s=="-d")
cmd|=VM_DBGINFO|VM_EXEC;
else else
err(); err();
} }

5
makefile Normal file
View File

@ -0,0 +1,5 @@
.PHONY=clean
nasal:main.cpp nasal_ast.h nasal_builtin.h nasal_codegen.h nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal.h
-@ clang++ -std=c++11 -O3 main.cpp -o nasal -fno-exceptions
clean:
-@ rm nasal

19
nasal.h
View File

@ -20,25 +20,6 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
class nasal_err
{
private:
uint32_t error;
std::string stage;
public:
nasal_err(
const uint32_t _error,
const std::string _stage
):error(_error),stage(_stage){}
void unwarp(const std::string& error_file)
{
if(!error)
return;
std::cout<<"["<<stage<<"] in <"<<error_file<<">: error(s) occurred,stop.\n";
std::exit(1);
}
};
/* /*
check if a string can be converted to a number check if a string can be converted to a number
if this string cannot be converted to a number,it will return nan if this string cannot be converted to a number,it will return nan

View File

@ -27,11 +27,14 @@ private:
const std::vector<std::string>&); const std::vector<std::string>&);
void clear(); void clear();
/* debug functions */ /* debug functions */
bool detail_info;
void valinfo(nasal_ref&);
void bytecodeinfo(const uint32_t); void bytecodeinfo(const uint32_t);
void traceback(); void traceback();
void stackinfo(const uint32_t); void stackinfo(const uint32_t);
void detail();
void opcallsort(const uint64_t*);
void die(std::string); void die(std::string);
void stackoverflow();
/* vm calculation functions*/ /* vm calculation functions*/
bool condition(nasal_ref); bool condition(nasal_ref);
void opr_nop(); void opr_nop();
@ -115,7 +118,11 @@ private:
public: public:
nasal_vm():stack_top(gc.stack_top){} nasal_vm():stack_top(gc.stack_top){}
~nasal_vm(){clear();} ~nasal_vm(){clear();}
void run(const nasal_codegen&,const nasal_import&,const bool); void run(
const nasal_codegen&,
const nasal_import&,
const bool,
const bool);
}; };
void nasal_vm::init( void nasal_vm::init(
@ -136,6 +143,22 @@ void nasal_vm::clear()
while(!counter.empty()) while(!counter.empty())
counter.pop(); counter.pop();
str_table.clear(); str_table.clear();
imm.clear();
}
void nasal_vm::valinfo(nasal_ref& val)
{
const nasal_val* ptr=val.value.gcobj;
switch(val.type)
{
case vm_none: printf("\tnull |\n");break;
case vm_nil: printf("\tnil |\n");break;
case vm_num: printf("\tnum | %lf\n",val.num());break;
case vm_str: printf("\tstr | <%p> %s\n",ptr,raw_string(*val.str()).c_str());break;
case vm_func: printf("\tfunc | <%p> func{entry=0x%x}\n",ptr,val.func()->entry);break;
case vm_vec: printf("\tvec | <%p> [%lu val]\n",ptr,val.vec()->elems.size());break;
case vm_hash: printf("\thash | <%p> {%lu member}\n",ptr,val.hash()->elems.size());break;
case vm_obj: printf("\tobj | <%p>\n",ptr);break;
}
} }
void nasal_vm::bytecodeinfo(const uint32_t p) void nasal_vm::bytecodeinfo(const uint32_t p)
{ {
@ -143,10 +166,12 @@ void nasal_vm::bytecodeinfo(const uint32_t p)
printf("\t0x%.8x: %s 0x%x",p,code_table[code.op].name,code.num); printf("\t0x%.8x: %s 0x%x",p,code_table[code.op].name,code.num);
if(code.op==op_callb) if(code.op==op_callb)
printf(" <%s>",builtin_func[code.num].name); printf(" <%s>",builtin_func[code.num].name);
printf(" (%s line %d)\n",files[code.fidx].c_str(),code.line); printf(" (<%s> line %d)\n",files[code.fidx].c_str(),code.line);
} }
void nasal_vm::traceback() void nasal_vm::traceback()
{ {
// push pc to ret stack to store the position program crashed
ret.push(pc);
printf("trace back:\n"); printf("trace back:\n");
uint32_t same_cnt=0,last_point=0xffffffff; uint32_t same_cnt=0,last_point=0xffffffff;
for(uint32_t point=0;!ret.empty();last_point=point,ret.pop()) for(uint32_t point=0;!ret.empty();last_point=point,ret.pop())
@ -185,36 +210,58 @@ void nasal_vm::stackinfo(const uint32_t limit)
same_cnt=0; same_cnt=0;
} }
last_ptr=stack_top[0]; last_ptr=stack_top[0];
const nasal_val* ptr=stack_top[0].value.gcobj; valinfo(stack_top[0]);
switch(stack_top[0].type)
{
case vm_none: printf("\tnull |\n");break;
case vm_nil: printf("\tnil |\n");break;
case vm_num: printf("\tnum | %lf\n",stack_top[0].num());break;
case vm_str: printf("\tstr | <%p> %s\n",ptr,raw_string(*stack_top[0].str()).c_str());break;
case vm_func: printf("\tfunc | <%p> func{entry=0x%x}\n",ptr,stack_top[0].func()->entry);break;
case vm_vec: printf("\tvec | <%p> [%lu val]\n",ptr,stack_top[0].vec()->elems.size());break;
case vm_hash: printf("\thash | <%p> {%lu member}\n",ptr,stack_top[0].hash()->elems.size());break;
case vm_obj: printf("\tobj | <%p>\n",ptr);break;
}
} }
if(same_cnt) if(same_cnt)
printf("\t... | %d same value(s)\n",same_cnt); printf("\t... | %d same value(s)\n",same_cnt);
} }
void nasal_vm::detail()
{
printf("mcall address: %p\n",mem_addr);
printf("global value:\n");
// bytecode[0] is op_intg
for(uint32_t i=0;i<bytecode[0].num;++i)
{
printf("[%d]",i);
valinfo(gc.val_stack[i]);
}
if(!gc.local.empty())
{
printf("local value:\n");
auto& vec=gc.local.back().vec()->elems;
for(uint32_t i=0;i<vec.size();++i)
{
printf("[%d]",i);
valinfo(vec[i]);
}
}
}
void nasal_vm::opcallsort(const uint64_t* arr)
{
typedef std::pair<uint32_t,uint64_t> op;
std::vector<op> opcall;
for(uint32_t i=0;i<=op_exit;++i)
opcall.push_back({i,arr[i]});
std::sort(
opcall.begin(),
opcall.end(),
[](op& a,op& b){return a.second>b.second;}
);
std::cout<<'\n';
for(auto& i:opcall)
{
if(!i.second)
break;
std::cout<<code_table[i.first].name<<": "<<i.second<<'\n';
}
}
void nasal_vm::die(std::string str) void nasal_vm::die(std::string str)
{ {
printf("[vm] error at 0x%.8x: %s\n",pc,str.c_str()); printf("[vm] %s\n",str.c_str());
// trace back will use ret_stack
ret.push(pc);
traceback();
stackinfo(10);
std::exit(1);
}
void nasal_vm::stackoverflow()
{
printf("[vm] stack overflow\n");
traceback(); traceback();
stackinfo(10); stackinfo(10);
if(detail_info)
detail();
std::exit(1); std::exit(1);
} }
inline bool nasal_vm::condition(nasal_ref val) inline bool nasal_vm::condition(nasal_ref val)
@ -775,8 +822,13 @@ inline void nasal_vm::opr_ret()
gc.local.pop_back(); // pop local scope gc.local.pop_back(); // pop local scope
pc=ret.top();ret.pop(); // fetch pc pc=ret.top();ret.pop(); // fetch pc
} }
void nasal_vm::run(const nasal_codegen& gen,const nasal_import& linker,const bool opcnt) void nasal_vm::run(
const nasal_codegen& gen,
const nasal_import& linker,
const bool opcnt,
const bool debug=false)
{ {
detail_info=debug;
init(gen.get_strs(),gen.get_nums(),linker.get_file()); init(gen.get_strs(),gen.get_nums(),linker.get_file());
uint64_t count[op_exit+1]={0}; uint64_t count[op_exit+1]={0};
const void* opr_table[]= const void* opr_table[]=
@ -819,23 +871,9 @@ void nasal_vm::run(const nasal_codegen& gen,const nasal_import& linker,const boo
vmexit: vmexit:
if(canary.value.gcobj) if(canary.value.gcobj)
stackoverflow(); die("stack overflow");
if(opcnt) if(opcnt)
{ opcallsort(count);
std::cout<<std::endl;
for(int i=0;i<15;++i)
{
uint64_t maxnum=0,index=0;
for(int j=0;j<op_ret+1;++j)
if(count[j]>maxnum)
{
index=j;
maxnum=count[j];
}
std::cout<<code_table[index].name<<": "<<maxnum<<"\n";
count[index]=0;
}
}
clear(); clear();
return; return;
// may cause stackoverflow // may cause stackoverflow