Skip to content

Commit

Permalink
Add support for query thread user-time
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name committed Mar 20, 2024
1 parent 8ef8e4a commit 588273e
Show file tree
Hide file tree
Showing 11 changed files with 533 additions and 0 deletions.
10 changes: 10 additions & 0 deletions bindings/gumjs/gumquickthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ enum _GumBacktracerType

GUMJS_DECLARE_FUNCTION (gumjs_thread_backtrace)
GUMJS_DECLARE_FUNCTION (gumjs_thread_sleep)
GUMJS_DECLARE_FUNCTION (gumjs_thread_get_user_time)

static const JSCFunctionListEntry gumjs_thread_entries[] =
{
JS_CFUNC_DEF ("_backtrace", 0, gumjs_thread_backtrace),
JS_CFUNC_DEF ("sleep", 0, gumjs_thread_sleep),
JS_CFUNC_DEF ("getUserTime", 0, gumjs_thread_get_user_time),
};

static const JSCFunctionListEntry gumjs_backtracer_entries[] =
Expand Down Expand Up @@ -159,3 +161,11 @@ GUMJS_DEFINE_FUNCTION (gumjs_thread_sleep)

return JS_UNDEFINED;
}

GUMJS_DEFINE_FUNCTION (gumjs_thread_get_user_time)
{
guint64 user_time = gum_thead_get_user_time ();

return JS_NewFloat64 (ctx, ((double) user_time) / G_USEC_PER_SEC);
}

10 changes: 10 additions & 0 deletions bindings/gumjs/gumv8thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ using namespace v8;

GUMJS_DECLARE_FUNCTION (gumjs_thread_backtrace)
GUMJS_DECLARE_FUNCTION (gumjs_thread_sleep)
GUMJS_DECLARE_FUNCTION (gumjs_thread_get_user_time)

static const GumV8Function gumjs_thread_functions[] =
{
{ "_backtrace", gumjs_thread_backtrace },
{ "sleep", gumjs_thread_sleep },
{ "getUserTime", gumjs_thread_get_user_time},

{ NULL, NULL }
};
Expand Down Expand Up @@ -171,3 +173,11 @@ GUMJS_DEFINE_FUNCTION (gumjs_thread_sleep)
g_usleep (delay * G_USEC_PER_SEC);
}
}

GUMJS_DEFINE_FUNCTION (gumjs_thread_get_user_time)
{
guint64 user_time = gum_thead_get_user_time ();

info.GetReturnValue ().Set ((double) user_time / G_USEC_PER_SEC);
}

18 changes: 18 additions & 0 deletions gum/backend-darwin/gumprocess-darwin.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,24 @@ gum_thread_resume (GumThreadId thread_id,
#endif
}

guint64
gum_thead_get_user_time (void)
{
mach_port_t port;
thread_basic_info_data_t info;
mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;
G_GNUC_UNUSED kern_return_t kr;

port = mach_thread_self ();
kr = thread_info (port, THREAD_BASIC_INFO,
(thread_info_t) &info, &info_count);
g_assert (kr == KERN_SUCCESS);
mach_port_deallocate (mach_task_self (), port);

return ((guint64) info.user_time.seconds * G_USEC_PER_SEC) +
info.user_time.microseconds;
}

gboolean
gum_module_load (const gchar * module_name,
GError ** error)
Expand Down
16 changes: 16 additions & 0 deletions gum/backend-freebsd/gumprocess-freebsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <ucontext.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/thr.h>
#include <sys/types.h>
Expand Down Expand Up @@ -716,6 +717,21 @@ gum_thread_resume (GumThreadId thread_id,
}
}

guint64
gum_thead_get_user_time (void)
{
guint64 user_time = 0;
struct rusage usage;

if (getrusage (RUSAGE_THREAD, &usage) == 0)
{
user_time = (usage.ru_utime.tv_sec * G_USEC_PER_SEC)
+ usage.ru_utime.tv_usec;
}

return user_time;
}

gboolean
gum_module_load (const gchar * module_name,
GError ** error)
Expand Down
25 changes: 25 additions & 0 deletions gum/backend-linux/gumprocess-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#ifdef HAVE_SYS_USER_H
# include <sys/user.h>
#endif
#include <sys/time.h>
#include <sys/resource.h>

