|
@@ -22,6 +22,12 @@
|
|
#include <hl.h>
|
|
#include <hl.h>
|
|
#include <hlmodule.h>
|
|
#include <hlmodule.h>
|
|
|
|
|
|
|
|
+#ifdef HL_LINUX
|
|
|
|
+#include <signal.h>
|
|
|
|
+#include <semaphore.h>
|
|
|
|
+#include <unistd.h>
|
|
|
|
+#endif
|
|
|
|
+
|
|
#define MAX_STACK_SIZE (8 << 20)
|
|
#define MAX_STACK_SIZE (8 << 20)
|
|
#define MAX_STACK_COUNT 2048
|
|
#define MAX_STACK_COUNT 2048
|
|
|
|
|
|
@@ -73,6 +79,25 @@ static struct {
|
|
profile_data *first_record;
|
|
profile_data *first_record;
|
|
} data = {0};
|
|
} data = {0};
|
|
|
|
|
|
|
|
+#ifdef HL_LINUX
|
|
|
|
+static struct
|
|
|
|
+{
|
|
|
|
+ sem_t msg2;
|
|
|
|
+ sem_t msg3;
|
|
|
|
+ sem_t msg4;
|
|
|
|
+ ucontext_t context;
|
|
|
|
+} shared_context;
|
|
|
|
+
|
|
|
|
+static void sigprof_handler(int sig, siginfo_t *info, void *ucontext)
|
|
|
|
+{
|
|
|
|
+ ucontext_t *ctx = ucontext;
|
|
|
|
+ shared_context.context = *ctx;
|
|
|
|
+ sem_post(&shared_context.msg2);
|
|
|
|
+ sem_wait(&shared_context.msg3);
|
|
|
|
+ sem_post(&shared_context.msg4);
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
static void *get_thread_stackptr( thread_handle *t, void **eip ) {
|
|
static void *get_thread_stackptr( thread_handle *t, void **eip ) {
|
|
#ifdef HL_WIN_DESKTOP
|
|
#ifdef HL_WIN_DESKTOP
|
|
CONTEXT c;
|
|
CONTEXT c;
|
|
@@ -85,6 +110,14 @@ static void *get_thread_stackptr( thread_handle *t, void **eip ) {
|
|
*eip = (void*)c.Eip;
|
|
*eip = (void*)c.Eip;
|
|
return (void*)c.Esp;
|
|
return (void*)c.Esp;
|
|
# endif
|
|
# endif
|
|
|
|
+#elif defined(HL_LINUX)
|
|
|
|
+# ifdef HL_64
|
|
|
|
+ *eip = (void*)shared_context.context.uc_mcontext.gregs[REG_RIP];
|
|
|
|
+ return (void*)shared_context.context.uc_mcontext.gregs[REG_RSP];
|
|
|
|
+# else
|
|
|
|
+ *eip = (void*)shared_context.context.uc_mcontext.gregs[REG_EIP];
|
|
|
|
+ return (void*)shared_context.context.uc_mcontext.gregs[REG_ESP];
|
|
|
|
+# endif
|
|
#else
|
|
#else
|
|
return NULL;
|
|
return NULL;
|
|
#endif
|
|
#endif
|
|
@@ -110,6 +143,14 @@ static bool pause_thread( thread_handle *t, bool b ) {
|
|
ResumeThread(t->h);
|
|
ResumeThread(t->h);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
+#elif defined(HL_LINUX)
|
|
|
|
+ if( b ) {
|
|
|
|
+ tgkill(getpid(), t->tid, SIGPROF);
|
|
|
|
+ return sem_wait(&shared_context.msg2) == 0;
|
|
|
|
+ } else {
|
|
|
|
+ sem_post(&shared_context.msg3);
|
|
|
|
+ return sem_wait(&shared_context.msg4) == 0;
|
|
|
|
+ }
|
|
#else
|
|
#else
|
|
return false;
|
|
return false;
|
|
#endif
|
|
#endif
|
|
@@ -144,6 +185,10 @@ static void read_thread_data( thread_handle *t ) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef HL_LINUX
|
|
|
|
+ int count = hl_module_capture_stack_range(t->inf->stack_top, stack, data.stackOut, MAX_STACK_COUNT);
|
|
|
|
+ pause_thread(t, false);
|
|
|
|
+#else
|
|
int size = (int)((unsigned char*)t->inf->stack_top - (unsigned char*)stack);
|
|
int size = (int)((unsigned char*)t->inf->stack_top - (unsigned char*)stack);
|
|
if( size > MAX_STACK_SIZE-32 ) size = MAX_STACK_SIZE-32;
|
|
if( size > MAX_STACK_SIZE-32 ) size = MAX_STACK_SIZE-32;
|
|
memcpy(data.tmpMemory + 2,stack,size);
|
|
memcpy(data.tmpMemory + 2,stack,size);
|
|
@@ -153,6 +198,7 @@ static void read_thread_data( thread_handle *t ) {
|
|
size += sizeof(void*) * 2;
|
|
size += sizeof(void*) * 2;
|
|
|
|
|
|
int count = hl_module_capture_stack_range((char*)data.tmpMemory+size, (void**)data.tmpMemory, data.stackOut, MAX_STACK_COUNT);
|
|
int count = hl_module_capture_stack_range((char*)data.tmpMemory+size, (void**)data.tmpMemory, data.stackOut, MAX_STACK_COUNT);
|
|
|
|
+#endif
|
|
int eventId = count | 0x80000000;
|
|
int eventId = count | 0x80000000;
|
|
double time = hl_sys_time();
|
|
double time = hl_sys_time();
|
|
record_data(&time,sizeof(double));
|
|
record_data(&time,sizeof(double));
|
|
@@ -211,7 +257,7 @@ static void hl_profile_loop( void *_ ) {
|
|
static void profile_event( int code, vbyte *data, int dataLen );
|
|
static void profile_event( int code, vbyte *data, int dataLen );
|
|
|
|
|
|
void hl_profile_setup( int sample_count ) {
|
|
void hl_profile_setup( int sample_count ) {
|
|
-# if defined(HL_THREADS) && defined(HL_WIN_DESKTOP)
|
|
|
|
|
|
+# if defined(HL_THREADS) && (defined(HL_WIN_DESKTOP) || defined(HL_LINUX))
|
|
hl_setup_profiler(profile_event,hl_profile_end);
|
|
hl_setup_profiler(profile_event,hl_profile_end);
|
|
if( data.sample_count ) return;
|
|
if( data.sample_count ) return;
|
|
if( sample_count < 0 ) {
|
|
if( sample_count < 0 ) {
|
|
@@ -220,6 +266,15 @@ void hl_profile_setup( int sample_count ) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
data.sample_count = sample_count;
|
|
data.sample_count = sample_count;
|
|
|
|
+# ifdef HL_LINUX
|
|
|
|
+ sem_init(&shared_context.msg2, 0, 0);
|
|
|
|
+ sem_init(&shared_context.msg3, 0, 0);
|
|
|
|
+ sem_init(&shared_context.msg4, 0, 0);
|
|
|
|
+ struct sigaction action = {0};
|
|
|
|
+ action.sa_sigaction = sigprof_handler;
|
|
|
|
+ action.sa_flags = SA_SIGINFO;
|
|
|
|
+ sigaction(SIGPROF, &action, NULL);
|
|
|
|
+# endif
|
|
hl_thread_start(hl_profile_loop,NULL,false);
|
|
hl_thread_start(hl_profile_loop,NULL,false);
|
|
# endif
|
|
# endif
|
|
}
|
|
}
|