Skip to content

Commit

Permalink
dynamic: Streamline trampoline life cycle
Browse files Browse the repository at this point in the history
Install a trampoline for each loaded module map, on initialization. Keep
the trampolines in memory to allow for dynamic patching at runtime.
Clear the trampolines on libmcount exit.

Co-authored-by: Gabriel-Andrew Pollo-Guilbert <[email protected]>
Signed-off-by: Clément Guidi <[email protected]>
  • Loading branch information
clementguidi and gpollo committed May 10, 2023
1 parent 38b823b commit faefcfa
Showing 1 changed file with 47 additions and 31 deletions.
78 changes: 47 additions & 31 deletions libmcount/dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,15 @@ static struct mcount_dynamic_info *create_mdi(struct dl_phdr_info *info)
return mdi;
}

/* callback for dl_iterate_phdr() */
static int find_dynamic_module(struct dl_phdr_info *info, size_t sz, void *data)
/**
* prepare_dynamic_module - store dynamic module info and install trampoline;
* callback for dl_iterate_phdr()
* @info - module info
* @sz - data size (unused)
* @data - callback data: symbol info and module parsing flag
* @return - stop iteration on non-zero value
*/
static int prepare_dynamic_module(struct dl_phdr_info *info, size_t sz, void *data)
{
struct mcount_dynamic_info *mdi;
struct find_module_data *fmd = data;
Expand All @@ -315,6 +322,9 @@ static int find_dynamic_module(struct dl_phdr_info *info, size_t sz, void *data)
mdi->map = map;
mcount_arch_find_module(mdi, &map->mod->symtab);

if (mcount_setup_trampoline(mdi) < 0)
mdi->trampoline = 0;

mdi->next = mdinfo;
mdinfo = mdi;
pr_dbg3("load dynamic info for '%s'\n", mdi->map->libname);
Expand Down Expand Up @@ -352,7 +362,7 @@ static void prepare_dynamic_update(struct uftrace_sym_info *sinfo, bool needs_mo
else
return;

dl_iterate_phdr(find_dynamic_module, &fmd);
dl_iterate_phdr(prepare_dynamic_module, &fmd);
}

/**
Expand Down Expand Up @@ -629,10 +639,18 @@ static void patch_func_matched(struct mcount_dynamic_info *mdi, struct uftrace_m
patch_normal_func_matched(mdi, map);
}

/**
* do_dynamic_update - apply (un)patching across loaded modules' maps
* @sinfo - dynamic symbol info
* @patch_funcs - spec of symbols to (un)patch
* @ptype - matching pattern type
* @return - 0 (unused)
*/
static int do_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
enum uftrace_pattern_type ptype)
{
struct uftrace_mmap *map;
struct mcount_dynamic_info *mdi;
char *def_mod;

if (patch_funcs == NULL)
Expand All @@ -641,15 +659,11 @@ static int do_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
def_mod = basename(sinfo->exec_map->libname);
parse_pattern_list(patch_funcs, def_mod, ptype);

for_each_map(sinfo, map) {
struct mcount_dynamic_info *mdi;

/* TODO: filter out unsuppported libs */
mdi = setup_trampoline(map);
if (mdi == NULL)
continue;

patch_func_matched(mdi, map);
/* TODO: filter out unsupported libs */
for (mdi = mdinfo; mdi != NULL; mdi = mdi->next) {
map = mdi->map;
if (mdi->trampoline)
patch_func_matched(mdi, map);
}

release_pattern_list();
Expand All @@ -662,24 +676,6 @@ static int do_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
return 0;
}

static void freeze_dynamic_update(void)
{
struct mcount_dynamic_info *mdi, *tmp;

mdi = mdinfo;
while (mdi) {
tmp = mdi->next;

mcount_arch_dynamic_recover(mdi, &disasm);
mcount_cleanup_trampoline(mdi);
free(mdi);

mdi = tmp;
}

mcount_freeze_code();
}

/* do not use floating-point in libmcount */
static int calc_percent(int n, int total, int *rem)
{
Expand Down Expand Up @@ -724,7 +720,7 @@ int mcount_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
pr_dbg("no match: %8d\n", stats.nomatch);
}

freeze_dynamic_update();
mcount_freeze_code();
return ret;
}

Expand Down Expand Up @@ -770,9 +766,29 @@ void mcount_dynamic_dlopen(struct uftrace_sym_info *sinfo, struct dl_phdr_info *
mcount_freeze_code();
}

/**
* mcount_free_mdinfo - free all dynamic info structures
*/
static void mcount_free_mdinfo(void)
{
struct mcount_dynamic_info *mdi, *tmp;

mdi = mdinfo;
while (mdi) {
tmp = mdi->next;

mcount_arch_dynamic_recover(mdi, &disasm);
mcount_cleanup_trampoline(mdi);
free(mdi);

mdi = tmp;
}
}

void mcount_dynamic_finish(void)
{
release_pattern_list();
mcount_free_mdinfo();
mcount_disasm_finish(&disasm);
}

Expand Down

0 comments on commit faefcfa

Please sign in to comment.