#include "bbdebug.h" #include "bbarray.h" #include #if _WIN32 #include #include #endif #include typedef void(*dbEmit_t)(void*); namespace bbDB{ int nextSeq; bbDBContext *currentContext; #if !_WIN32 void breakHandler( int sig ){ currentContext->stopped=0x10000000; } #endif void sighandler( int sig ){ const char *err="Unknown signal"; switch( sig ){ case SIGSEGV:err="Memory access violation";break; case SIGILL:err="Illegal instruction"; case SIGFPE:err="Floating point exception"; #if !_WIN32 case SIGBUS:err="Bus error"; #endif } #ifndef NDEBUG error( err ); exit( 0 ); #endif bb_printf( "Caught signal:%s\n",err ); exit( -1 ); } void init(){ currentContext=new bbDBContext; currentContext->init(); signal( SIGSEGV,sighandler ); signal( SIGILL,sighandler ); signal( SIGFPE,sighandler ); #if !_WIN32 signal( SIGBUS,sighandler ); #endif #ifndef NDEBUG #if _WIN32 if( HANDLE breakEvent=OpenEvent( EVENT_ALL_ACCESS,false,"MX2_BREAK_EVENT" ) ){ // bb_printf( "Found BREAK_EVENT!\n" );fflush( stdout ); std::thread( [=](){ for( ;; ){ WaitForSingleObject( breakEvent,INFINITE ); // bb_printf( "Break event!\n" );fflush( stdout ); currentContext->stopped=0x10000000; } } ).detach(); } #else signal( SIGTSTP,breakHandler ); #endif #endif } void emitVar( bbDBVar *v ){ bbString id=v->name; bbString type=v->type->type(); bbString value=v->type->value( v->var ); bbString t=id+":"+type+"="+value+"\n"; bb_printf( "%s",t.c_str() ); } void emitStack(){ bbDBVar *ev=currentContext->locals; for( bbDBFrame *f=currentContext->frames;f;f=f->succ ){ bb_printf( ">%s;%s;%i;%i\n",f->decl,f->srcFile,f->srcPos>>12,f->seq ); for( bbDBVar *v=f->locals;v!=ev;++v ){ emitVar( v ); } ev=f->locals; } } void stop(){ currentContext->stopped=0; } void emit( const char *e ){ if( const char *p=strchr( e,':' ) ){ dbEmit_t dbEmit=(dbEmit_t)( strtol( p+1,0,16 ) ); dbEmit( (void*)strtol( e,0,16 ) ); }else{ bbGCNode *node=(bbGCNode*)strtol( e,0,16 ); node->dbEmit(); } puts( "" ); fflush( stdout ); } void stopped(){ bb_printf( "{{!DEBUG!}}\n" ); emitStack(); bb_printf( "\n" ); fflush( stdout ); for(;;){ char buf[256]; char *e=fgets( buf,256,stdin ); if( !e ) exit( -1 ); switch( e[0] ){ case 's':currentContext->stopped=0;return; case 'e':currentContext->stopped=1;return; case 'l':currentContext->stopped=-1;return; case 'r':currentContext->stopped=-0x10000000;return; case '@':emit( e+1 );continue; case 'q':exit( 0 );return; } bb_printf( "Unrecognized debug cmd: %s\n",buf );fflush( stdout ); exit( -1 ); } } void error( bbString msg ){ bb_printf( "\n%s\n",msg.c_str() ); stopped(); } bbArray stack(){ int n=0; for( bbDBFrame *frame=currentContext->frames;frame;frame=frame->succ ) ++n; //TODO: Fix GC issues! Can't have a free local like this in case bbString ctors cause gc sweep!!!! bbArray st=bbArray( n ); int i=0; for( bbDBFrame *frame=currentContext->frames;frame;frame=frame->succ ){ st[i++]=BB_T( frame->srcFile )+" ["+bbString( frame->srcPos>>12 )+"] "+frame->decl; } return st; } } void bbDBContext::init(){ if( !localsBuf ) localsBuf=new bbDBVar[16384]; locals=localsBuf; frames=nullptr; stopped=0; } bbDBContext::~bbDBContext(){ delete[] localsBuf; } bbString bbDBValue( bbString *p ){ bbString t=*p,dd=""; if( t.length()>100 ){ t=t.slice( 0,100 ); dd="..."; } t=t.replace( "\"","~q" ); t=t.replace( "\n","~n" ); t=t.replace( "\r","~r" ); t=t.replace( "\t","~t" ); return BB_T("\"")+t+"\""+dd; }