userspace/kp_parse_events.c - ktap

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /*
  2. * parse_events.c - ktap events parser
  3. *
  4. * This file is part of ktap by Jovi Zhangwei.
  5. *
  6. * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
  7. *
  8. * ktap is free software; you can redistribute it and/or modify it
  9. * under the terms and conditions of the GNU General Public License,
  10. * version 2, as published by the Free Software Foundation.
  11. *
  12. * ktap is distributed in the hope it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  20. */

  21. #include <unistd.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <dirent.h>
  26. #include <fcntl.h>
  27. #include <ctype.h>

  28. #include "../include/ktap_types.h"
  29. #include "../include/ktap_bc.h"
  30. #include "kp_symbol.h"
  31. #include "kp_util.h"

  32. #define TRACING_EVENTS_DIR "/sys/kernel/debug/tracing/events"

  33. static u8 *idmap;
  34. static int idmap_size = 1024; /* set init size */
  35. static int id_nr;

  36. static int idmap_init(void)
  37. {
  38.     idmap = malloc(idmap_size);
  39.     if (!idmap)
  40.         return -1;

  41.     memset(idmap, 0, idmap_size);
  42.     return 0;
  43. }

  44. static void idmap_free(void)
  45. {
  46.     id_nr = 0;
  47.     free(idmap);
  48. }

  49. static inline int idmap_is_set(int id)
  50. {
  51.     return idmap[id / 8] & (1 << (id % 8));
  52. }

  53. static void idmap_set(int id)
  54. {
  55.     if (id >= idmap_size * 8) {
  56.         int newsize = id + 100; /* allocate extra 800 id */
  57.         idmap = realloc(idmap, newsize);
  58.         memset(idmap + idmap_size, 0, newsize - idmap_size);
  59.         idmap_size = newsize;
  60.     }

  61.     if (!idmap_is_set(id))
  62.         id_nr++;

  63.     idmap[id / 8] = idmap[id / 8] | (1 << (id % 8));
  64. }

  65. static void idmap_clear(int id)
  66. {
  67.     if (!idmap_is_set(id))
  68.         return;

  69.     id_nr--;
  70.     idmap[id / 8] = idmap[id / 8] & ~ (1 << (id % 8));
  71. }

  72. static int idmap_get_max_id(void)
  73. {
  74.     return idmap_size * 8;
  75. }

  76. static int *get_id_array()
  77. {
  78.     int *id_array;
  79.     int i, j = 0;

  80.     id_array = malloc(sizeof(int) * id_nr);
  81.     if (!id_array)
  82.         return NULL;

  83.     for (i = 0; i < idmap_get_max_id(); i++) {
  84.         if (idmap_is_set(i))
  85.             id_array[j++] = i;
  86.     }

  87.     return id_array;
  88. }

  89. static int add_event(char *evtid_path)
  90. {
  91.     char id_buf[24];
  92.     int id, fd;

  93.     fd = open(evtid_path, O_RDONLY);
  94.     if (fd < 0) {
  95.         /*
  96.          * some tracepoint doesn't have id file, like ftrace,
  97.          * return success in here, and don't print error.
  98.          */
  99.         verbose_printf("warning: cannot open file %s\n", evtid_path);
  100.         return 0;
  101.     }

  102.     if (read(fd, id_buf, sizeof(id_buf)) < 0) {
  103.         fprintf(stderr, "read file error %s\n", evtid_path);
  104.         close(fd);
  105.         return -1;
  106.     }

  107.     id = atoll(id_buf);

  108.     idmap_set(id);

  109.     close(fd);
  110.     return 0;
  111. }

  112. static int add_tracepoint(const char *sys_name, const char *evt_name)
  113. {
  114.     char evtid_path[PATH_MAX] = {0};

  115.     snprintf(evtid_path, PATH_MAX, "%s/%s/%s/id", TRACING_EVENTS_DIR,
  116.                     sys_name, evt_name);
  117.     return add_event(evtid_path);
  118. }

  119. static int parse_events_add_tracepoint(char *sys, char *event)
  120. {
  121.     process_available_tracepoints(sys, event, add_tracepoint);
  122.     return 0;
  123. }

  124. enum {
  125.     KPROBE_EVENT,
  126.     UPROBE_EVENT,
  127. };

  128. struct probe_list {
  129.     struct probe_list *next;
  130.     int type;
  131.     char event[64];
  132. };

  133. static struct probe_list *probe_list_head; /* for cleanup resources */

  134. /*
  135. * Some symbol format cannot write to uprobe_events in debugfs, like:
  136. * symbol "check_one_fd.part.0" in glibc.
  137. * For those symbols, we change the format to:
  138. * "check_one_fd.part.0" -> "check_one_fd_part_0"
  139. */
  140. static char *format_symbol_name(const char *old_symbol)
  141. {
  142.     char *new_name = strdup(old_symbol);
  143.     char *name = new_name;
  144.     int changed = 0;

  145.         if (!isalpha(*name) && *name != '_') {
  146.         *name = '_';
  147.         changed = 1;
  148.     }

  149.         while (*++name != '\0') {
  150.                 if (!isalpha(*name) && !isdigit(*name) && *name != '_') {
  151.             *name = '_';
  152.             changed = 1;
  153.             continue;
  154.         }
  155.         }

  156.     if (changed)
  157.         fprintf(stderr,
  158.             "Warning: symbol \"%s\" transformed to event \"%s\"\n",
  159.             old_symbol, new_name);

  160.     /* this is a good name */
  161.         return new_name;
  162. }


  163. #define KPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/kprobe_events"

  164. /**
  165. * @return 0 on success, otherwise -1
  166. */
  167. static int
  168. write_kprobe_event(int fd, int ret_probe, const char *symbol,
  169.            unsigned long start, char *fetch_args)
  170. {
  171.     char probe_event[128] = {0};
  172.     char event[64] = {0};
  173.     struct probe_list *pl;
  174.     char event_id_path[128] = {0};
  175.     char *symbol_name;
  176.     int id_fd, ret;

  177.     /* In case some symbols cannot write to uprobe_events debugfs file */
  178.     symbol_name = format_symbol_name(symbol);

  179.     if (!fetch_args)
  180.         fetch_args = " ";

  181.     if (ret_probe) {
  182.         snprintf(event, 64, "ktap_kprobes_%d/ret_%s",
  183.              getpid(), symbol_name);
  184.         /* Return probe point must be a symbol */
  185.         snprintf(probe_event, 128, "r:%s %s %s",
  186.              event, symbol, fetch_args);
  187.     } else {
  188.         snprintf(event, 64, "ktap_kprobes_%d/%s",
  189.              getpid(), symbol_name);
  190.         snprintf(probe_event, 128, "p:%s 0x%lx %s",
  191.              event, start, fetch_args);
  192.     }

  193.     sprintf(event_id_path, "/sys/kernel/debug/tracing/events/%s/id", event);
  194.     /* if event id already exist, then don't write to kprobes_event again */
  195.     id_fd = open(event_id_path, O_RDONLY);
  196.     if (id_fd > 0) {
  197.         close(id_fd);

  198.         /* remember add event id to ids_array */
  199.         ret = add_event(event_id_path);
  200.         if (ret)
  201.             goto error;

  202.         goto out;
  203.     }

  204.     verbose_printf("write kprobe event %s\n", probe_event);

  205.     if (write(fd, probe_event, strlen(probe_event)) <= 0) {
  206.         fprintf(stderr, "Cannot write %s to %s\n", probe_event,
  207.                 KPROBE_EVENTS_PATH);
  208.         goto error;
  209.     }

  210.     /* add to cleanup list */
  211.     pl = malloc(sizeof(struct probe_list));
  212.     if (!pl)
  213.         goto error;

  214.     pl->type = KPROBE_EVENT;
  215.     pl->next = probe_list_head;
  216.     memcpy(pl->event, event, 64);
  217.     probe_list_head = pl;

  218.     ret = add_event(event_id_path);
  219.     if (ret < 0)
  220.         goto error;

  221. out:
  222.     free(symbol_name);
  223.     return 0;

  224. error:
  225.     free(symbol_name);
  226.     return -1;
  227. }

  228. static unsigned long kprobes_text_start;
  229. static unsigned long kprobes_text_end;

  230. static void init_kprobe_prohibited_area(void)
  231. {
  232.     static int once = 0;

  233.     if (once > 0)
  234.         return;

  235.     once = 1;
  236.     kprobes_text_start     = find_kernel_symbol("__kprobes_text_start");
  237.     kprobes_text_end       = find_kernel_symbol("__kprobes_text_end");
  238. }

  239. static int check_kprobe_addr_prohibited(unsigned long addr)
  240. {
  241.     if (addr >= kprobes_text_start && addr <= kprobes_text_end)
  242.         return -1;

  243.     return 0;
  244. }

  245. struct probe_cb_base {
  246.     int fd;
  247.     int ret_probe;
  248.     const char *event;
  249.     char *binary;
  250.     char *symbol;
  251.     char *fetch_args;
  252. };

  253. static int kprobe_symbol_actor(void *arg, const char *name, char type,
  254.                    unsigned long start)
  255. {
  256.     struct probe_cb_base *base = (struct probe_cb_base *)arg;

  257.     /* only can probe text function */
  258.     if (type != 't' && type != 'T')
  259.         return -1;

  260.     if (!strglobmatch(name, base->symbol))
  261.         return -1;

  262.     if (check_kprobe_addr_prohibited(start))
  263.         return -1;

  264.     /* ignore reture code of write debugfs */
  265.     write_kprobe_event(base->fd, base->ret_probe, name, start,
  266.                base->fetch_args);

  267.     return 0; /* success */
  268. }

  269. static int parse_events_add_kprobe(char *event)
  270. {
  271.     char *symbol, *end;
  272.     struct probe_cb_base base;
  273.     int fd, ret;

  274.     fd = open(KPROBE_EVENTS_PATH, O_WRONLY);
  275.     if (fd < 0) {
  276.         fprintf(stderr, "Cannot open %s\n", KPROBE_EVENTS_PATH);
  277.         return -1;
  278.     }

  279.     end = strpbrk(event, "% ");
  280.     if (end)
  281.         symbol = strndup(event, end - event);
  282.     else
  283.         symbol = strdup(event);

  284.     base.fd = fd;
  285.     base.ret_probe = !!strstr(event, "%return");
  286.     base.symbol = symbol;
  287.     base.fetch_args = strchr(event, ' ');

  288.     init_kprobe_prohibited_area();

  289.     ret = kallsyms_parse(&base, kprobe_symbol_actor);
  290.     if (ret <= 0) {
  291.         fprintf(stderr, "cannot parse symbol \"%s\"\n", symbol);
  292.         ret = -1;
  293.     } else {
  294.         ret = 0;
  295.     }

  296.     free(symbol);
  297.     close(fd);

  298.     return ret;
  299. }

  300. #define UPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/uprobe_events"

  301. /**
  302. * @return 0 on success, otherwise -1
  303. */
  304. static int
  305. write_uprobe_event(int fd, int ret_probe, const char *binary,
  306.            const char *symbol, unsigned long addr,
  307.            char *fetch_args)
  308. {
  309.     char probe_event[128] = {0};
  310.     char event[64] = {0};
  311.     struct probe_list *pl;
  312.     char event_id_path[128] = {0};
  313.     char *symbol_name;
  314.     int id_fd, ret;

  315.     /* In case some symbols cannot write to uprobe_events debugfs file */
  316.     symbol_name = format_symbol_name(symbol);

  317.     if (!fetch_args)
  318.         fetch_args = " ";

  319.     if (ret_probe) {
  320.         snprintf(event, 64, "ktap_uprobes_%d/ret_%s",
  321.              getpid(), symbol_name);
  322.         snprintf(probe_event, 128, "r:%s %s:0x%lx %s",
  323.              event, binary, addr, fetch_args);
  324.     } else {
  325.         snprintf(event, 64, "ktap_uprobes_%d/%s",
  326.              getpid(), symbol_name);
  327.         snprintf(probe_event, 128, "p:%s %s:0x%lx %s",
  328.              event, binary, addr, fetch_args);
  329.     }

  330.     sprintf(event_id_path, "/sys/kernel/debug/tracing/events/%s/id", event);
  331.     /* if event id already exist, then don't write to uprobes_event again */
  332.     id_fd = open(event_id_path, O_RDONLY);
  333.     if (id_fd > 0) {
  334.         close(id_fd);

  335.         /* remember add event id to ids_array */
  336.         ret = add_event(event_id_path);
  337.         if (ret)
  338.             goto error;

  339.         goto out;
  340.     }

  341.     verbose_printf("write uprobe event %s\n", probe_event);

  342.     if (write(fd, probe_event, strlen(probe_event)) <= 0) {
  343.         fprintf(stderr, "Cannot write %s to %s\n", probe_event,
  344.                 UPROBE_EVENTS_PATH);
  345.         goto error;
  346.     }

  347.     /* add to cleanup list */
  348.     pl = malloc(sizeof(struct probe_list));
  349.     if (!pl)
  350.         goto error;

  351.     pl->type = UPROBE_EVENT;
  352.     pl->next = probe_list_head;
  353.     memcpy(pl->event, event, 64);
  354.     probe_list_head = pl;

  355.     ret = add_event(event_id_path);
  356.     if (ret < 0)
  357.         goto error;

  358. out:
  359.     free(symbol_name);
  360.     return 0;

  361. error:
  362.     free(symbol_name);
  363.     return -1;
  364. }

  365. /**
  366. * TODO: avoid copy-paste stuff
  367. *
  368. * @return 1 on success, otherwise 0
  369. */
  370. #ifdef NO_LIBELF
  371. static int parse_events_resolve_symbol(int fd, char *event, int type)
  372. {
  373.     char *colon, *binary, *fetch_args;
  374.     unsigned long symbol_address;

  375.     colon = strchr(event, ':');
  376.     if (!colon)
  377.         return -1;

  378.     symbol_address = strtol(colon + 1 /* skip ":" */, NULL, 0);

  379.     fetch_args = strchr(event, ' ');

  380.     /**
  381.      * We already have address, no need in resolving.
  382.      */
  383.     if (symbol_address) {
  384.         int ret;

  385.         binary = strndup(event, colon - event);
  386.         ret = write_uprobe_event(fd, !!strstr(event, "%return"), binary,
  387.                      "NULL", symbol_address, fetch_args);
  388.         free(binary);
  389.         return ret;
  390.     }

  391.     fprintf(stderr, "error: cannot resolve event \"%s\" without libelf, "
  392.             "please recompile ktap with NO_LIBELF disabled\n",
  393.             event);
  394.     exit(EXIT_FAILURE);
  395.     return -1;
  396. }

  397. #else
  398. static int uprobe_symbol_actor(const char *name, vaddr_t addr, void *arg)
  399. {
  400.     struct probe_cb_base *base = (struct probe_cb_base *)arg;
  401.     int ret;

  402.     if (!strglobmatch(name, base->symbol))
  403.         return 0;

  404.     verbose_printf("uprobe: binary: \"%s\" symbol \"%s\" "
  405.             "resolved to 0x%lx\n",
  406.             base->binary, base->symbol, (unsigned long)addr);

  407.     ret = write_uprobe_event(base->fd, base->ret_probe, base->binary,
  408.                  name, addr, base->fetch_args);
  409.     if (ret)
  410.         return ret;

  411.     return 0;
  412. }

  413. static int parse_events_resolve_symbol(int fd, char *event, int type)
  414. {
  415.     char *colon, *end;
  416.     vaddr_t symbol_address;
  417.     int ret;
  418.     struct probe_cb_base base = {
  419.         .fd = fd,
  420.         .event = event
  421.     };

  422.     colon = strchr(event, ':');
  423.     if (!colon)
  424.         return 0;

  425.     base.ret_probe = !!strstr(event, "%return");
  426.     symbol_address = strtol(colon + 1 /* skip ":" */, NULL, 0);
  427.     base.binary = strndup(event, colon - event);

  428.     base.fetch_args = strchr(event, ' ');

  429.     /*
  430.      * We already have address, no need in resolving.
  431.      */
  432.     if (symbol_address) {
  433.         int ret;
  434.         ret = write_uprobe_event(fd, base.ret_probe, base.binary,
  435.                      "NULL", symbol_address,
  436.                      base.fetch_args);
  437.         free(base.binary);
  438.         return ret;
  439.     }

  440.     end = strpbrk(event, "% ");
  441.     if (end)
  442.         base.symbol = strndup(colon + 1, end - 1 - colon);
  443.     else
  444.         base.symbol = strdup(colon + 1);

  445.     ret = parse_dso_symbols(base.binary, type, uprobe_symbol_actor,
  446.                 (void *)&base);
  447.     if (!ret) {
  448.         fprintf(stderr, "error: cannot find symbol %s in binary %s\n",
  449.             base.symbol, base.binary);
  450.         ret = -1;
  451.     } else if(ret > 0) {
  452.         /* no error found when parse symbols */
  453.         ret = 0;
  454.     }

  455.     free(base.binary);
  456.     free(base.symbol);

  457.     return ret;
  458. }
  459. #endif

  460. static int parse_events_add_uprobe(char *old_event, int type)
  461. {
  462.     int ret;
  463.     int fd;

  464.     fd = open(UPROBE_EVENTS_PATH, O_WRONLY);
  465.     if (fd < 0) {
  466.         fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH);
  467.         return -1;
  468.     }

  469.     ret = parse_events_resolve_symbol(fd, old_event, type);

  470.     close(fd);
  471.     return ret;
  472. }

  473. static int parse_events_add_probe(char *old_event)
  474. {
  475.     char *separator;

  476.     separator = strchr(old_event, ':');
  477.     if (!separator || (separator == old_event))
  478.         return parse_events_add_kprobe(old_event);
  479.     else
  480.         return parse_events_add_uprobe(old_event, FIND_SYMBOL);
  481. }

  482. static int parse_events_add_sdt(char *old_event)
  483. {
  484.     return parse_events_add_uprobe(old_event, FIND_STAPSDT_NOTE);
  485. }

  486. static void strim(char *s)
  487. {
  488.     size_t size;
  489.     char *end;

  490.     size = strlen(s);
  491.     if (!size)
  492.         return;

  493.     end = s + size -1;
  494.     while (end >= s && isspace(*end))
  495.         end--;

  496.     *(end + 1) = '\0';
  497. }

  498. static int get_sys_event_filter_str(char *start,
  499.                     char **sys, char **event, char **filter)
  500. {
  501.     char *separator, *separator2, *ptr, *end;

  502.     while (*start == ' ')
  503.         start++;

  504.     /* find sys */
  505.     separator = strchr(start, ':');
  506.     if (!separator || (separator == start)) {
  507.         return -1;
  508.     }

  509.     ptr = malloc(separator - start + 1);
  510.     if (!ptr)
  511.         return -1;

  512.     strncpy(ptr, start, separator - start);
  513.     ptr[separator - start] = '\0';

  514.     strim(ptr);
  515.     *sys = ptr;

  516.     if (!strcmp(*sys, "probe") && (*(separator + 1) == '/')) {
  517.         /* it's uprobe event */
  518.         separator2 = strchr(separator + 1, ':');
  519.         if (!separator2)
  520.             return -1;
  521.     } else
  522.         separator2 = separator;

  523.     /* find filter */
  524.     end = start + strlen(start);
  525.     while (*--end == ' ') {
  526.     }

  527.     if (*end == '/') {
  528.         char *filter_start;

  529.         filter_start = strchr(separator2, '/');
  530.         if (filter_start == end)
  531.             return -1;

  532.         ptr = malloc(end - filter_start);
  533.         if (!ptr)
  534.             return -1;

  535.         memcpy(ptr, filter_start + 1, end - filter_start - 1);
  536.         ptr[end - filter_start - 1] = '\0';

  537.         *filter = ptr;

  538.         end = filter_start;
  539.     } else {
  540.         *filter = NULL;
  541.         end++;
  542.     }

  543.     /* find event */
  544.     ptr = malloc(end - separator);
  545.     if (!ptr)
  546.         return -1;

  547.     memcpy(ptr, separator + 1, end - separator - 1);
  548.     ptr[end - separator - 1] = '\0';

  549.     strim(ptr);
  550.     *event = ptr;

  551.     return 0;
  552. }

  553. static char *get_next_eventdef(char *str)
  554. {
  555.     char *separator;

  556.     separator = strchr(str, ',');
  557.     if (!separator)
  558.         return str + strlen(str);

  559.     *separator = '\0';
  560.     return separator + 1;
  561. }

  562. ktap_eventdesc_t *kp_parse_events(const char *eventdef)
  563. {
  564.     char *str = strdup(eventdef);
  565.     char *sys, *event, *filter, *next;
  566.     ktap_eventdesc_t *evdef_info;
  567.     int ret;

  568.     idmap_init();

  569. parse_next_eventdef:
  570.     next = get_next_eventdef(str);

  571.     if (get_sys_event_filter_str(str, &sys, &event, &filter))
  572.         goto error;

  573.     verbose_printf("parse_eventdef: sys[%s], event[%s], filter[%s]\n",
  574.                sys, event, filter);

  575.     if (!strcmp(sys, "probe"))
  576.         ret = parse_events_add_probe(event);
  577.     else if (!strcmp(sys, "sdt"))
  578.         ret = parse_events_add_sdt(event);
  579.     else
  580.         ret = parse_events_add_tracepoint(sys, event);

  581.     if (ret)
  582.         goto error;

  583.     /* don't trace ftrace:function when all tracepoints enabled */
  584.     if (!strcmp(sys, "*"))
  585.         idmap_clear(1);


  586.     if (filter && *next != '\0') {
  587.         fprintf(stderr, "Error: eventdef only can append one filter\n");
  588.         goto error;
  589.     }

  590.     str = next;
  591.     if (*next != '\0')
  592.         goto parse_next_eventdef;

  593.     evdef_info = malloc(sizeof(*evdef_info));
  594.     if (!evdef_info)
  595.         goto error;

  596.     evdef_info->nr = id_nr;
  597.     evdef_info->id_arr = get_id_array();
  598.     evdef_info->filter = filter;

  599.     idmap_free();
  600.     return evdef_info;
  601. error:
  602.     idmap_free();
  603.     cleanup_event_resources();
  604.     return NULL;
  605. }

  606. void cleanup_event_resources(void)
  607. {
  608.     struct probe_list *pl;
  609.     const char *path;
  610.     char probe_event[128] = {0};
  611.     int fd, ret;

  612.     for (pl = probe_list_head; pl; pl = pl->next) {
  613.         if (pl->type == KPROBE_EVENT)
  614.             path = KPROBE_EVENTS_PATH;
  615.         else if (pl->type == UPROBE_EVENT)
  616.             path = UPROBE_EVENTS_PATH;
  617.         else {
  618.             fprintf(stderr, "Cannot cleanup event type %d\n",
  619.                     pl->type);
  620.             continue;
  621.         }

  622.         snprintf(probe_event, 128, "-:%s", pl->event);

  623.         fd = open(path, O_WRONLY);
  624.         if (fd < 0) {
  625.             fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH);
  626.             continue;
  627.         }

  628.         ret = write(fd, probe_event, strlen(probe_event));
  629.         if (ret <= 0) {
  630.             fprintf(stderr, "Cannot write %s to %s\n", probe_event,
  631.                     path);
  632.             close(fd);
  633.             continue;
  634.         }

  635.         close(fd);
  636.     }
  637. }