diff options
author | Steven Rostedt (Google) <rostedt@goodmis.org> | 2022-01-27 21:29:24 -0500 |
---|---|---|
committer | Steven Rostedt (Google) <rostedt@goodmis.org> | 2022-01-27 22:33:06 -0500 |
commit | 51aedca5c0a97c16d233ba8c627e7fdafaccc499 (patch) | |
tree | 19b101cb1382ea6747eaa25214a38582f1a0741a | |
parent | 907cbf7c474bf7fa9d9bedf1e8110f400250e140 (diff) | |
download | ktrace-51aedca5c0a97c16d233ba8c627e7fdafaccc499.tar.gz |
ktrace: Add completions for create kprobe
Add the completion callback for creating kprobes. Add the kprobe
functions, and offset and types.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
-rw-r--r-- | src/create.c | 216 |
1 files changed, 192 insertions, 24 deletions
diff --git a/src/create.c b/src/create.c index ce0753c..d66cc34 100644 --- a/src/create.c +++ b/src/create.c @@ -200,10 +200,200 @@ int cmd_create(struct ccli *ccli, const char *command, const char *line, return 0; } +static int get_mods(char ***mods) +{ + FILE *fp; + char **list = NULL; + char **tmp; + char *line = NULL; + char *mod; + char *sav; + size_t len = 0; + size_t mlen; + int cnt = 0; + + fp = fopen("/proc/modules", "r"); + if (!fp) + return 0; + + while (getline(&line, &len, fp) > 0) { + mod = strtok_r(line, " ", &sav); + tmp = realloc(list, sizeof(*list) * (cnt + 1)); + if (!tmp) { + for (cnt--; cnt >= 0; cnt--) + free(list[cnt]); + free(list); + free(line); + return 0; + } + tmp[cnt++] = mod; + mlen = strlen(mod); + /* Append the ":" on modules to denote these are modules */ + if (mlen + 2 < len) { + mod[mlen++] = ':'; + mod[mlen] = '\0'; + } + list = tmp; + line = NULL; + len = 0; + } + free(line); + *mods = list; + fclose(fp); + return cnt; +} + +static int load_available_filter(char ***list, char *match) +{ + char **funcs = NULL; + char **mods = NULL; + char *filter = NULL; + char *mod = NULL; + char *p; + int ret; + int cnt = 0; + int mcnt = 0; + int i; + + *list = NULL; + if ((p = strchr(match, ':'))) { + mod = strdup(match); + if (!mod) + return 0; + mod[p - match] = '\0'; + match = p + 1; + } else { + mcnt = get_mods(&mods); + } + ret = asprintf(&filter, "%s*", match); + if (ret < 0) + goto out; + + ret = tracefs_filter_functions(filter, mod, &funcs); + if (ret < 0) + goto out; + + cnt = tracefs_list_size(funcs); + if (cnt < 0) + goto out; + + *list = calloc(cnt + mcnt, sizeof(**list)); + for (i = 0; i < mcnt; i++) { + (*list)[i] = mods[i]; + mods[i] = NULL; + } + + for (i = 0; i < cnt; i++) { + if (mod) { + ret = asprintf(&p, "%s:%s", mod, funcs[i]); + if (ret < 0) + p = NULL; + } else + p = strdup(funcs[i]); + (*list)[i + mcnt] = p; + } + out: + tracefs_list_free(funcs); + free(filter); + for (i = 0; i < mcnt; i++) + free(mods[i]); + free(mods); + free(mod); + /* It's possible to get here without allocating list */ + return *list ? cnt + mcnt : 0; +} + +static int type_completion(char ***list, char *match, int len) +{ + static char *types[] = {"string" , "ustring", "x8", "x16", "x32", "x64", + "u8", "u16", "u32", "u64", "s8", "s16", "s32", "s64" }; + char **words; + int i, x; + + x = ARRAY_SIZE(types); + words = calloc(x, sizeof(char *)); + if (!words) + return 0; + for (i = 0; i < x; i++) { + asprintf(&words[i], "%.*s.%s", + len, match, types[i]); + } + *list = words; + match[strlen(match)] = CCLI_NOSPACE; + return x; +} + +static int offset_completion(char m, char ***list, char *match, int len) +{ + char **words; + + if (!m) { + words = calloc(1, sizeof(char *)); + if (!words) + return 0; + asprintf(&words[0], "%.*s->", + len, match); + *list = words; + match[strlen(match)] = CCLI_NOSPACE; + return 1; + } + return 0; +} static int kprobe_completion(struct ccli *ccli, void *data, int argc, char **argv, char ***list, int word, char *match) { + char *p, *m; + int len; + int ret; + + switch (word) { + case 0: + ccli_printf(ccli, "\n# Name the kprobe\n"); + ccli_line_refresh(ccli); + return 0; + case 1: + if (!strlen(match)) { + ccli_printf(ccli, "\n# [mod:]function-name[+offset] | @memory-address\n"); + ccli_line_refresh(ccli); + return 0; + } + if (match[0] == '@') { + ccli_printf(ccli, "\n# @memory-address\n"); + ccli_line_refresh(ccli); + return 0; + } + if (strchr(match, '+')) { + ccli_printf(ccli, "\n# [mod:]function-name+offset\n"); + ccli_line_refresh(ccli); + return 0; + } + ret = load_available_filter(list, match); + match[strlen(match)] = CCLI_NOSPACE; + return ret; + default: + p = strchr(match, '='); + if (!p) { + ccli_printf(ccli, "\n# var=ARG[.type][->offset[.type]\n"); + ccli_line_refresh(ccli); + return 0; + } + m = p; + while (*p) { + if (*p == '.' || *p == '-') + m = p; + p++; + } + + len = m - match; + + switch (*m) { + case '.': + return type_completion(list, match, len); + case '-': + return offset_completion(m[1], list, match, len); + } + } return 0; } @@ -215,8 +405,6 @@ static int eprobe_completion(struct ccli *ccli, void *data, struct tep_format_field **common_fields; struct tep_format_field **fields; struct tep_event *event; - static char *types[] = {"string" , "ustring", "x8", "x16", "x32", "x64", - "u8", "u16", "u32", "u64", "s8", "s16", "s32", "s64" }; char **systems; char **events; char **words; @@ -331,29 +519,9 @@ static int eprobe_completion(struct ccli *ccli, void *data, match[strlen(match)] = CCLI_NOSPACE; return x; case '.': - x = ARRAY_SIZE(types); - words = calloc(x, sizeof(char *)); - if (!words) - return 0; - for (i = 0; i < x; i++) { - asprintf(&words[i], "%.*s.%s", - len, match, types[i]); - } - *list = words; - match[strlen(match)] = CCLI_NOSPACE; - return x; + return type_completion(list, match, len); case '-': - if (!m[1]) { - words = calloc(1, sizeof(char *)); - if (!words) - return 0; - asprintf(&words[0], "%.*s->", - len, match); - *list = words; - match[strlen(match)] = CCLI_NOSPACE; - return 1; - } - return 0; + return offset_completion(m[1], list, match, len); } } printf("\neprobe word=%d match=%s\n", word, match); |