Skip to content

Commit

Permalink
Merge branch 'dlopen-args'
Browse files Browse the repository at this point in the history
Enable auto-args for libraries loaded by dlopen().  Save the debug info
and check them after trying the initially loaded libraries.

Fixed: #842
Signed-off-by: Namhyung Kim <namhyung@gmail.com>
  • Loading branch information
namhyung committed Dec 5, 2024
2 parents 05045a0 + 6ef641d commit 2b9e0bb
Show file tree
Hide file tree
Showing 17 changed files with 427 additions and 57 deletions.
6 changes: 6 additions & 0 deletions cmds/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ static void print_module(struct field_data *fd)
uint64_t timestamp = task->timestamp;
struct uftrace_session *s;
struct uftrace_mmap *map;
struct uftrace_dlopen_list *udl;
const char *modname = "[unknown]";

/* for EVENT or LOST record */
Expand All @@ -115,6 +116,11 @@ static void print_module(struct field_data *fd)
modname = uftrace_basename(map->libname);
else if (is_sched_event(fstack->addr))
modname = "[event]";
else {
udl = session_find_dlopen(s, timestamp, fstack->addr);
if (udl)
modname = uftrace_basename(udl->mod->name);
}
}

pr_out("%*.*s", 16, 16, modname);
Expand Down
2 changes: 1 addition & 1 deletion libmcount/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static volatile bool agent_run = false;
* @old - pointer to the tree to deprecate
* @new - new version of the tree to use
*/
static void swap_triggers(struct uftrace_triggers_info **old, struct uftrace_triggers_info *new)
void swap_triggers(struct uftrace_triggers_info **old, struct uftrace_triggers_info *new)
{
struct uftrace_triggers_info *tmp;
tmp = __sync_val_compare_and_swap(old, *old, new);
Expand Down
16 changes: 1 addition & 15 deletions libmcount/dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,30 +692,16 @@ int mcount_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
}

