summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Google) <rostedt@goodmis.org>2022-01-27 21:29:24 -0500
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-01-27 22:33:06 -0500
commit51aedca5c0a97c16d233ba8c627e7fdafaccc499 (patch)
tree19b101cb1382ea6747eaa25214a38582f1a0741a
parent907cbf7c474bf7fa9d9bedf1e8110f400250e140 (diff)
downloadktrace-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.c216
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);