#define GUM_PAGE_START(value, page_size) \
(GUM_ADDRESS (value) & ~GUM_ADDRESS (page_size - 1))
Expand Down Expand Up @@ -87,6 +89,9 @@
#ifndef NT_PRSTATUS
# define NT_PRSTATUS 1
#endif
#ifndef RUSAGE_THREAD
# define RUSAGE_THREAD 1
#endif

#define GUM_TEMP_FAILURE_RETRY(expression) \
({ \
Expand Down Expand Up @@ -1548,6 +1553,26 @@ gum_thread_resume (GumThreadId thread_id,
}
}

/**
* gum_thead_get_user_time:
*
* Returns: the time the thread has spend executing in user-mode in micro-seconds
*/
guint64
gum_thead_get_user_time (void)
{
guint64 user_time = 0;
struct rusage usage;

if (getrusage (RUSAGE_THREAD, &usage) == 0)
{
user_time = (usage.ru_utime.tv_sec * G_USEC_PER_SEC)
+ usage.ru_utime.tv_usec;
}

return user_time;
}

gboolean
gum_module_load (const gchar * module_name,
GError ** error)
Expand Down
6 changes: 6 additions & 0 deletions gum/backend-qnx/gumprocess-qnx.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,12 @@ gum_thread_resume (GumThreadId thread_id,
}
}

guint64
gum_thead_get_user_time (void)
{
return 0;
}

gboolean
gum_module_load (const gchar * module_name,
GError ** error)
Expand Down
43 changes: 43 additions & 0 deletions gum/backend-windows/gumprocess-windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ typedef void (WINAPI * GumGetCurrentThreadStackLimitsFunc) (
PULONG_PTR low_limit, PULONG_PTR high_limit);
typedef struct _GumEnumerateSymbolsContext GumEnumerateSymbolsContext;
typedef struct _GumFindExportContext GumFindExportContext;
typedef BOOL (WINAPI * GetThreadTimesFunc) (HANDLE ThreadHandle,
LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime,
LPFILETIME lpUserTime);

struct _GumEnumerateSymbolsContext
{
Expand Down Expand Up @@ -637,6 +640,46 @@ gum_thread_resume (GumThreadId thread_id,
}
}

guint64
gum_thead_get_user_time (void)
{
static gboolean initialized = FALSE;
static GetThreadTimesFunc get_thread_times = NULL;

HMODULE mod;
FILETIME creationTime;
FILETIME exitTime;
FILETIME kernelTime;
FILETIME userTime;
guint64 result;

if (!initialized)
{
initialized = TRUE;

mod = GetModuleHandle (_T ("kernel32.dll"));
if (mod == NULL)
return 0;

get_thread_times =(GetThreadTimesFunc) GetProcAddress (mod,
"GetThreadTimes");
}

if (get_thread_times == NULL)
return 0;

if (!get_thread_times (GetCurrentThread (), &creationTime, &exitTime,
&kernelTime, &userTime))
{
return 0;
}

result = (((guint64) userTime.dwHighDateTime) << 32) + userTime.dwLowDateTime;

/* Timings on Windows are to 100-nanosecond granularity. Convert to u-secs */
return result / 10;
}

gboolean
gum_module_load (const gchar * module_name,
GError ** error)
Expand Down
1 change: 1 addition & 0 deletions gum/gumprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "gum-init.h"
#include "gumcloak.h"
#include "gumstalker.h"

typedef struct _GumEmitThreadsContext GumEmitThreadsContext;
typedef struct _GumResolveModulePointerContext GumResolveModulePointerContext;
Expand Down
1 change: 1 addition & 0 deletions gum/gumprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ GUM_API gint gum_thread_get_system_error (void);
GUM_API void gum_thread_set_system_error (gint value);
GUM_API gboolean gum_thread_suspend (GumThreadId thread_id, GError ** error);
GUM_API gboolean gum_thread_resume (GumThreadId thread_id, GError ** error);
GUM_API guint64 gum_thead_get_user_time (void);
GUM_API gboolean gum_module_load (const gchar * module_name, GError ** error);
GUM_API gboolean gum_module_ensure_initialized (const gchar * module_name);
GUM_API void gum_module_enumerate_imports (const gchar * module_name,
Expand Down
Loading

0 comments on commit 588273e

Please sign in to comment.