void mcount_dynamic_dlopen(struct uftrace_sym_info *sinfo, struct dl_phdr_info *info,
char *pathname)
char *pathname, struct uftrace_mmap *map)
{
struct mcount_dynamic_info *mdi;
struct uftrace_mmap *map;

if (!match_pattern_module(pathname))
return;

mdi = create_mdi(info);

map = xmalloc(sizeof(*map) + strlen(pathname) + 1);
map->start = info->dlpi_addr;
map->end = map->start + mdi->text_size;
map->len = strlen(pathname);

strcpy(map->libname, pathname);
mcount_memcpy1(map->prot, "r-xp", 4);
read_build_id(pathname, map->build_id, sizeof(map->build_id));

map->next = sinfo->maps;
sinfo->maps = map;
mdi->map = map;

map->mod = load_module_symtab(sinfo, map->libname, map->build_id);
mcount_arch_find_module(mdi, &map->mod->symtab);

if (mcount_setup_trampoline(mdi) < 0) {
Expand Down
3 changes: 2 additions & 1 deletion libmcount/dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ struct mcount_disasm_engine {

int mcount_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
enum uftrace_pattern_type ptype);
void mcount_dynamic_dlopen(struct uftrace_sym_info *sinfo, struct dl_phdr_info *info, char *path);
void mcount_dynamic_dlopen(struct uftrace_sym_info *sinfo, struct dl_phdr_info *info, char *path,
struct uftrace_mmap *map);
void mcount_dynamic_finish(void);

struct mcount_orig_insn {
Expand Down
8 changes: 8 additions & 0 deletions libmcount/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ static inline void mcount_watch_setup(struct mcount_thread_data *mtdp)
static inline void mcount_watch_release(struct mcount_thread_data *mtdp)
{
}
static inline struct uftrace_triggers_info *
mcount_trigger_init(struct uftrace_filter_setting *filter_setting)
{
return NULL;
}
#endif /* DISABLE_MCOUNT_FILTER */

static inline uint64_t mcount_gettime(void)
Expand Down Expand Up @@ -434,6 +439,7 @@ extern void save_argument(struct mcount_thread_data *mtdp, struct mcount_ret_sta
void save_retval(struct mcount_thread_data *mtdp, struct mcount_ret_stack *rstack, long *retval);
void save_trigger_read(struct mcount_thread_data *mtdp, struct mcount_ret_stack *rstack,
enum trigger_read_type type, bool diff);
struct uftrace_triggers_info *mcount_trigger_init(struct uftrace_filter_setting *filter_setting);
#endif /* DISABLE_MCOUNT_FILTER */

bool check_mem_region(struct mcount_arg_context *ctx, unsigned long addr);
Expand Down Expand Up @@ -472,4 +478,6 @@ bool mcount_is_main_executable(const char *filename, const char *exename);
int agent_spawn(void);
int agent_kill(void);

void swap_triggers(struct uftrace_triggers_info **old, struct uftrace_triggers_info *new);

#endif /* UFTRACE_MCOUNT_INTERNAL_H */
78 changes: 51 additions & 27 deletions libmcount/mcount.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,24 +391,19 @@ static void mcount_signal_finish(void)
}
}

static void mcount_filter_init(struct uftrace_filter_setting *filter_setting, bool force)
struct uftrace_triggers_info *mcount_trigger_init(struct uftrace_filter_setting *filter_setting)
{
struct uftrace_triggers_info *triggers;
char *filter_str = getenv("UFTRACE_FILTER");
char *trigger_str = getenv("UFTRACE_TRIGGER");
char *argument_str = getenv("UFTRACE_ARGUMENT");
char *retval_str = getenv("UFTRACE_RETVAL");
char *autoargs_str = getenv("UFTRACE_AUTO_ARGS");
char *patch_str = getenv("UFTRACE_PATCH");
char *caller_str = getenv("UFTRACE_CALLER");
char *loc_str = getenv("UFTRACE_LOCATION");
bool needs_debug_info = false;

filter_setting->lp64 = host_is_lp64();
filter_setting->arch = host_cpu_arch();

load_module_symtabs(&mcount_sym_info);

mcount_signal_init(getenv("UFTRACE_SIGNAL"), filter_setting);

/* setup auto-args only if argument/return value is used */
if (argument_str || retval_str || autoargs_str ||
(trigger_str && (strstr(trigger_str, "arg") || strstr(trigger_str, "retval")))) {
Expand All @@ -422,27 +417,29 @@ static void mcount_filter_init(struct uftrace_filter_setting *filter_setting, bo
/* use debug info if available */
if (needs_debug_info) {
prepare_debug_info(&mcount_sym_info, filter_setting->ptype, argument_str,
retval_str, !!autoargs_str, force);
retval_str, !!autoargs_str, !!patch_str);
save_debug_info(&mcount_sym_info, mcount_sym_info.dirname);
}

mcount_triggers = xmalloc(sizeof(*mcount_triggers));
memset(mcount_triggers, 0, sizeof(*mcount_triggers));
mcount_triggers->root = RB_ROOT;
uftrace_setup_filter(filter_str, &mcount_sym_info, mcount_triggers, filter_setting);
uftrace_setup_trigger(trigger_str, &mcount_sym_info, mcount_triggers, filter_setting);
uftrace_setup_argument(argument_str, &mcount_sym_info, mcount_triggers, filter_setting);
uftrace_setup_retval(retval_str, &mcount_sym_info, mcount_triggers, filter_setting);
if (!filter_str && !trigger_str && !argument_str && !retval_str && !autoargs_str &&
!caller_str && !loc_str)
return NULL;

if (needs_debug_info) {
uftrace_setup_loc_filter(loc_str, &mcount_sym_info, mcount_triggers,
filter_setting);
}
triggers = xzalloc(sizeof(*triggers));
triggers->root = RB_ROOT;

if (caller_str) {
uftrace_setup_caller_filter(caller_str, &mcount_sym_info, mcount_triggers,
filter_setting);
}
filter_setting->auto_args = false;

uftrace_setup_filter(filter_str, &mcount_sym_info, triggers, filter_setting);
uftrace_setup_trigger(trigger_str, &mcount_sym_info, triggers, filter_setting);
uftrace_setup_argument(argument_str, &mcount_sym_info, triggers, filter_setting);
uftrace_setup_retval(retval_str, &mcount_sym_info, triggers, filter_setting);

if (needs_debug_info)
uftrace_setup_loc_filter(loc_str, &mcount_sym_info, triggers, filter_setting);

if (caller_str)
uftrace_setup_caller_filter(caller_str, &mcount_sym_info, triggers, filter_setting);

if (autoargs_str) {
char *autoarg = ".";
Expand All @@ -453,8 +450,27 @@ static void mcount_filter_init(struct uftrace_filter_setting *filter_setting, bo

filter_setting->auto_args = true;

uftrace_setup_argument(autoarg, &mcount_sym_info, mcount_triggers, filter_setting);
uftrace_setup_retval(autoret, &mcount_sym_info, mcount_triggers, filter_setting);
uftrace_setup_argument(autoarg, &mcount_sym_info, triggers, filter_setting);
uftrace_setup_retval(autoret, &mcount_sym_info, triggers, filter_setting);
}

return triggers;
}

static void mcount_filter_init(struct uftrace_filter_setting *filter_setting, bool force)
{
filter_setting->lp64 = host_is_lp64();
filter_setting->arch = host_cpu_arch();

load_module_symtabs(&mcount_sym_info);

mcount_signal_init(getenv("UFTRACE_SIGNAL"), filter_setting);

mcount_triggers = mcount_trigger_init(filter_setting);
if (mcount_triggers == NULL) {
/* make sure it has the root of triggers */
mcount_triggers = xzalloc(sizeof(*mcount_triggers));
mcount_triggers->root = RB_ROOT;
}

if (getenv("UFTRACE_DEPTH"))
Expand Down Expand Up @@ -1296,8 +1312,16 @@ void mcount_exit_filter_record(struct mcount_thread_data *mtdp, struct mcount_re
if (!mcount_enabled)
return;

if (!(rstack->flags & MCOUNT_FL_RETVAL))
if (rstack->flags & MCOUNT_FL_RETVAL) {
struct uftrace_trigger tr;

/* update args as trigger might be updated due to dlopen() */
uftrace_match_filter(rstack->child_ip, &mcount_triggers->root, &tr);
rstack->pargs = tr.pargs;
}
else {
retval = NULL;
}

if (rstack->flags & MCOUNT_FL_READ) {
struct uftrace_trigger tr;
Expand Down
78 changes: 77 additions & 1 deletion libmcount/wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ extern struct uftrace_sym_info mcount_sym_info;
struct dlopen_base_data {
const char *filename;
struct mcount_thread_data *mtdp;
struct uftrace_triggers_info *triggers;
uint64_t timestamp;
void *handle;
};

static void send_dlopen_msg(struct mcount_thread_data *mtdp, const char *sess_id,
Expand Down Expand Up @@ -71,6 +73,7 @@ static void send_dlopen_msg(struct mcount_thread_data *mtdp, const char *sess_id
static int dlopen_base_callback(struct dl_phdr_info *info, size_t size, void *arg)
{
struct dlopen_base_data *data = arg;
struct uftrace_mmap *map;
char buf[PATH_MAX];
char *p;

Expand All @@ -92,7 +95,37 @@ static int dlopen_base_callback(struct dl_phdr_info *info, size_t size, void *ar
send_dlopen_msg(data->mtdp, mcount_session_name(), data->timestamp, info->dlpi_addr,
info->dlpi_name);

mcount_dynamic_dlopen(&mcount_sym_info, info, p);
map = xzalloc(sizeof(*map) + strlen(p) + 1);
map->len = strlen(p);
strcpy(map->libname, p);
mcount_memcpy1(map->prot, "r-xp", 4);
map->handle = data->handle;

for (int i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type != PT_LOAD)
continue;

if (map->start == 0)
map->start = info->dlpi_phdr[i].p_vaddr + info->dlpi_addr;

if (info->dlpi_phdr[i].p_flags & PF_X) {
map->end = info->dlpi_phdr[i].p_vaddr + info->dlpi_addr;
map->end += info->dlpi_phdr[i].p_memsz;
break;
}
}

read_build_id(p, map->build_id, sizeof(map->build_id));
map->mod = load_module_symtab(&mcount_sym_info, p, map->build_id);

map->next = mcount_sym_info.maps;
write_memory_barrier();
mcount_sym_info.maps = map;

mcount_dynamic_dlopen(&mcount_sym_info, info, p, map);

data->triggers = mcount_trigger_init(&mcount_filter_setting);

return 0;
}

Expand Down Expand Up @@ -256,6 +289,7 @@ static void *(*real_cxa_begin_catch)(void *exc);
static void (*real_cxa_end_catch)(void);
static void (*real_cxa_guard_abort)(void *guard_obj);
static void *(*real_dlopen)(const char *filename, int flags);
static int (*real_dlclose)(void *handle);
static __noreturn void (*real_pthread_exit)(void *retval);
static void (*real_unwind_resume)(void *exc);
static int (*real_posix_spawn)(pid_t *pid, const char *path,
Expand All @@ -281,6 +315,7 @@ void mcount_hook_functions(void)
real_cxa_end_catch = dlsym(RTLD_NEXT, "__cxa_end_catch");
real_cxa_guard_abort = dlsym(RTLD_NEXT, "__cxa_guard_abort");
real_dlopen = dlsym(RTLD_NEXT, "dlopen");
real_dlclose = dlsym(RTLD_NEXT, "dlclose");
real_pthread_exit = dlsym(RTLD_NEXT, "pthread_exit");
real_unwind_resume = dlsym(RTLD_NEXT, "_Unwind_Resume");
real_posix_spawn = dlsym(RTLD_NEXT, "posix_spawn");
Expand Down Expand Up @@ -499,9 +534,50 @@ __visible_default void *dlopen(const char *filename, int flags)
}

data.mtdp = mtdp;
data.handle = ret;
dl_iterate_phdr(dlopen_base_callback, &data);

if (data.triggers)
swap_triggers(&mcount_triggers, data.triggers);

mcount_unguard_recursion(mtdp);
return ret;
}

__visible_default int dlclose(void *handle)
{
struct mcount_thread_data *mtdp;
struct uftrace_mmap *map;
int ret;

if (unlikely(real_dlopen == NULL))
mcount_hook_functions();

ret = real_dlclose(handle);

mtdp = get_thread_data();
if (unlikely(check_thread_data(mtdp))) {
mtdp = mcount_prepare();
if (mtdp == NULL)
return ret;
}
else {
if (!mcount_guard_recursion(mtdp))
return ret;
}

for_each_map(&mcount_sym_info, map) {
if (map->mod == NULL)
continue;

if (map->handle == handle) {
map->mod = NULL;
break;
}
}

mcount_unguard_recursion(mtdp);

return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion misc/symbols.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ static int read_sessions(struct uftrace_session_link *link, char *dirname)
dlop.namelen = strlen(exename);

s = get_session_from_sid(link, dlop.sid);
session_add_dlopen(s, dlop.task.time, dlop.base_addr, exename);
session_add_dlopen(s, dlop.task.time, dlop.base_addr, exename, false);
}
}

Expand Down
Loading

0 comments on commit 2b9e0bb

Please sign in to comment.