Skip to content

Commit

Permalink
module: Optimize find_symbol_by_name() fallback
Browse files Browse the repository at this point in the history
When the Module implementation lacks an optimized symbol lookup vmethod,
build a sorted index and binary-search it.
  • Loading branch information
oleavr committed Jan 6, 2025
1 parent 37617db commit 1fd528f
Showing 1 changed file with 56 additions and 21 deletions.
77 changes: 56 additions & 21 deletions gum/gummodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,25 @@

#include "gummodule.h"

typedef struct _GumResolveSymbolContext GumResolveSymbolContext;
#include <string.h>

struct _GumResolveSymbolContext
typedef struct _GumSymbolEntry GumSymbolEntry;

struct _GumSymbolEntry
{
const gchar * name;
GumAddress result;
GumAddress address;
};

static gboolean gum_store_address_if_name_matches (
const GumSymbolDetails * details, gpointer user_data);
static gboolean gum_store_symbol (const GumSymbolDetails * details,
gpointer user_data);
static gint gum_symbol_entry_compare (const GumSymbolEntry * lhs,
const GumSymbolEntry * rhs);

G_DEFINE_INTERFACE (GumModule, gum_module, G_TYPE_OBJECT)

G_LOCK_DEFINE_STATIC (gum_module_symbol_cache);

static void
gum_module_default_init (GumModuleInterface * iface)
{
Expand Down Expand Up @@ -109,33 +115,62 @@ gum_module_find_symbol_by_name (GumModule * self,
const gchar * symbol_name)
{
GumModuleInterface * iface;
GumResolveSymbolContext ctx;
GArray * cache;
GumSymbolEntry needle;
guint matched_index;

iface = GUM_MODULE_GET_IFACE (self);

if (iface->find_symbol_by_name != NULL)
return iface->find_symbol_by_name (self, symbol_name);

ctx.name = symbol_name;
ctx.result = 0;
G_LOCK (gum_module_symbol_cache);

gum_module_enumerate_symbols (self, gum_store_address_if_name_matches, &ctx);
cache = g_object_get_data (G_OBJECT (self), "symbol-cache");
if (cache == NULL)
{
cache = g_array_new (FALSE, FALSE, sizeof (GumSymbolEntry));
gum_module_enumerate_symbols (self, gum_store_symbol, cache);
g_array_sort (cache, (GCompareFunc) gum_symbol_entry_compare);
g_object_set_data_full (G_OBJECT (self), "symbol-cache", cache,
(GDestroyNotify) g_array_unref);
}

return ctx.result;
}
G_UNLOCK (gum_module_symbol_cache);

static gboolean
gum_store_address_if_name_matches (const GumSymbolDetails * details,
gpointer user_data)
{
GumResolveSymbolContext * ctx = user_data;
gboolean carry_on = TRUE;
needle.name = symbol_name;
needle.address = 0;

if (strcmp (details->name, ctx->name) == 0)
if (!g_array_binary_search (cache, &needle,
(GCompareFunc) gum_symbol_entry_compare, &matched_index))
{
ctx->result = details->address;
carry_on = FALSE;
return 0;
}

return carry_on;
return g_array_index (cache, GumSymbolEntry, matched_index).address;
}

static gboolean
gum_store_symbol (const GumSymbolDetails * details,
gpointer user_data)
{
GArray * cache = user_data;
GumSymbolEntry entry;

/*
* Implementations guarantee that the lifetime of this string is at least that
* of the module.
*/
entry.name = details->name;
entry.address = details->address;
g_array_append_val (cache, entry);

return TRUE;
}

static gint
gum_symbol_entry_compare (const GumSymbolEntry * lhs,
const GumSymbolEntry * rhs)
{
return strcmp (lhs->name, rhs->name);
}

0 comments on commit 1fd528f

Please sign in to comment.