Skip to content

Commit

Permalink
Added user_time to ThreadDetails
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name committed Jan 31, 2024
1 parent a485997 commit 6d00323
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 9 deletions.
2 changes: 2 additions & 0 deletions bindings/gumjs/gumquickcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -5679,6 +5679,7 @@ gum_quick_core_setup_atoms (GumQuickCore * self)
GUM_SETUP_ATOM (toolchain);
GUM_SETUP_ATOM (traps);
GUM_SETUP_ATOM (type);
GUM_SETUP_ATOM (userTime);
GUM_SETUP_ATOM (value);
GUM_SETUP_ATOM (written);

Expand Down Expand Up @@ -5755,6 +5756,7 @@ gum_quick_core_teardown_atoms (GumQuickCore * self)
GUM_TEARDOWN_ATOM (toolchain);
GUM_TEARDOWN_ATOM (traps);
GUM_TEARDOWN_ATOM (type);
GUM_TEARDOWN_ATOM (userTime);
GUM_TEARDOWN_ATOM (value);
GUM_TEARDOWN_ATOM (written);

Expand Down
1 change: 1 addition & 0 deletions bindings/gumjs/gumquickcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ struct _GumQuickCore
GUM_DECLARE_ATOM (toolchain);
GUM_DECLARE_ATOM (traps);
GUM_DECLARE_ATOM (type);
GUM_DECLARE_ATOM (userTime);
GUM_DECLARE_ATOM (value);
GUM_DECLARE_ATOM (written);

