One Level Up
Top Level
userspace/kp_parse_events.c - ktap
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include "../include/ktap_types.h"
- #include "../include/ktap_bc.h"
- #include "kp_symbol.h"
- #include "kp_util.h"
- #define TRACING_EVENTS_DIR "/sys/kernel/debug/tracing/events"
- static u8 *idmap;
- static int idmap_size = 1024;
- static int id_nr;
- static int idmap_init(void)
- {
- idmap = malloc(idmap_size);
- if (!idmap)
- return -1;
- memset(idmap, 0, idmap_size);
- return 0;
- }
- static void idmap_free(void)
- {
- id_nr = 0;
- free(idmap);
- }
- static inline int idmap_is_set(int id)
- {
- return idmap[id / 8] & (1 << (id % 8));
- }
- static void idmap_set(int id)
- {
- if (id >= idmap_size * 8) {
- int newsize = id + 100;
- idmap = realloc(idmap, newsize);
- memset(idmap + idmap_size, 0, newsize - idmap_size);
- idmap_size = newsize;
- }
- if (!idmap_is_set(id))
- id_nr++;
- idmap[id / 8] = idmap[id / 8] | (1 << (id % 8));
- }
- static void idmap_clear(int id)
- {
- if (!idmap_is_set(id))
- return;
- id_nr--;
- idmap[id / 8] = idmap[id / 8] & ~ (1 << (id % 8));
- }
- static int idmap_get_max_id(void)
- {
- return idmap_size * 8;
- }
- static int *get_id_array()
- {
- int *id_array;
- int i, j = 0;
- id_array = malloc(sizeof(int) * id_nr);
- if (!id_array)
- return NULL;
- for (i = 0; i < idmap_get_max_id(); i++) {
- if (idmap_is_set(i))
- id_array[j++] = i;
- }
- return id_array;
- }
- static int add_event(char *evtid_path)
- {
- char id_buf[24];
- int id, fd;
- fd = open(evtid_path, O_RDONLY);
- if (fd < 0) {
-
- verbose_printf("warning: cannot open file %s\n", evtid_path);
- return 0;
- }
- if (read(fd, id_buf, sizeof(id_buf)) < 0) {
- fprintf(stderr, "read file error %s\n", evtid_path);
- close(fd);
- return -1;
- }
- id = atoll(id_buf);
- idmap_set(id);
- close(fd);
- return 0;
- }
- static int add_tracepoint(const char *sys_name, const char *evt_name)
- {
- char evtid_path[PATH_MAX] = {0};
- snprintf(evtid_path, PATH_MAX, "%s/%s/%s/id", TRACING_EVENTS_DIR,
- sys_name, evt_name);
- return add_event(evtid_path);
- }
- static int parse_events_add_tracepoint(char *sys, char *event)
- {
- process_available_tracepoints(sys, event, add_tracepoint);
- return 0;
- }
- enum {
- KPROBE_EVENT,
- UPROBE_EVENT,
- };
- struct probe_list {
- struct probe_list *next;
- int type;
- char event[64];
- };
- static struct probe_list *probe_list_head;
- static char *format_symbol_name(const char *old_symbol)
- {
- char *new_name = strdup(old_symbol);
- char *name = new_name;
- int changed = 0;
- if (!isalpha(*name) && *name != '_') {
- *name = '_';
- changed = 1;
- }
- while (*++name != '\0') {
- if (!isalpha(*name) && !isdigit(*name) && *name != '_') {
- *name = '_';
- changed = 1;
- continue;
- }
- }
- if (changed)
- fprintf(stderr,
- "Warning: symbol \"%s\" transformed to event \"%s\"\n",
- old_symbol, new_name);
-
- return new_name;
- }
- #define KPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/kprobe_events"
- static int
- write_kprobe_event(int fd, int ret_probe, const char *symbol,
- unsigned long start, char *fetch_args)
- {
- char probe_event[128] = {0};
- char event[64] = {0};
- struct probe_list *pl;
- char event_id_path[128] = {0};
- char *symbol_name;
- int id_fd, ret;
-
- symbol_name = format_symbol_name(symbol);
- if (!fetch_args)
- fetch_args = " ";
- if (ret_probe) {
- snprintf(event, 64, "ktap_kprobes_%d/ret_%s",
- getpid(), symbol_name);
-
- snprintf(probe_event, 128, "r:%s %s %s",
- event, symbol, fetch_args);
- } else {
- snprintf(event, 64, "ktap_kprobes_%d/%s",
- getpid(), symbol_name);
- snprintf(probe_event, 128, "p:%s 0x%lx %s",
- event, start, fetch_args);
- }
- sprintf(event_id_path, "/sys/kernel/debug/tracing/events/%s/id", event);
-
- id_fd = open(event_id_path, O_RDONLY);
- if (id_fd > 0) {
- close(id_fd);
-
- ret = add_event(event_id_path);
- if (ret)
- goto error;
- goto out;
- }
- verbose_printf("write kprobe event %s\n", probe_event);
- if (write(fd, probe_event, strlen(probe_event)) <= 0) {
- fprintf(stderr, "Cannot write %s to %s\n", probe_event,
- KPROBE_EVENTS_PATH);
- goto error;
- }
-
- pl = malloc(sizeof(struct probe_list));
- if (!pl)
- goto error;
- pl->type = KPROBE_EVENT;
- pl->next = probe_list_head;
- memcpy(pl->event, event, 64);
- probe_list_head = pl;
- ret = add_event(event_id_path);
- if (ret < 0)
- goto error;
- out:
- free(symbol_name);
- return 0;
- error:
- free(symbol_name);
- return -1;
- }
- static unsigned long kprobes_text_start;
- static unsigned long kprobes_text_end;
- static void init_kprobe_prohibited_area(void)
- {
- static int once = 0;
- if (once > 0)
- return;
- once = 1;
- kprobes_text_start = find_kernel_symbol("__kprobes_text_start");
- kprobes_text_end = find_kernel_symbol("__kprobes_text_end");
- }
- static int check_kprobe_addr_prohibited(unsigned long addr)
- {
- if (addr >= kprobes_text_start && addr <= kprobes_text_end)
- return -1;
- return 0;
- }
- struct probe_cb_base {
- int fd;
- int ret_probe;
- const char *event;
- char *binary;
- char *symbol;
- char *fetch_args;
- };
- static int kprobe_symbol_actor(void *arg, const char *name, char type,
- unsigned long start)
- {
- struct probe_cb_base *base = (struct probe_cb_base *)arg;
-
- if (type != 't' && type != 'T')
- return -1;
- if (!strglobmatch(name, base->symbol))
- return -1;
- if (check_kprobe_addr_prohibited(start))
- return -1;
-
- write_kprobe_event(base->fd, base->ret_probe, name, start,
- base->fetch_args);
- return 0;
- }
- static int parse_events_add_kprobe(char *event)
- {
- char *symbol, *end;
- struct probe_cb_base base;
- int fd, ret;
- fd = open(KPROBE_EVENTS_PATH, O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "Cannot open %s\n", KPROBE_EVENTS_PATH);
- return -1;
- }
- end = strpbrk(event, "% ");
- if (end)
- symbol = strndup(event, end - event);
- else
- symbol = strdup(event);
- base.fd = fd;
- base.ret_probe = !!strstr(event, "%return");
- base.symbol = symbol;
- base.fetch_args = strchr(event, ' ');
- init_kprobe_prohibited_area();
- ret = kallsyms_parse(&base, kprobe_symbol_actor);
- if (ret <= 0) {
- fprintf(stderr, "cannot parse symbol \"%s\"\n", symbol);
- ret = -1;
- } else {
- ret = 0;
- }
- free(symbol);
- close(fd);
- return ret;
- }
- #define UPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/uprobe_events"
- static int
- write_uprobe_event(int fd, int ret_probe, const char *binary,
- const char *symbol, unsigned long addr,
- char *fetch_args)
- {
- char probe_event[128] = {0};
- char event[64] = {0};
- struct probe_list *pl;
- char event_id_path[128] = {0};
- char *symbol_name;
- int id_fd, ret;
-
- symbol_name = format_symbol_name(symbol);
- if (!fetch_args)
- fetch_args = " ";
- if (ret_probe) {
- snprintf(event, 64, "ktap_uprobes_%d/ret_%s",
- getpid(), symbol_name);
- snprintf(probe_event, 128, "r:%s %s:0x%lx %s",
- event, binary, addr, fetch_args);
- } else {
- snprintf(event, 64, "ktap_uprobes_%d/%s",
- getpid(), symbol_name);
- snprintf(probe_event, 128, "p:%s %s:0x%lx %s",
- event, binary, addr, fetch_args);
- }
- sprintf(event_id_path, "/sys/kernel/debug/tracing/events/%s/id", event);
-
- id_fd = open(event_id_path, O_RDONLY);
- if (id_fd > 0) {
- close(id_fd);
-
- ret = add_event(event_id_path);
- if (ret)
- goto error;
- goto out;
- }
- verbose_printf("write uprobe event %s\n", probe_event);
- if (write(fd, probe_event, strlen(probe_event)) <= 0) {
- fprintf(stderr, "Cannot write %s to %s\n", probe_event,
- UPROBE_EVENTS_PATH);
- goto error;
- }
-
- pl = malloc(sizeof(struct probe_list));
- if (!pl)
- goto error;
- pl->type = UPROBE_EVENT;
- pl->next = probe_list_head;
- memcpy(pl->event, event, 64);
- probe_list_head = pl;
- ret = add_event(event_id_path);
- if (ret < 0)
- goto error;
- out:
- free(symbol_name);
- return 0;
- error:
- free(symbol_name);
- return -1;
- }
- TODO
- #ifdef NO_LIBELF
- static int parse_events_resolve_symbol(int fd, char *event, int type)
- {
- char *colon, *binary, *fetch_args;
- unsigned long symbol_address;
- colon = strchr(event, ':');
- if (!colon)
- return -1;
- symbol_address = strtol(colon + 1 , NULL, 0);
- fetch_args = strchr(event, ' ');
-
- if (symbol_address) {
- int ret;
- binary = strndup(event, colon - event);
- ret = write_uprobe_event(fd, !!strstr(event, "%return"), binary,
- "NULL", symbol_address, fetch_args);
- free(binary);
- return ret;
- }
- fprintf(stderr, "error: cannot resolve event \"%s\" without libelf, "
- "please recompile ktap with NO_LIBELF disabled\n",
- event);
- exit(EXIT_FAILURE);
- return -1;
- }
- #else
- static int uprobe_symbol_actor(const char *name, vaddr_t addr, void *arg)
- {
- struct probe_cb_base *base = (struct probe_cb_base *)arg;
- int ret;
- if (!strglobmatch(name, base->symbol))
- return 0;
- verbose_printf("uprobe: binary: \"%s\" symbol \"%s\" "
- "resolved to 0x%lx\n",
- base->binary, base->symbol, (unsigned long)addr);
- ret = write_uprobe_event(base->fd, base->ret_probe, base->binary,
- name, addr, base->fetch_args);
- if (ret)
- return ret;
- return 0;
- }
- static int parse_events_resolve_symbol(int fd, char *event, int type)
- {
- char *colon, *end;
- vaddr_t symbol_address;
- int ret;
- struct probe_cb_base base = {
- .fd = fd,
- .event = event
- };
- colon = strchr(event, ':');
- if (!colon)
- return 0;
- base.ret_probe = !!strstr(event, "%return");
- symbol_address = strtol(colon + 1 , NULL, 0);
- base.binary = strndup(event, colon - event);
- base.fetch_args = strchr(event, ' ');
-
- if (symbol_address) {
- int ret;
- ret = write_uprobe_event(fd, base.ret_probe, base.binary,
- "NULL", symbol_address,
- base.fetch_args);
- free(base.binary);
- return ret;
- }
- end = strpbrk(event, "% ");
- if (end)
- base.symbol = strndup(colon + 1, end - 1 - colon);
- else
- base.symbol = strdup(colon + 1);
- ret = parse_dso_symbols(base.binary, type, uprobe_symbol_actor,
- (void *)&base);
- if (!ret) {
- fprintf(stderr, "error: cannot find symbol %s in binary %s\n",
- base.symbol, base.binary);
- ret = -1;
- } else if(ret > 0) {
-
- ret = 0;
- }
- free(base.binary);
- free(base.symbol);
- return ret;
- }
- #endif
- static int parse_events_add_uprobe(char *old_event, int type)
- {
- int ret;
- int fd;
- fd = open(UPROBE_EVENTS_PATH, O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH);
- return -1;
- }
- ret = parse_events_resolve_symbol(fd, old_event, type);
- close(fd);
- return ret;
- }
- static int parse_events_add_probe(char *old_event)
- {
- char *separator;
- separator = strchr(old_event, ':');
- if (!separator || (separator == old_event))
- return parse_events_add_kprobe(old_event);
- else
- return parse_events_add_uprobe(old_event, FIND_SYMBOL);
- }
- static int parse_events_add_sdt(char *old_event)
- {
- return parse_events_add_uprobe(old_event, FIND_STAPSDT_NOTE);
- }
- static void strim(char *s)
- {
- size_t size;
- char *end;
- size = strlen(s);
- if (!size)
- return;
- end = s + size -1;
- while (end >= s && isspace(*end))
- end--;
- *(end + 1) = '\0';
- }
- static int get_sys_event_filter_str(char *start,
- char **sys, char **event, char **filter)
- {
- char *separator, *separator2, *ptr, *end;
- while (*start == ' ')
- start++;
-
- separator = strchr(start, ':');
- if (!separator || (separator == start)) {
- return -1;
- }
- ptr = malloc(separator - start + 1);
- if (!ptr)
- return -1;
- strncpy(ptr, start, separator - start);
- ptr[separator - start] = '\0';
- strim(ptr);
- *sys = ptr;
- if (!strcmp(*sys, "probe") && (*(separator + 1) == '/')) {
-
- separator2 = strchr(separator + 1, ':');
- if (!separator2)
- return -1;
- } else
- separator2 = separator;
-
- end = start + strlen(start);
- while (*--end == ' ') {
- }
- if (*end == '/') {
- char *filter_start;
- filter_start = strchr(separator2, '/');
- if (filter_start == end)
- return -1;
- ptr = malloc(end - filter_start);
- if (!ptr)
- return -1;
- memcpy(ptr, filter_start + 1, end - filter_start - 1);
- ptr[end - filter_start - 1] = '\0';
- *filter = ptr;
- end = filter_start;
- } else {
- *filter = NULL;
- end++;
- }
-
- ptr = malloc(end - separator);
- if (!ptr)
- return -1;
- memcpy(ptr, separator + 1, end - separator - 1);
- ptr[end - separator - 1] = '\0';
- strim(ptr);
- *event = ptr;
- return 0;
- }
- static char *get_next_eventdef(char *str)
- {
- char *separator;
- separator = strchr(str, ',');
- if (!separator)
- return str + strlen(str);
- *separator = '\0';
- return separator + 1;
- }
- ktap_eventdesc_t *kp_parse_events(const char *eventdef)
- {
- char *str = strdup(eventdef);
- char *sys, *event, *filter, *next;
- ktap_eventdesc_t *evdef_info;
- int ret;
- idmap_init();
- parse_next_eventdef:
- next = get_next_eventdef(str);
- if (get_sys_event_filter_str(str, &sys, &event, &filter))
- goto error;
- verbose_printf("parse_eventdef: sys[%s], event[%s], filter[%s]\n",
- sys, event, filter);
- if (!strcmp(sys, "probe"))
- ret = parse_events_add_probe(event);
- else if (!strcmp(sys, "sdt"))
- ret = parse_events_add_sdt(event);
- else
- ret = parse_events_add_tracepoint(sys, event);
- if (ret)
- goto error;
-
- if (!strcmp(sys, "*"))
- idmap_clear(1);
- if (filter && *next != '\0') {
- fprintf(stderr, "Error: eventdef only can append one filter\n");
- goto error;
- }
- str = next;
- if (*next != '\0')
- goto parse_next_eventdef;
- evdef_info = malloc(sizeof(*evdef_info));
- if (!evdef_info)
- goto error;
- evdef_info->nr = id_nr;
- evdef_info->id_arr = get_id_array();
- evdef_info->filter = filter;
- idmap_free();
- return evdef_info;
- error:
- idmap_free();
- cleanup_event_resources();
- return NULL;
- }
- void cleanup_event_resources(void)
- {
- struct probe_list *pl;
- const char *path;
- char probe_event[128] = {0};
- int fd, ret;
- for (pl = probe_list_head; pl; pl = pl->next) {
- if (pl->type == KPROBE_EVENT)
- path = KPROBE_EVENTS_PATH;
- else if (pl->type == UPROBE_EVENT)
- path = UPROBE_EVENTS_PATH;
- else {
- fprintf(stderr, "Cannot cleanup event type %d\n",
- pl->type);
- continue;
- }
- snprintf(probe_event, 128, "-:%s", pl->event);
- fd = open(path, O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH);
- continue;
- }
- ret = write(fd, probe_event, strlen(probe_event));
- if (ret <= 0) {
- fprintf(stderr, "Cannot write %s to %s\n", probe_event,
- path);
- close(fd);
- continue;
- }
- close(fd);
- }
- }
One Level Up
Top Level