Browse Source

debugger progress (pause/run/stack working)

Nicolas Cannasse 8 years ago
parent
commit
fc79ba66f7
8 changed files with 221 additions and 39 deletions
  1. 6 1
      libs/sdl/sdl.c
  2. 14 18
      libs/ui/ui_win.c
  3. 82 3
      src/debugger.c
  4. 7 0
      src/hl.h
  5. 3 2
      src/hlmodule.h
  6. 6 1
      src/main.c
  7. 25 13
      src/module.c
  8. 78 1
      src/std/thread.c

+ 6 - 1
libs/sdl/sdl.c

@@ -251,12 +251,17 @@ DEFINE_PRIM(_BOOL, detect_win32, _NO_ARG);
 // Window
 
 HL_PRIM SDL_Window *HL_NAME(win_create)(vbyte *title, int width, int height) {
+	SDL_Window *w;
 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
-	return SDL_CreateWindow((char*)title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
+	w = SDL_CreateWindow((char*)title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
+	// force window to show even if the debugger force process windows to be hidden
+	SDL_HideWindow(w);
+	SDL_ShowWindow(w);
+	return w;
 }
 
 HL_PRIM SDL_GLContext HL_NAME(win_get_glcontext)(SDL_Window *win) {

+ 14 - 18
libs/ui/ui_win.c

@@ -191,8 +191,8 @@ HL_PRIM void HL_NAME(ui_stop_loop)() {
 }
 
 typedef struct {
-	HANDLE thread;
-	HANDLE original;
+	hl_thread *thread;
+	hl_thread *original;
 	void *callback;
 	double timeout;
 	int ticks;
@@ -200,6 +200,9 @@ typedef struct {
 
 static void sentinel_loop( vsentinel *s ) {
 	int time_ms = (int)((s->timeout * 1000.) / 16.);
+	hl_thread_registers *regs = (hl_thread_registers*)malloc(sizeof(int_val) * hl_thread_context_size());
+	int eip = hl_thread_context_index("eip");
+	int esp = hl_thread_context_index("esp");
 	while( true ) {
 		int k = 0;
 		int tick = s->ticks;
@@ -208,23 +211,16 @@ static void sentinel_loop( vsentinel *s ) {
 			if( tick != s->ticks ) break;
 			k++;
 			if( k == 16 ) {
-				// Wakeup
-				CONTEXT ctx;
-				ctx.ContextFlags = CONTEXT_FULL;
-				SuspendThread(s->original);
-				GetThreadContext(s->original,&ctx);
+				// pause
+				hl_thread_pause(s->original, true);
+				hl_thread_get_context(s->original,regs);
 				// simulate a call
-#				ifdef HL_64
-				*--((int_val*)ctx.Rsp) = ctx.Rip;
-				*--((int_val*)ctx.Rsp) = ctx.Rsp;
-				ctx.Rip = (int_val)s->callback;
-#				else
-				*--((int*)ctx.Esp) = ctx.Eip;
-				*--((int*)ctx.Esp) = ctx.Esp;
-				ctx.Eip = (DWORD)s->callback;
-#				endif
-				SetThreadContext(s->original,&ctx);
-				ResumeThread(s->original);
+				*--(int_val*)regs[esp] = regs[eip];
+				*--(int_val*)regs[esp] = regs[esp];
+				regs[eip] = (int_val)s->callback;
+				// resume
+				hl_thread_set_context(s->original,regs);
+				hl_thread_pause(s->original, false);
 				break;
 			}
 		}

+ 82 - 3
src/debugger.c

@@ -31,18 +31,89 @@ HL_API bool hl_socket_listen( hl_socket *s, int n );
 HL_API void hl_socket_close( hl_socket *s );
 HL_API hl_socket *hl_socket_accept( hl_socket *s );
 HL_API bool hl_socket_set_timeout( hl_socket *s, double t );
+HL_API void hl_sys_sleep( double t );
+HL_API int hl_socket_send( hl_socket *s, vbyte *buf, int pos, int len );
+HL_API int hl_socket_recv( hl_socket *s, vbyte *buf, int pos, int len );
 
-static hl_socket *debug_socket;
+static hl_thread *main_thread = NULL;
+static hl_socket *debug_socket = NULL;
+static hl_socket *client_socket = NULL;
+static bool debugger_connected = false;
+static bool kill_on_debug_exit = false;
+
+typedef enum {
+	Run = 0,
+	Pause = 1,
+	Resume = 2,
+	Stop = 3,
+	Stack = 4,
+} Command;
+
+static void dbg_send( Command cmd ) {
+	vbyte c = (vbyte)cmd;
+	hl_socket_send(client_socket, &c, 0, 1);
+}
+
+#define STACK_SIZE 256
 
 static void hl_debug_loop( hl_module *m ) {
+	vbyte cmd;
+	void *stack[STACK_SIZE];
+	hl_thread_registers *regs = (hl_thread_registers*)malloc(sizeof(int_val) * hl_thread_context_size());
+	int i_esp = hl_thread_context_index("esp");
+//	int eip = hl_thread_context_index("eip");
 	while( true ) {
 		hl_socket *s = hl_socket_accept(debug_socket);
-		printf("CONNECTED\n");
+		client_socket = s;
+		while( true ) {
+			if( hl_socket_recv(s,&cmd,0,1) != 1 ) {
+				hl_socket_close(s);
+				if( kill_on_debug_exit ) exit(-9);
+				break;
+			}
+			switch( cmd ) {
+			case Run:
+				debugger_connected = true;
+				break;
+			case Pause:
+				hl_thread_pause(main_thread, true);
+				break;
+			case Resume:
+				hl_thread_pause(main_thread, false);
+				break;
+			case Stack:
+				if( !hl_thread_get_context(main_thread, regs) )
+					exit(-10);
+				{
+					int i;
+					int size = hl_module_capture_stack(stack,STACK_SIZE,(void**)regs[i_esp]);
+					hl_socket_send(s,(vbyte*)&size,0,4);
+					for(i=0;i<size;i++) {
+						struct {
+							int fidx;
+							int fpos;
+						} inf;
+						if( !hl_module_resolve_pos(stack[i],&inf.fidx,&inf.fpos) ) {
+							inf.fidx = -1;
+							inf.fpos = -1;
+						}
+						hl_socket_send(s,(vbyte*)&inf,0,8);
+					}
+				}
+				break;
+			case Stop:
+				exit(-9);
+				break;
+			default:
+				fprintf(stderr,"Unknown debug command [%d]\n",cmd);
+				break;
+			}
+		}
 		hl_socket_close(s);
 	}
 }
 
-bool hl_module_debug( hl_module *m, int port ) {
+bool hl_module_debug( hl_module *m, int port, bool wait ) {
 	hl_socket *s;
 	hl_socket_init();
 	s = hl_socket_new(false);
@@ -51,10 +122,18 @@ bool hl_module_debug( hl_module *m, int port ) {
 		hl_socket_close(s);
 		return false;
 	}
+	hl_add_root(&debug_socket);
+	hl_add_root(&client_socket);
+	main_thread = hl_thread_current();
 	debug_socket = s;
+	if( wait ) kill_on_debug_exit = true;
 	if( !hl_thread_start(hl_debug_loop, m, false) ) {
 		hl_socket_close(s);
 		return false;
 	}
+	if( wait ) {
+		while( !debugger_connected )
+			hl_sys_sleep(0.01);
+	}
 	return true;
 }

+ 7 - 0
src/hl.h

@@ -484,8 +484,15 @@ HL_API vdynamic *hl_dyn_call( vclosure *c, vdynamic **args, int nargs );
 
 struct _hl_thread;
 typedef struct _hl_thread hl_thread;
+typedef int_val hl_thread_registers;
+
 HL_API hl_thread *hl_thread_start( void *callback, void *param, bool withGC );
 HL_API hl_thread *hl_thread_current();
+HL_API bool hl_thread_pause( hl_thread *t, bool pause );
+HL_API int hl_thread_context_size();
+HL_API int hl_thread_context_index( const char *name );
+HL_API bool hl_thread_get_context( hl_thread *t, hl_thread_registers *regs );
+HL_API bool hl_thread_set_context( hl_thread *t, hl_thread_registers *regs );
 
 // ----------------------- ALLOC --------------------------------------------------
 

+ 3 - 2
src/hlmodule.h

@@ -105,13 +105,14 @@ const char* hl_op_name( int op );
 hl_module *hl_module_alloc( hl_code *code );
 int hl_module_init( hl_module *m );
 void hl_module_free( hl_module *m );
-bool hl_module_debug( hl_module *m, int port );
+bool hl_module_debug( hl_module *m, int port, bool wait );
 
 jit_ctx *hl_jit_alloc();
 void hl_jit_free( jit_ctx *ctx );
 void hl_jit_init( jit_ctx *ctx, hl_module *m );
 int hl_jit_init_callback( jit_ctx *ctx );
-void hl_jit_init_setfp( jit_ctx *ctx, int *ff, int *fd );
 int hl_jit_function( jit_ctx *ctx, hl_module *m, hl_function *f );
 void *hl_jit_code( jit_ctx *ctx, hl_module *m, int *codesize, hl_debug_infos **debug );
 
+int hl_module_capture_stack( void **stack, int size, void **stack_ptr );
+bool hl_module_resolve_pos( void *addr, int *fidx, int *fpos );

+ 6 - 1
src/main.c

@@ -93,6 +93,7 @@ int main(int argc, pchar *argv[]) {
 #endif
 	pchar *file = NULL;
 	int debug_port = -1;
+	bool debug_wait = false;
 	struct {
 		hl_code *code;
 		hl_module *m;
@@ -108,6 +109,10 @@ int main(int argc, pchar *argv[]) {
 			debug_port = ptoi(*argv++);
 			continue;
 		}
+		if( pcompare(arg,PSTR("--debug-wait")) == 0 ) {
+			debug_wait = true;
+			continue;
+		}
 		file = arg;
 		break;
 	}
@@ -126,7 +131,7 @@ int main(int argc, pchar *argv[]) {
 	if( !hl_module_init(ctx.m) )
 		return 3;
 	hl_code_free(ctx.code);
-	if( debug_port > 0 && !hl_module_debug(ctx.m,debug_port) ) {
+	if( debug_port > 0 && !hl_module_debug(ctx.m,debug_port,debug_wait) ) {
 		fprintf(stderr,"Could not start debugger on port %d",debug_port);
 		return 4;
 	}

+ 25 - 13
src/module.c

@@ -34,18 +34,13 @@ extern void hl_callback_init( void *e );
 static hl_module *cur_module;
 static void *stack_top;
 
-static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
+bool hl_module_resolve_pos( void *addr, int *fidx, int *fpos ) {
 	int code_pos = ((int)(int_val)((unsigned char*)addr - (unsigned char*)cur_module->jit_code));
 	int min, max;
 	hl_debug_infos *dbg;
 	hl_function *fdebug;
-	int *debug_addr;
-	int file, line;
-	int size = *outSize;
-	int pos = 0;
-
 	if( cur_module->jit_debug == NULL )
-		return NULL;
+		return false;
 	// lookup function from code pos
 	min = 0;
 	max = cur_module->code->nfunctions;
@@ -58,7 +53,8 @@ static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 			max = mid;
 	}
 	if( min == 0 )
-		return NULL; // hl_callback
+		return false; // hl_callback
+	*fidx = (min - 1);
 	dbg = cur_module->jit_debug + (min - 1);
 	fdebug = cur_module->code->functions + (min - 1);
 	// lookup inside function
@@ -74,10 +70,23 @@ static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 			max = mid;
 	}
 	if( min == 0 )
-		return NULL; // ???
-	code_pos = min - 1;
+		return false; // ???
+	*fpos = min - 1;
+	return true;
+}
+
+static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
+	int *debug_addr;
+	int file, line;
+	int size = *outSize;
+	int pos = 0;
+	int fidx, fpos;
+	hl_function *fdebug;
+	if( !hl_module_resolve_pos(addr,&fidx,&fpos) )
+		return NULL;
 	// extract debug info
-	debug_addr = fdebug->debug + ((code_pos&0xFFFF) * 2);
+	fdebug = cur_module->code->functions + fidx;
+	debug_addr = fdebug->debug + ((fpos&0xFFFF) * 2);
 	file = debug_addr[0];
 	line = debug_addr[1];
 	if( fdebug->obj )
@@ -90,8 +99,7 @@ static uchar *module_resolve_symbol( void *addr, uchar *out, int *outSize ) {
 	return out;
 }
 
-static int module_capture_stack( void **stack, int size ) {
-	void **stack_ptr = (void**)&stack;
+int hl_module_capture_stack( void **stack, int size, void **stack_ptr ) {
 	void *stack_bottom = stack_ptr;
 	int count = 0;
 	unsigned char *code = cur_module->jit_code;
@@ -115,6 +123,10 @@ static int module_capture_stack( void **stack, int size ) {
 	return count;
 }
 
+static int module_capture_stack( void **stack, int size ) {
+	return hl_module_capture_stack(stack,size,(void**)&stack);
+}
+
 static void hl_init_enum( hl_type_enum *e ) {
 	int i, j;
 	for(i=0;i<e->nconstructs;i++) {

+ 78 - 1
src/std/thread.c

@@ -54,4 +54,81 @@ HL_PRIM hl_thread *hl_thread_start( void *callback, void *param, bool withGC ) {
 	pthread_attr_destroy(&attr);
 	return (hl_thread*)t;
 #	endif
-}
+}
+
+HL_PRIM bool hl_thread_pause( hl_thread *t, bool pause ) {
+#	ifdef HL_WIN
+	bool ret;
+	HANDLE h = OpenThread(THREAD_ALL_ACCESS,FALSE,(DWORD)t);
+	if( pause ) 
+		ret = ((int)SuspendThread(h)) >= 0;
+	else {
+		int r;
+		while( (r = (int)ResumeThread(h)) > 0 ) {
+		}
+		ret = r == 0;
+	}
+	CloseHandle(h);
+	return ret;
+#	else
+	// TODO : use libthread_db
+	return false;
+#	endif
+}
+
+HL_PRIM int hl_thread_context_size() {
+#	ifdef HL_WIN
+	return (sizeof(CONTEXT) + sizeof(int_val) - 1) / sizeof(int_val);
+#	else
+	return 0;
+#	endif
+}
+
+HL_API int hl_thread_context_index( const char *name ) {
+#	ifdef HL_WIN
+	CONTEXT *c = NULL;
+#	define _ADDR(__r) (((int_val)&c->__r) / sizeof(int_val))
+#	ifdef HL_64
+#		define ADDR(_,r) _ADDR(r)
+#	else
+#		define ADDR(r,_) _ADDR(r)
+#	endif
+	if( strcmp(name,"eip") == 0 )
+		return ADDR(Eip,Rip);
+	if( strcmp(name,"esp") == 0 )
+		return ADDR(Esp,Rsp);
+	return -1;
+#	else
+	return -1;
+#	endif
+#	undef ADDR
+#	undef _ADDR
+}
+
+HL_API bool hl_thread_get_context( hl_thread *t, hl_thread_registers *regs ) {
+#	ifdef HL_WIN
+	HANDLE h = OpenThread(THREAD_ALL_ACCESS,FALSE,(DWORD)t);
+	bool ret;
+	CONTEXT *c = (CONTEXT*)regs;
+	c->ContextFlags = CONTEXT_FULL;
+	ret = (bool)GetThreadContext(h,c);
+	CloseHandle(h);
+	return ret;
+#	else
+	return false;
+#	endif
+}
+
+HL_API bool hl_thread_set_context( hl_thread *t, hl_thread_registers *regs ) {
+#	ifdef HL_WIN
+	HANDLE h = OpenThread(THREAD_ALL_ACCESS,FALSE,(DWORD)t);
+	bool ret;
+	CONTEXT *c = (CONTEXT*)regs;
+	c->ContextFlags = CONTEXT_FULL;
+	ret = (bool)SetThreadContext(h,c);
+	CloseHandle(h);
+	return ret;
+#	else
+	return false;
+#	endif
+}