Expand Down
4 changes: 4 additions & 0 deletions bindings/gumjs/gumquickprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ gum_emit_thread (const GumThreadDetails * details,
GUM_QUICK_CORE_ATOM (core, state),
_gum_quick_thread_state_new (ctx, details->state),
JS_PROP_C_W_E);
JS_DefinePropertyValue (ctx, thread,
GUM_QUICK_CORE_ATOM (core, userTime),
_gum_quick_uint64_new (ctx, details->user_time, core),
JS_PROP_C_W_E);
JS_DefinePropertyValue (ctx, thread,
GUM_QUICK_CORE_ATOM (core, context),
_gum_quick_cpu_context_new (ctx, (GumCpuContext *) &details->cpu_context,
Expand Down
1 change: 1 addition & 0 deletions bindings/gumjs/gumv8process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ gum_emit_thread (const GumThreadDetails * details,
auto cpu_context =
_gum_v8_cpu_context_new_immutable (&details->cpu_context, core);
_gum_v8_object_set (thread, "context", cpu_context, core);
_gum_v8_object_set (thread, "userTime", Number::New (isolate, details->user_time), core);

auto proceed = mc->OnMatch (thread);

Expand Down
1 change: 1 addition & 0 deletions gum/backend-darwin/gumprocess-darwin.c
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,7 @@ gum_darwin_enumerate_threads (mach_port_t task,
details.state = gum_thread_state_from_darwin (info.run_state);

gum_darwin_parse_unified_thread_state (&state, &details.cpu_context);
details.user_time = 0;

if (!func (&details, user_data))
break;
Expand Down
1 change: 1 addition & 0 deletions gum/backend-freebsd/gumprocess-freebsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ _gum_process_enumerate_threads (GumFoundThreadFunc func,
{
bzero (&details.cpu_context, sizeof (details.cpu_context));
}
details.user_time = 0;

if (!func (&details, user_data))
break;
Expand Down
58 changes: 49 additions & 9 deletions gum/backend-linux/gumprocess-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
#ifdef HAVE_ASM_PTRACE_H
# include <asm/ptrace.h>
#endif
#if defined (HAVE_LINUX)
#include <sys/resource.h>
#endif
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
Expand Down Expand Up @@ -231,8 +234,11 @@ static gint gum_do_modify_thread (gpointer data);
static gboolean gum_await_ack (gint fd, GumModifyThreadAck expected_ack);
static void gum_put_ack (gint fd, GumModifyThreadAck ack);

static void gum_store_cpu_context (GumThreadId thread_id,
GumCpuContext * cpu_context, gpointer user_data);
static void gum_store_context (const GumCpuContext * cpu_context,
gpointer user_data);
static void gum_store_cpu_context (const GumCpuContext * cpu_context,
gpointer user_data);
static void gum_store_user_time (guint64 * user_time);

static void gum_do_enumerate_modules (const gchar * libc_name,
GumFoundModuleFunc func, gpointer user_data);
Expand Down Expand Up @@ -1014,11 +1020,14 @@ _gum_process_enumerate_threads (GumFoundThreadFunc func,
{
GDir * dir;
const gchar * name;
GumStalker * stalker;
gboolean carry_on = TRUE;

dir = g_dir_open ("/proc/self/task", 0, NULL);
g_assert (dir != NULL);

stalker = gum_stalker_new ();

while (carry_on && (name = g_dir_read_name (dir)) != NULL)
{
GumThreadDetails details;
Expand All @@ -1031,27 +1040,58 @@ _gum_process_enumerate_threads (GumFoundThreadFunc func,

if (gum_thread_read_state (details.id, &details.state))
{
if (gum_process_modify_thread (details.id, gum_store_cpu_context,
&details.cpu_context, GUM_MODIFY_THREAD_FLAGS_ABORT_SAFELY))
{
carry_on = func (&details, user_data);
}
details.user_time = 0;
if (gum_stalker_run_on_thread_sync(stalker, details.id,
gum_store_context, &details))
{
carry_on = func(&details, user_data);
}
}

g_free (thread_name);
}

while (gum_stalker_garbage_collect (stalker))
g_usleep (10000);

g_object_unref (stalker);

g_dir_close (dir);
}

static void
gum_store_cpu_context (GumThreadId thread_id,
GumCpuContext * cpu_context,
gum_store_context (const GumCpuContext * cpu_context,
gpointer user_data)
{
GumThreadDetails * details = (GumThreadDetails *) user_data;
gum_store_user_time (&details->user_time);
gum_store_cpu_context (cpu_context, &details->cpu_context);
}

static void
gum_store_cpu_context (const GumCpuContext * cpu_context,
gpointer user_data)
{
memcpy (user_data, cpu_context, sizeof (GumCpuContext));
}

static void
gum_store_user_time (guint64 * user_time)
{
guint64 result = 0;
#if defined (HAVE_LINUX)
struct rusage usage;

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

gboolean
_gum_process_collect_main_module (const GumModuleDetails * details,
gpointer user_data)
Expand Down
1 change: 1 addition & 0 deletions gum/backend-qnx/gumprocess-qnx.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ _gum_process_enumerate_threads (GumFoundThreadFunc func,
gum_process_modify_thread (details.id, gum_store_cpu_context,
&details.cpu_context, GUM_MODIFY_THREAD_FLAGS_ABORT_SAFELY))
{
details.user_time = 0;
carry_on = func (&details, user_data);
}

Expand Down
1 change: 1 addition & 0 deletions gum/backend-windows/gumprocess-windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ _gum_process_enumerate_threads (GumFoundThreadFunc func,

if (gum_windows_get_thread_details (entry.th32ThreadID, &details))
{
details.user_time = 0;
if (!func (&details, user_data))
break;
}
Expand Down
1 change: 1 addition & 0 deletions gum/gumprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct _GumThreadDetails
GumThreadId id;
const gchar * name;
GumThreadState state;
guint64 user_time;
GumCpuContext cpu_context;
};

Expand Down
49 changes: 49 additions & 0 deletions tests/core/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ TESTLIST_BEGIN (process)
TESTENTRY (process_threads)
TESTENTRY (process_threads_exclude_cloaked)
TESTENTRY (process_threads_should_include_name)
TESTENTRY (process_threads_should_include_time)
TESTENTRY (process_modules)
TESTENTRY (process_ranges)
TESTENTRY (process_ranges_exclude_cloaked)
Expand Down Expand Up @@ -286,6 +287,46 @@ check_thread_enumeration_testable (void)
return TRUE;
}

TESTCASE (process_threads_should_include_time)
{
volatile gboolean done = FALSE;
GThread * thread;
GumThreadDetails ctx = {0};
guint64 user_time;

if (!check_thread_enumeration_testable ())
return;

thread = create_sleeping_dummy_thread_sync ("user_time", &done, &ctx.id);

/* Sleep for a short while to let the other thread wake and run */
g_usleep (250000);

gum_process_enumerate_threads (thread_collect_if_matching_id, &ctx);
user_time = ctx.user_time;

#if defined (HAVE_LINUX)
g_assert_cmpuint (user_time, !=, 0);
#else
g_assert_cmpuint (user_time, ==, 0);
#endif

/* Sleep for a short while to let the other thread wake and run */
g_usleep (250000);

gum_process_enumerate_threads (thread_collect_if_matching_id, &ctx);
#if defined (HAVE_LINUX)
g_assert_cmpuint (ctx.user_time, >, user_time);
#else
g_assert_cmpuint (ctx.user_time, ==, 0);
#endif

done = TRUE;
g_thread_join (thread);

g_free ((gpointer) ctx.name);
}

TESTCASE (process_modules)
{
TestForEachContext ctx;
Expand Down Expand Up @@ -1150,6 +1191,13 @@ sleeping_dummy (gpointer data)
pthread_setname_np (pthread_self (), sync_data->name);
#endif

/* Do some work and use some CPU cycles */
static guint no_opt = 0;
for (guint i = 0; i < 1000000; i++)
{
no_opt = no_opt + i;
}

g_mutex_lock (&sync_data->mutex);
sync_data->started = TRUE;
sync_data->thread_id = gum_process_get_current_thread_id ();
Expand Down Expand Up @@ -1197,6 +1245,7 @@ thread_collect_if_matching_id (const GumThreadDetails * details,
ctx->name = g_strdup (details->name);
ctx->state = details->state;
ctx->cpu_context = details->cpu_context;
ctx->user_time = details->user_time;

return FALSE;
}
Expand Down
59 changes: 59 additions & 0 deletions tests/gumjs/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ TESTLIST_BEGIN (script)
TESTENTRY (process_threads_can_be_enumerated)
TESTENTRY (process_threads_can_be_enumerated_legacy_style)
TESTENTRY (process_threads_have_names)
TESTENTRY (process_threads_have_time)
TESTENTRY (process_modules_can_be_enumerated)
TESTENTRY (process_modules_can_be_enumerated_legacy_style)
TESTENTRY (process_module_can_be_looked_up_from_address)
Expand Down Expand Up @@ -5105,6 +5106,64 @@ TESTCASE (process_threads_have_names)
g_async_queue_unref (ctx.controller_messages);
}

TESTCASE (process_threads_have_time)
{
GThread * thread;
GumThreadId thread_id;
volatile gboolean done = FALSE;
guint64 user_time_a, user_time_b;

#ifdef HAVE_LINUX
if (!check_exception_handling_testable ())
return;
#endif

#ifdef HAVE_MIPS
if (!g_test_slow ())
{
g_print ("<skipping, run in slow mode> ");
return;
}
#endif

thread = create_sleeping_dummy_thread_sync (&done, &thread_id);

COMPILE_AND_LOAD_SCRIPT (
"Thread.sleep(0.25);"
GUM_PTR_CONST".writeU64("
" Process.enumerateThreads()"
" .find(t => t.id == " GUM_PTR_CONST ")"
" .userTime);",
&user_time_a,
thread_id
);

EXPECT_NO_MESSAGES ();

COMPILE_AND_LOAD_SCRIPT (
"Thread.sleep(0.25);"
GUM_PTR_CONST".writeU64("
" Process.enumerateThreads()"
" .find(t => t.id == " GUM_PTR_CONST ")"
" .userTime);",
&user_time_b,
thread_id
);

EXPECT_NO_MESSAGES ();

#if defined (HAVE_LINUX)
g_assert_cmpuint (user_time_a, !=, 0);
g_assert_cmpuint (user_time_b, >, user_time_a);
#else
g_assert_cmpuint (user_time_a, ==, 0);
g_assert_cmpuint (user_time_b, ==, 0);
#endif

done = TRUE;
g_thread_join (thread);
}

static gpointer
named_sleeper (gpointer data)
{
Expand Down

0 comments on commit 6d00323

Please sign in to comment.