From 7125ee7386e13231bac4ab5e6e3c90a2e48433b6 Mon Sep 17 00:00:00 2001 From: Hanbum Park Date: Sun, 18 Oct 2020 20:46:39 +0900 Subject: [PATCH 1/6] dynamic: add new struct module_patt_list a new struct 'module_patt_list' has been added to support pattern matching on module names. this structure divides the list of function name patterns by module and stores them in a list format. Signed-off-by: Hanbum Park --- libmcount/dynamic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index 71121d9e6..e80142b28 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -310,6 +310,13 @@ struct patt_list { bool positive; }; +struct module_patt_list { + struct list_head list; + struct list_head func_patt; + struct uftrace_pattern module_patt; + char *module; +}; + static bool match_pattern_list(struct list_head *patterns, struct uftrace_mmap *map, char *sym_name) From 6dbb40dc935f50ff3aaf18b6f6e6c14863aba453 Mon Sep 17 00:00:00 2001 From: Hanbum Park Date: Sun, 18 Oct 2020 20:47:44 +0900 Subject: [PATCH 2/6] dynamic: rename patt_list to func_patt_list for clearity prior to pattern support for module names, patt_list was used simultaneous to match module names and function names. after pattern support for module names patt_list will only be used for function name matching, so we have renamed it to clarify this. Signed-off-by: Hanbum Park --- libmcount/dynamic.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index e80142b28..b2efe3747 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -303,7 +303,7 @@ struct mcount_dynamic_info *setup_trampoline(struct uftrace_mmap *map) return mdi; } -struct patt_list { +struct func_patt_list { struct list_head list; struct uftrace_pattern patt; char *module; @@ -321,7 +321,7 @@ static bool match_pattern_list(struct list_head *patterns, struct uftrace_mmap *map, char *sym_name) { - struct patt_list *pl; + struct func_patt_list *pl; bool ret = false; list_for_each_entry(pl, patterns, list) { @@ -355,7 +355,7 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, "__libc_csu_fini", }; LIST_HEAD(patterns); - struct patt_list *pl; + struct func_patt_list *pl; bool all_negative = true; if (patch_funcs == NULL) @@ -465,9 +465,9 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, } while (!list_empty(&patterns)) { - struct patt_list *pl; + struct func_patt_list *pl; - pl = list_first_entry(&patterns, struct patt_list, list); + pl = list_first_entry(&patterns, struct func_patt_list, list); list_del(&pl->list); free(pl->module); From 72ffe273720e82dcec7323fad39856555a20415b Mon Sep 17 00:00:00 2001 From: Hanbum Park Date: Sun, 18 Oct 2020 20:33:10 +0900 Subject: [PATCH 3/6] dynamic: add functions to support the pattern for module name functions have been added to support the pattern support for module names. Signed-off-by: Hanbum Park --- libmcount/dynamic.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index b2efe3747..4f2edf3d2 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -16,6 +16,7 @@ #include #include #include +#include /* This should be defined before #include "utils.h" */ #define PR_FMT "dynamic" @@ -337,6 +338,38 @@ static bool match_pattern_list(struct list_head *patterns, return ret; } + +static struct module_patt_list *find_ml(struct list_head *patterns, + char *modname) +{ + struct module_patt_list *ml; + + list_for_each_entry(ml, patterns, list) { + if (!strncmp(ml->module, modname, strlen(modname))) + return ml; + + if (match_filter_pattern(&ml->module_patt, modname)) + return ml; + } + + return NULL; +} + +static struct module_patt_list *create_ml(struct list_head *patterns, + enum uftrace_pattern_type ptype, + char *modname) +{ + struct module_patt_list *ml; + + ml = xmalloc(sizeof(*ml)); + INIT_LIST_HEAD(&ml->func_patt); + ml->module = xstrdup(modname); + init_filter_pattern(ptype, &ml->module_patt, modname); + list_add_tail(&ml->list, patterns); + + return ml; +} + static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, enum uftrace_pattern_type ptype, struct mcount_disasm_engine *disasm, From 3a10f0ad37d2f6b244f0e594390e4cbd90bb3fc6 Mon Sep 17 00:00:00 2001 From: Hanbum Park Date: Sun, 18 Oct 2020 20:40:12 +0900 Subject: [PATCH 4/6] dynamic: Add skip libraries as array libraries that affect the operation of Uftrace should be excluded from the dynamic code patch list. added list of affected libraries. Signed-off-by: Hanbum Park --- libmcount/dynamic.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index 4f2edf3d2..cefd8a79e 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -390,6 +390,29 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, LIST_HEAD(patterns); struct func_patt_list *pl; bool all_negative = true; + const char *skip_libs[] = { + /* uftrace internal libraries */ + "libmcount.so", + "libmcount-fast.so", + "libmcount-single.so", + "libmcount-fast-single.so", + /* used by uftrace for dynamic tracing */ + "libcapstone.so.3", + /* system base libraries */ + "libpthread.so.0", + "libpthread-2.*.so", + "ld-*.so", + "libc.so.6", + "libc-2.*.so", + "libm.so.6", + "libm-2.*.so", + "libgcc_s.so.1", + "linux-vdso.so.1", + "linux-gate.so.1", + "ld-linux-*.so.*", + "libdl.so.2", + "libdl-2.*.so", + }; if (patch_funcs == NULL) return 0; From 718183efc2e58811391fccb96e9b0bfb7b058964 Mon Sep 17 00:00:00 2001 From: Hanbum Park Date: Sun, 18 Oct 2020 20:42:17 +0900 Subject: [PATCH 5/6] dynamic: Apply pattern matching on module names when dynamic patching the changed logic is as follows: when creating a list to be dynamically patched, -. creates a list of functions to patch by module by separating the specified dynamic patch targets. when performing dynamic patching for each module, -. if the name of the currently searched module exists in skip_libs, it moves to the next module. -. search the module list and check whether the current target module name is a dynamic patch target. -. searching the symbol of the module registered in the function list of the module list. perform dynamic patching if find matched symbol. Signed-off-by: Hanbum Park --- libmcount/dynamic.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index cefd8a79e..a2014b5a8 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -318,19 +318,14 @@ struct module_patt_list { char *module; }; -static bool match_pattern_list(struct list_head *patterns, - struct uftrace_mmap *map, - char *sym_name) +static bool match_func_list(struct list_head *func_patt, + struct uftrace_mmap *map, + char *sym_name) { struct func_patt_list *pl; bool ret = false; - list_for_each_entry(pl, patterns, list) { - char *libname = basename(map->libname); - - if (strncmp(libname, pl->module, strlen(pl->module))) - continue; - + list_for_each_entry(pl, func_patt, list) { if (match_filter_pattern(&pl->patt, sym_name)) ret = pl->positive; } @@ -389,6 +384,7 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, }; LIST_HEAD(patterns); struct func_patt_list *pl; + struct module_patt_list *ml; bool all_negative = true; const char *skip_libs[] = { /* uftrace internal libraries */ @@ -441,8 +437,12 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, pl->module = xstrdup(++delim); } + ml = find_ml(&patterns, pl->module); + if (ml == NULL) + ml = create_ml(&patterns, ptype, pl->module); + init_filter_pattern(ptype, &pl->patt, name); - list_add_tail(&pl->list, &patterns); + list_add_tail(&pl->list, &ml->func_patt); } /* prepend match-all pattern, if all patterns are negative */ @@ -465,11 +465,20 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, unsigned i, k; struct sym *sym; struct mcount_dynamic_info *mdi; + struct module_patt_list *ml; + + ml = find_ml(&patterns, basename(map->libname)); + if (ml == NULL) + continue; + + for (k = 0; k < ARRAY_SIZE(skip_libs); k++) { + if (!fnmatch(skip_libs[k], basename(map->libname), 0)) + goto NEXT; + } - /* TODO: filter out unsuppported libs */ mdi = setup_trampoline(map); if (mdi == NULL) - continue; + goto NEXT; symtab = &map->mod->symtab; @@ -490,13 +499,14 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, sym->type != ST_GLOBAL_FUNC) continue; - if (!match_pattern_list(&patterns, map, sym->name)) { + if (!match_func_list(&ml->func_patt, map, sym->name)) { if (mcount_unpatch_func(mdi, sym, disasm) == 0) stats.unpatch++; continue; } found = true; + switch (mcount_patch_func(mdi, sym, disasm, min_size)) { case INSTRUMENT_FAILED: stats.failed++; @@ -513,6 +523,12 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, if (!found) stats.nomatch++; + + pr_dbg3("Module %s done\n", map->libname); + continue; + +NEXT: + pr_dbg3("Module %s passed\n", map->libname); } if (stats.failed + stats.skipped + stats.nomatch == 0) { From d36861c1aa8d24b822336acdbdabb278cd2383b2 Mon Sep 17 00:00:00 2001 From: Hanbum Park Date: Sun, 18 Oct 2020 20:34:09 +0900 Subject: [PATCH 6/6] dynamic: Releases resources of module list since the module list is additionally allocated to support pattern matching for the module name, we added logic to release it. Signed-off-by: Hanbum Park --- libmcount/dynamic.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index a2014b5a8..6d830012d 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -537,13 +537,22 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs, } while (!list_empty(&patterns)) { - struct func_patt_list *pl; + struct module_patt_list *ml; + + ml = list_first_entry(&patterns, struct module_patt_list, list); + while (!list_empty(&ml->func_patt)) { + struct func_patt_list *pl; - pl = list_first_entry(&patterns, struct func_patt_list, list); + pl = list_first_entry(&ml->func_patt, struct func_patt_list, list); + + list_del(&pl->list); + free(pl->module); + free(pl); + } - list_del(&pl->list); - free(pl->module); - free(pl); + list_del(&ml->list); + free(ml->module); + free(ml); } strv_free(&funcs);