From 534a366dcffd1be0e82ab89e471e0067e4a4a5cf Mon Sep 17 00:00:00 2001 From: Gabriel Kim <0xgabriel.kim@gmail.com> Date: Sun, 30 Jul 2023 19:59:54 +0900 Subject: [PATCH] record: skip whitespaces after shebang for scripts Python tracing won't work when the shebang line has a space like below: " #! /usr/bin/env python3 " This patch makes uftrace to understand the above shebang as well. Fixed: #1690 Signed-off-by: Gabriel Kim <0xgabriel.kim@gmail.com> --- cmds/record.c | 4 +-- libmcount/dynamic.c | 67 ++++++++++++++++++++------------------------- utils/utils.c | 38 ++++++++++++------------- utils/utils.h | 3 +- 4 files changed, 51 insertions(+), 61 deletions(-) diff --git a/cmds/record.c b/cmds/record.c index ec40ca179..26537df6a 100644 --- a/cmds/record.c +++ b/cmds/record.c @@ -1625,7 +1625,7 @@ static void check_binary(struct uftrace_opts *opts) if (!opts->force && !opts->patch) pr_err_ns(SCRIPT_MSG, opts->exename); - script = str_ltrim(script); + script = str_trim(script); /* ignore options */ p = strchr(script, ' '); @@ -2188,7 +2188,7 @@ int do_child_exec(int ready, struct uftrace_opts *opts, int argc, char *argv[]) if (strstr(shebang, "python")) is_python = true; #endif - s = str_ltrim(shebang); + s = str_trim(shebang); p = strchr(s, ' '); if (p != NULL) diff --git a/libmcount/dynamic.c b/libmcount/dynamic.c index c9c058eb5..6e7b56dd9 100644 --- a/libmcount/dynamic.c +++ b/libmcount/dynamic.c @@ -384,10 +384,17 @@ static bool match_pattern_module(char *pathname) return ret; } -static bool match_pattern_list(struct uftrace_mmap *map, char *soname, char *sym_name) +/** + * match_pattern_list - match a symbol name against a pattern list + * @map - memory map of the symbol + * @soname - name of the module + * @sym_name - name of the symbol + * @return - -1 if match negative, 1 if match positive, 0 if no match + */ +static int match_pattern_list(struct uftrace_mmap *map, char *soname, char *sym_name) { struct patt_list *pl; - bool ret = false; + int ret = 0; char *libname = basename(map->libname); list_for_each_entry(pl, &patterns, list) { @@ -398,7 +405,7 @@ static bool match_pattern_list(struct uftrace_mmap *map, char *soname, char *sym continue; if (match_filter_pattern(&pl->patt, sym_name)) - ret = pl->positive; + ret = pl->positive ? 1 : -1; } return ret; @@ -410,7 +417,6 @@ static void parse_pattern_list(char *patch_funcs, char *def_mod, enum uftrace_pa char *name; int j; struct patt_list *pl; - bool all_negative = true; strv_split(&funcs, patch_funcs, ";"); @@ -421,10 +427,8 @@ static void parse_pattern_list(char *patch_funcs, char *def_mod, enum uftrace_pa if (name[0] == '!') name++; - else { + else pl->positive = true; - all_negative = false; - } delim = strchr(name, '@'); if (delim == NULL) { @@ -439,20 +443,6 @@ static void parse_pattern_list(char *patch_funcs, char *def_mod, enum uftrace_pa list_add_tail(&pl->list, &patterns); } - /* prepend match-all pattern, if all patterns are negative */ - if (all_negative) { - pl = xzalloc(sizeof(*pl)); - pl->positive = true; - pl->module = xstrdup(def_mod); - - if (ptype == PATT_REGEX) - init_filter_pattern(ptype, &pl->patt, "."); - else - init_filter_pattern(PATT_GLOB, &pl->patt, "*"); - - list_add(&pl->list, &patterns); - } - strv_free(&funcs); } @@ -487,12 +477,6 @@ static bool skip_sym(struct uftrace_symbol *sym, struct mcount_dynamic_info *mdi if (sym->type != ST_LOCAL_FUNC && sym->type != ST_GLOBAL_FUNC && sym->type != ST_WEAK_FUNC) return true; - if (!match_pattern_list(map, soname, sym->name)) { - if (mcount_unpatch_func(mdi, sym, &disasm) == 0) - stats.unpatch++; - return true; - } - return false; } @@ -559,6 +543,7 @@ static void patch_normal_func_matched(struct mcount_dynamic_info *mdi, struct uf unsigned i; struct uftrace_symbol *sym; bool found = false; + int match; char *soname = get_soname(map->libname); symtab = &map->mod->symtab; @@ -568,9 +553,15 @@ static void patch_normal_func_matched(struct mcount_dynamic_info *mdi, struct uf if (skip_sym(sym, mdi, map, soname)) continue; - found = true; - mcount_patch_func_with_stats(mdi, sym); + + match = match_pattern_list(map, soname, sym->name); + if (!match) + continue; + else if (match == 1) + mcount_patch_func_with_stats(mdi, sym); + else + mcount_unpatch_func(mdi, sym, NULL); } if (!found) @@ -846,27 +837,27 @@ TEST_CASE(dynamic_pattern_list) pr_dbg("check simple match with default module\n"); parse_pattern_list("abc;!def", "main", PATT_SIMPLE); - TEST_EQ(match_pattern_list(main_map, NULL, "abc"), true); - TEST_EQ(match_pattern_list(main_map, NULL, "def"), false); - TEST_EQ(match_pattern_list(other_map, NULL, "xyz"), false); + TEST_EQ(match_pattern_list(main_map, NULL, "abc"), 1); + TEST_EQ(match_pattern_list(main_map, NULL, "def"), -1); + TEST_EQ(match_pattern_list(other_map, NULL, "xyz"), 0); release_pattern_list(); pr_dbg("check negative regex match with default module\n"); parse_pattern_list("!^a", "main", PATT_REGEX); - TEST_EQ(match_pattern_list(main_map, NULL, "abc"), false); - TEST_EQ(match_pattern_list(main_map, NULL, "def"), true); - TEST_EQ(match_pattern_list(other_map, NULL, "xyz"), false); + TEST_EQ(match_pattern_list(main_map, NULL, "abc"), -1); + TEST_EQ(match_pattern_list(main_map, NULL, "def"), 0); + TEST_EQ(match_pattern_list(other_map, NULL, "xyz"), 0); release_pattern_list(); pr_dbg("check wildcard match with other module\n"); parse_pattern_list("*@other", "main", PATT_GLOB); - TEST_EQ(match_pattern_list(main_map, NULL, "abc"), false); - TEST_EQ(match_pattern_list(main_map, NULL, "def"), false); - TEST_EQ(match_pattern_list(other_map, NULL, "xyz"), true); + TEST_EQ(match_pattern_list(main_map, NULL, "abc"), 0); + TEST_EQ(match_pattern_list(main_map, NULL, "def"), 0); + TEST_EQ(match_pattern_list(other_map, NULL, "xyz"), 1); release_pattern_list(); diff --git a/utils/utils.c b/utils/utils.c index cd49bb8da..953ba06e8 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -595,33 +595,33 @@ char *strjoin(char *left, char *right, const char *delim) } /** - * str_ltrim - to trim left spaces + * str_trim - to trim all spaces * @str: input string * - * This function make @str to left trimmed @str + * This function make @str to right trimmed @str */ -char *str_ltrim(char *str) +char *str_trim(char *str) { + int i = 0; + int j = 0; + bool spaceFound = false; + if (!str) return NULL; - while (isspace((unsigned char)*str)) { - str++; + + while (str[j]) { + if (str[j] != ' ' || !spaceFound) { + str[i] = str[j]; + i++; + spaceFound = (str[j] == ' '); + } + j++; } - return str; -} -/** - * str_rtrim - to trim right spaces - * @str: input string - * - * This function make @str to right trimmed @str - */ -char *str_rtrim(char *str) -{ - char *p = strchr(str, '\0'); - while (--p >= str && isspace(*p)) - ; - *(p + 1) = '\0'; + if (i > 0 && str[i - 1] == ' ') + i--; + + str[i] = '\0'; return str; } diff --git a/utils/utils.h b/utils/utils.h index 393def811..9dc03f8fc 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -389,8 +389,7 @@ void strv_append(struct strv *strv, const char *str); void strv_replace(struct strv *strv, int idx, const char *str); char *strv_join(struct strv *strv, const char *delim); void strv_free(struct strv *strv); -char *str_ltrim(char *str); -char *str_rtrim(char *str); +char *str_trim(char *str); char **parse_cmdline(char *cmd, int *argc); void free_parsed_cmdline(char **argv);