Selaa lähdekoodia

linux debugging support using ptrace()

Nicolas Cannasse 7 vuotta sitten
vanhempi
commit
c378af1643
2 muutettua tiedostoa jossa 92 lisäystä ja 13 poistoa
  1. 1 1
      Makefile
  2. 91 12
      src/std/debug.c

+ 1 - 1
Makefile

@@ -20,7 +20,7 @@ PCRE = include/pcre/pcre_chartables.o include/pcre/pcre_compile.o include/pcre/p
 
 RUNTIME = src/alloc.o
 
-STD = src/std/array.o src/std/buffer.o src/std/bytes.o src/std/cast.o src/std/date.o src/std/error.o \
+STD = src/std/array.o src/std/buffer.o src/std/bytes.o src/std/cast.o src/std/date.o src/std/error.o src/std/debug.o \
 	src/std/file.o src/std/fun.o src/std/maps.o src/std/math.o src/std/obj.o src/std/random.o src/std/regexp.o \
 	src/std/socket.o src/std/string.o src/std/sys.o src/std/types.o src/std/ucs2.o src/std/thread.o src/std/process.o
 

+ 91 - 12
src/std/debug.c

@@ -20,8 +20,15 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include <hl.h>
+#ifdef HL_LINUX
+#	include <sys/ptrace.h>
+#	include <sys/wait.h>
+#	include <sys/user.h>
+#	include <signal.h>
+#	define USE_PTRACE
+#endif
 
-#ifdef HL_WIN
+#if defined(HL_WIN)
 static HANDLE last_process = NULL, last_thread = NULL;
 static int last_pid = -1;
 static int last_tid = -1;
@@ -52,58 +59,110 @@ static void CleanHandles() {
 #endif
 
 HL_API bool hl_debug_start( int pid ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	last_pid = -1;
 	return (bool)DebugActiveProcess(pid);
+#	elif defined(USE_PTRACE)
+	return ptrace(PTRACE_ATTACH,pid,0,0) >= 0;
 #	else
 	return false;
 #	endif
 }
 
 HL_API bool hl_debug_stop( int pid ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	BOOL b = DebugActiveProcessStop(pid);
 	CleanHandles();
 	return (bool)b;
+#	elif defined(USE_PTRACE)
+	return ptrace(PTRACE_DETACH,pid,0,0) >= 0;
 #	else
 	return false;
 #	endif
 }
 
 HL_API bool hl_debug_breakpoint( int pid ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	return (bool)DebugBreakProcess(OpenPID(pid));
+#	elif defined(USE_PTRACE)
+	return kill(pid,SIGTRAP) == 0;
 #	else
 	return false;
 #	endif
 }
 
 HL_API bool hl_debug_read( int pid, vbyte *addr, vbyte *buffer, int size ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	return (bool)ReadProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
+#	elif defined(USE_PTRACE)
+	while( size ) {
+		long v = ptrace(PTRACE_PEEKDATA,pid,addr,0);
+		if( size >= sizeof(long) )
+			*(long*)buffer = v;
+		else {
+			memcpy(buffer,&v,size);
+			break;
+		}
+		addr += sizeof(long);
+		size -= sizeof(long);
+		buffer += sizeof(long);
+	}
+	return true;	
 #	else
 	return false;
 #	endif
 }
 
 HL_API bool hl_debug_write( int pid, vbyte *addr, vbyte *buffer, int size ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	return (bool)WriteProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
+#	elif defined(USE_PTRACE)
+	while( size ) {
+		int sz = size >= sizeof(long) ? sizeof(long) : size;
+		long v = *(long*)buffer;
+		if( sz != sizeof(long) ) {
+			long cur = ptrace(PTRACE_PEEKDATA,pid,addr);
+			memcpy((char*)&v+sz,(char*)&cur+sz,sizeof(long)-sz);
+		}
+		if( ptrace(PTRACE_POKEDATA,pid,addr,v) < 0 )
+			return false;
+		addr += sz;
+		size -= sz;
+		buffer += sz;
+	}
+	return true;
 #	else
 	return false;
 #	endif
 }
 
 HL_API bool hl_debug_flush( int pid, vbyte *addr, int size ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	return (bool)FlushInstructionCache(OpenPID(pid),addr,size);
+#	elif defined(USE_PTRACE)
+	return true;
 #	else
 	return false;
 #	endif
 }
 
+#ifdef USE_PTRACE
+static void *get_reg( int r ) {
+		struct user_regs_struct *regs = NULL;
+		struct user *user = NULL;
+		switch( r ) {
+		case 0: return &regs->rsp;
+		case 1: return &regs->rbp;
+		case 2: return &regs->rip;
+		case 3: return &regs->eflags;
+		default: return &user->u_debugreg[r-4];
+		}
+		return NULL;
+}
+#endif
+
 HL_API int hl_debug_wait( int pid, int *thread, int timeout ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	DEBUG_EVENT e;
 	if( !WaitForDebugEvent(&e,timeout) )
 		return -1;
@@ -133,14 +192,31 @@ HL_API int hl_debug_wait( int pid, int *thread, int timeout ) {
 		break;
 	}
 	return 4;
+#	elif defined(USE_PTRACE)
+	int status;
+	int ret = waitpid(pid,&status,0);
+	//printf("WAITPID=%X %X\n",ret,status);
+	*thread = ret;
+	if( WIFEXITED(status) )
+		return 0;
+	if( WIFSTOPPED(status) ) {
+		int sig = WSTOPSIG(status);
+		//printf(" STOPSIG=%d\n",sig);
+		if( sig == SIGSTOP || sig == SIGTRAP )
+			return 1;
+		return 3;
+	}	
+	return 4;
 #	else
 	return 0;
 #	endif
 }
 
 HL_API bool hl_debug_resume( int pid, int thread ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 	return (bool)ContinueDebugEvent(pid, thread, DBG_CONTINUE);
+#	elif defined(USE_PTRACE)
+	return ptrace(PTRACE_CONT,pid,0,0) >= 0;
 #	else
 	return false;
 #	endif
@@ -178,9 +254,8 @@ DefineGetReg(CONTEXT,GetContextReg);
 
 #endif
 
-
 HL_API void *hl_debug_read_register( int pid, int thread, int reg, bool is64 ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 #	ifdef HL_64
 	if( !is64 ) {
 		WOW64_CONTEXT c;
@@ -201,13 +276,15 @@ HL_API void *hl_debug_read_register( int pid, int thread, int reg, bool is64 ) {
 	if( reg == 3 )
 		return (void*)(int_val)c.EFlags;
 	return (void*)*GetContextReg(&c,reg);
+#	elif defined(USE_PTRACE)
+	return (void*)ptrace(PTRACE_PEEKUSER,thread,get_reg(reg),0);
 #	else
 	return NULL;
 #	endif
 }
 
 HL_API bool hl_debug_write_register( int pid, int thread, int reg, void *value, bool is64 ) {
-#	ifdef HL_WIN
+#	if defined(HL_WIN)
 #	ifdef HL_64
 	if( !is64 ) {
 		WOW64_CONTEXT c;
@@ -232,6 +309,8 @@ HL_API bool hl_debug_write_register( int pid, int thread, int reg, void *value,
 	else
 		*GetContextReg(&c,reg) = (REGDATA)value;
 	return (bool)SetThreadContext(OpenTID(thread),&c);
+#	elif defined(USE_PTRACE)
+	return ptrace(PTRACE_POKEUSER,thread,get_reg(reg),value) >= 0;
 #	else
 	return false;
 #	endif