userspace/kp_util.c - ktap

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /*
  2. * util.c
  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. * Adapted from luajit and lua interpreter.
  9. * Copyright (C) 2005-2014 Mike Pall.
  10. * Copyright (C) 1994-2008 Lua.org, PUC-Rio.
  11. *
  12. * ktap is free software; you can redistribute it and/or modify it
  13. * under the terms and conditions of the GNU General Public License,
  14. * version 2, as published by the Free Software Foundation.
  15. *
  16. * ktap is distributed in the hope it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18. * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  19. * more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along with
  22. * this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  24. */

  25. #include <stdarg.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <math.h>
  30. #include <ctype.h>
  31. #include "../include/ktap_types.h"
  32. #include "../include/ktap_bc.h"
  33. #include "kp_util.h"

  34. /* Error message strings. */
  35. const char *kp_err_allmsg =
  36. #define ERRDEF(name, msg)       msg "\0"
  37. #include "../include/ktap_errmsg.h"
  38. ;

  39. const uint8_t kp_char_bits[257] = {
  40.     0,
  41.     1111111113333311,
  42.     1111111111111111,
  43.     2444444444444444,
  44.   152,152,152,152,152,152,152,152,152,152444444,
  45.     4,176,176,176,176,176,176,160,160,160,160,160,160,160,160,160,
  46.   160,160,160,160,160,160,160,160,160,160,1604444,132,
  47.     4,208,208,208,208,208,208,192,192,192,192,192,192,192,192,192,
  48.   192,192,192,192,192,192,192,192,192,192,19244441,
  49.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  50.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  51.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  52.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  53.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  54.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  55.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
  56.   128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
  57. };

  58. void kp_buf_init(SBuf *sb)
  59. {
  60.     sb->b = (char *)malloc(200);
  61.     sb->p = NULL;
  62.     sb->e = sb->b + 200;
  63. }

  64. void kp_buf_reset(SBuf *sb)
  65. {
  66.     sb->p = sb->b;
  67. }

  68. void kp_buf_free(SBuf *sb)
  69. {
  70.     free(sbufB(sb));
  71. }

  72. char *kp_buf_more(SBuf *sb, int sz)
  73. {
  74.     char *b;
  75.     int old_len = sbuflen(sb);

  76.     if (sz > sbufleft(sb)) {
  77.         b = realloc(sbufB(sb), sbuflen(sb) * 2);
  78.         sb->b = b;
  79.         sb->p = b + old_len;
  80.         sb->e = b + old_len * 2;
  81.     }

  82.     return sbufP(sb);
  83. }

  84. char *kp_buf_need(SBuf *sb, int sz)
  85. {
  86.     char *b;
  87.     int old_len = sbuflen(sb);

  88.     if (sz > sbufsz(sb)) {
  89.         b = realloc(sbufB(sb), sz);
  90.         sb->b = b;
  91.         sb->p = b + old_len;
  92.         sb->e = b + sz;
  93.     }

  94.     return sbufB(sb);
  95. }

  96. char *kp_buf_wmem(char *p, const void *q, int len)
  97. {
  98.     return (char *)memcpy(p, q, len) + len;
  99. }

  100. void kp_buf_putb(SBuf *sb, int c)
  101. {
  102.     char *p = kp_buf_more(sb, 1);
  103.     *p++ = (char)c;
  104.     setsbufP(sb, p);
  105. }

  106. ktap_str_t *kp_buf_str(SBuf *sb)
  107. {
  108.     return kp_str_new(sbufB(sb), sbuflen(sb));
  109. }

  110. /* Write ULEB128 to buffer. */
  111. char *strfmt_wuleb128(char *p, uint32_t v)
  112. {
  113.   for (; v >= 0x80; v >>= 7)
  114.     *p++ = (char)((v & 0x7f) | 0x80);
  115.   *p++ = (char)v;
  116.   return p;
  117. }

  118. void kp_err_lex(ktap_str_t *src, const char *tok, BCLine line,
  119.         ErrMsg em, va_list argp)
  120. {
  121.     const char *msg;

  122.     msg = kp_sprintfv(err2msg(em), argp);
  123.     msg = kp_sprintf("%s:%d: %s", getstr(src), line, msg);
  124.     if (tok)
  125.         msg = kp_sprintf(err2msg(KP_ERR_XNEAR), msg, tok);
  126.     fprintf(stderr, "%s: %s\n", err2msg(KP_ERR_XSYNTAX), msg);
  127.     exit(-1);
  128. }

  129. void *kp_reallocv(void *block, size_t osize, size_t nsize)
  130. {
  131.     return realloc(block, nsize);
  132. }

  133. static const ktap_val_t kp_niltv = { {NULL}, {KTAP_TNIL} } ;
  134. #define niltv  (&kp_niltv)

  135. #define gnode(t,i)    (&(t)->node[i])
  136. #define gkey(n)        (&(n)->key)
  137. #define gval(n)        (&(n)->val)

  138. const ktap_val_t *kp_tab_get(ktap_tab_t *t, const ktap_val_t *key)
  139. {
  140.     int i;

  141.     switch (itype(key)) {
  142.     case KTAP_TNIL:
  143.         return niltv;
  144.     case KTAP_TNUM:
  145.         for (i = 0; i <= t->hmask; i++) {
  146.             ktap_val_t *v = gkey(gnode(t, i));
  147.             if (is_number(v) && nvalue(key) == nvalue(v))
  148.                 return gval(gnode(t, i));
  149.         }
  150.         break;
  151.     case KTAP_TSTR:
  152.         for (i = 0; i <= t->hmask; i++) {
  153.             ktap_val_t *v = gkey(gnode(t, i));
  154.             if (is_string(v) && (rawtsvalue(key) == rawtsvalue(v)))
  155.                 return gval(gnode(t, i));
  156.         }
  157.         break;
  158.     default:
  159.         for (i = 0; i <= t->hmask; i++) {
  160.             if (kp_obj_equal(key, gkey(gnode(t, i))))
  161.                 return gval(gnode(t, i));
  162.         }
  163.         break;
  164.     }

  165.     return niltv;
  166. }

  167. const ktap_val_t *kp_tab_getstr(ktap_tab_t *t, const ktap_str_t *ts)
  168. {
  169.     int i;

  170.     for (i = 0; i <= t->hmask; i++) {
  171.         ktap_val_t *v = gkey(gnode(t, i));
  172.         if (is_string(v) && (ts == rawtsvalue(v)))
  173.             return gval(gnode(t, i));
  174.     }

  175.     return niltv;
  176. }

  177. void kp_tab_setvalue(ktap_tab_t *t, const ktap_val_t *key, ktap_val_t *val)
  178. {
  179.     const ktap_val_t *v = kp_tab_get(t, key);

  180.     if (v != niltv) {
  181.         set_obj((ktap_val_t *)v, val);
  182.     } else {
  183.         if (t->freetop == t->node) {
  184.             int size = (t->hmask + 1) * sizeof(ktap_node_t);
  185.             t->node = realloc(t->node, size * 2);
  186.             memset(t->node + t->hmask + 1, 0, size);
  187.             t->freetop = t->node + (t->hmask + 1) * 2;
  188.             t->hmask = (t->hmask + 1) * 2 - 1;
  189.         }

  190.         ktap_node_t *n = --t->freetop;
  191.         set_obj(gkey(n), key);
  192.         set_obj(gval(n), val);
  193.     }
  194. }

  195. ktap_val_t *kp_tab_set(ktap_tab_t *t, const ktap_val_t *key)
  196. {
  197.     const ktap_val_t *v = kp_tab_get(t, key);

  198.     if (v != niltv) {
  199.         return (ktap_val_t *)v;
  200.     } else {
  201.         if (t->freetop == t->node) {
  202.             int size = (t->hmask + 1) * sizeof(ktap_node_t);
  203.             t->node = realloc(t->node, size * 2);
  204.             memset(t->node + t->hmask + 1, 0, size);
  205.             t->freetop = t->node + (t->hmask + 1) * 2;
  206.             t->hmask = (t->hmask + 1) * 2 - 1;
  207.         }

  208.         ktap_node_t *n = --t->freetop;
  209.         set_obj(gkey(n), key);
  210.         set_nil(gval(n));
  211.         return gval(n);
  212.     }
  213. }


  214. ktap_tab_t *kp_tab_new(void)
  215. {
  216.     int hsize, i;

  217.     ktap_tab_t *t = malloc(sizeof(ktap_tab_t));
  218.     t->gct = ~KTAP_TTAB;
  219.     hsize = 1024;
  220.     t->hmask = hsize - 1;
  221.     t->node = (ktap_node_t *)malloc(hsize * sizeof(ktap_node_t));
  222.     t->freetop = &t->node[hsize];
  223.     t->asize = 0;

  224.     for (i = 0; i <= t->hmask; i++) {
  225.         set_nil(&t->node[i].val);
  226.         set_nil(&t->node[i].key);
  227.     }
  228.     return t;
  229. }

  230. /* simple interned string array, use hash table in future  */
  231. static ktap_str_t **strtab;
  232. static int strtab_size = 1000; /* initial size */
  233. static int strtab_nr;

  234. void kp_str_resize(void)
  235. {
  236.     int size = strtab_size * sizeof(ktap_str_t *);

  237.     strtab = malloc(size);
  238.     if (!strtab) {
  239.         fprintf(stderr, "cannot allocate stringtable\n");
  240.         exit(-1);
  241.     }

  242.     memset(strtab, 0, size);
  243.     strtab_nr = 0;
  244. }

  245. static ktap_str_t *stringtable_search(const char *str, int len)
  246. {
  247.     int i;

  248.     for (i = 0; i < strtab_nr; i++) {
  249.         ktap_str_t *s = strtab[i];
  250.         if ((len == s->len) && !memcmp(str, getstr(s), len))
  251.             return s;
  252.     }

  253.     return NULL;
  254. }

  255. static void stringtable_insert(ktap_str_t *ts)
  256. {
  257.     strtab[strtab_nr++] = ts;

  258.     if (strtab_nr == strtab_size) {
  259.         int size = strtab_size * sizeof(ktap_str_t *);
  260.         strtab = realloc(strtab, size * 2);
  261.         memset(strtab + strtab_size, 0, size);
  262.         strtab_size *= 2;
  263.     }
  264. }

  265. static ktap_str_t *createstrobj(const char *str, size_t l)
  266. {
  267.     ktap_str_t *ts;
  268.     size_t totalsize;  /* total size of TString object */

  269.     totalsize = sizeof(ktap_str_t) + ((l + 1) * sizeof(char));
  270.     ts = (ktap_str_t *)malloc(totalsize);
  271.     ts->gct = ~KTAP_TSTR;
  272.     ts->len = l;
  273.     ts->reserved = 0;
  274.     ts->extra = 0;
  275.     memcpy(ts + 1, str, l * sizeof(char));
  276.     ((char *)(ts + 1))[l] = '\0'/* ending 0 */
  277.     return ts;
  278. }

  279. ktap_str_t *kp_str_new(const char *str, size_t l)
  280. {
  281.     ktap_str_t *ts = stringtable_search(str, l);

  282.     if (ts)
  283.         return ts;

  284.     ts = createstrobj(str, l);
  285.     stringtable_insert(ts);
  286.     return ts;
  287. }

  288. ktap_str_t *kp_str_newz(const char *str)
  289. {
  290.     return kp_str_new(str, strlen(str));
  291. }

  292. /*
  293. * todo: memory leak here
  294. */
  295. char *kp_sprintf(const char *fmt, ...)
  296. {
  297.     char *msg = malloc(128);

  298.     va_list argp;
  299.     va_start(argp, fmt);
  300.     vsprintf(msg, fmt, argp);
  301.     va_end(argp);
  302.     return msg;
  303. }

  304. const char *kp_sprintfv(const char *fmt, va_list argp)
  305. {
  306.     char *msg = malloc(128);

  307.     vsprintf(msg, fmt, argp);
  308.     return msg;
  309. }

  310. int kp_obj_equal(const ktap_val_t *t1, const ktap_val_t *t2)
  311. {
  312.     switch (itype(t1)) {
  313.     case KTAP_TNIL:
  314.         return 1;
  315.     case KTAP_TNUM:
  316.         return nvalue(t1) == nvalue(t2);
  317.     case KTAP_TTRUE:
  318.     case KTAP_TFALSE:
  319.         return itype(t1) == itype(t2);
  320.     case KTAP_TLIGHTUD:
  321.         return pvalue(t1) == pvalue(t2);
  322.     case KTAP_TFUNC:
  323.         return fvalue(t1) == fvalue(t2);
  324.     case KTAP_TSTR:
  325.         return rawtsvalue(t1) == rawtsvalue(t2);
  326.     default:
  327.         return gcvalue(t1) == gcvalue(t2);
  328.     }

  329.     return 0;
  330. }

  331. /*
  332. * strglobmatch is copyed from perf(linux/tools/perf/util/string.c)
  333. */

  334. /* Character class matching */
  335. static bool __match_charclass(const char *pat, char c, const char **npat)
  336. {
  337.     bool complement = false, ret = true;

  338.     if (*pat == '!') {
  339.         complement = true;
  340.         pat++;
  341.     }
  342.     if (*pat++ == c)    /* First character is special */
  343.         goto end;

  344.     while (*pat && *pat != ']') {    /* Matching */
  345.         if (*pat == '-' && *(pat + 1) != ']') {    /* Range */
  346.             if (*(pat - 1) <= c && c <= *(pat + 1))
  347.                 goto end;
  348.             if (*(pat - 1) > *(pat + 1))
  349.                 goto error;
  350.             pat += 2;
  351.         } else if (*pat++ == c)
  352.             goto end;
  353.     }
  354.     if (!*pat)
  355.         goto error;
  356.     ret = false;

  357. end:
  358.     while (*pat && *pat != ']')    /* Searching closing */
  359.         pat++;
  360.     if (!*pat)
  361.         goto error;
  362.     *npat = pat + 1;
  363.     return complement ? !ret : ret;

  364. error:
  365.     return false;
  366. }

  367. /* Glob/lazy pattern matching */
  368. static bool __match_glob(const char *str, const char *pat, bool ignore_space)
  369. {
  370.     while (*str && *pat && *pat != '*') {
  371.         if (ignore_space) {
  372.             /* Ignore spaces for lazy matching */
  373.             if (isspace(*str)) {
  374.                 str++;
  375.                 continue;
  376.             }
  377.             if (isspace(*pat)) {
  378.                 pat++;
  379.                 continue;
  380.             }
  381.         }
  382.         if (*pat == '?') {    /* Matches any single character */
  383.             str++;
  384.             pat++;
  385.             continue;
  386.         } else if (*pat == '[')    /* Character classes/Ranges */
  387.             if (__match_charclass(pat + 1, *str, &pat)) {
  388.                 str++;
  389.                 continue;
  390.             } else
  391.                 return false;
  392.         else if (*pat == '\\') /* Escaped char match as normal char */
  393.             pat++;
  394.         if (*str++ != *pat++)
  395.             return false;
  396.     }
  397.     /* Check wild card */
  398.     if (*pat == '*') {
  399.         while (*pat == '*')
  400.             pat++;
  401.         if (!*pat)    /* Tail wild card matches all */
  402.             return true;
  403.         while (*str)
  404.             if (__match_glob(str++, pat, ignore_space))
  405.                 return true;
  406.     }
  407.     return !*str && !*pat;
  408. }

  409. /**
  410. * strglobmatch - glob expression pattern matching
  411. * @str: the target string to match
  412. * @pat: the pattern string to match
  413. *
  414. * This returns true if the @str matches @pat. @pat can includes wildcards
  415. * ('*','?') and character classes ([CHARS], complementation and ranges are
  416. * also supported). Also, this supports escape character ('\') to use special
  417. * characters as normal character.
  418. *
  419. * Note: if @pat syntax is broken, this always returns false.
  420. */
  421. bool strglobmatch(const char *str, const char *pat)
  422. {
  423.     return __match_glob(str, pat, false);
  424. }

  425. #define handle_error(str) do { perror(str); exit(-1); } while(0)

  426. #define KALLSYMS_PATH "/proc/kallsyms"
  427. /*
  428. * read kernel symbol from /proc/kallsyms
  429. */
  430. int kallsyms_parse(void *arg,
  431.            int(*process_symbol)(void *arg, const char *name,
  432.            char type, unsigned long start))
  433. {
  434.     FILE *file;
  435.     char *line = NULL;
  436.     int ret = 0;
  437.     int found = 0;

  438.     file = fopen(KALLSYMS_PATH, "r");
  439.     if (file == NULL)
  440.         handle_error("open " KALLSYMS_PATH " failed");

  441.     while (!feof(file)) {
  442.         char *symbol_addr, *symbol_name;
  443.         char symbol_type;
  444.         unsigned long start;
  445.         int line_len;
  446.         size_t n;

  447.         line_len = getline(&line, &n, file);
  448.         if (line_len < 0 || !line)
  449.             break;

  450.         line[--line_len] = '\0'; /* \n */

  451.         symbol_addr = strtok(line, " \t");
  452.         start = strtoul(symbol_addr, NULL, 16);

  453.         symbol_type = *strtok(NULL, " \t");
  454.         symbol_name = strtok(NULL, " \t");

  455.         ret = process_symbol(arg, symbol_name, symbol_type, start);
  456.         if (!ret)
  457.             found = 1;
  458.     }

  459.     free(line);
  460.     fclose(file);

  461.     return found;
  462. }

  463. struct ksym_addr_t {
  464.     const char *name;
  465.     unsigned long addr;
  466. };

  467. static int symbol_cmp(void *arg, const char *name, char type,
  468.               unsigned long start)
  469. {
  470.     struct ksym_addr_t *base = arg;

  471.     if (strcmp(base->name, name) == 0) {
  472.         base->addr = start;
  473.         return 1;
  474.     }

  475.     return 0;
  476. }

  477. unsigned long find_kernel_symbol(const char *symbol)
  478. {
  479.     int ret;
  480.     struct ksym_addr_t arg = {
  481.         .name = symbol,
  482.         .addr = 0
  483.     };

  484.     ret = kallsyms_parse(&arg, symbol_cmp);
  485.     if (ret < 0 || arg.addr == 0) {
  486.         fprintf(stderr, "cannot read kernel symbol \"%s\" in %s\n",
  487.             symbol, KALLSYMS_PATH);
  488.         exit(EXIT_FAILURE);
  489.     }

  490.     return arg.addr;
  491. }


  492. #define AVAILABLE_EVENTS_PATH "/sys/kernel/debug/tracing/available_events"

  493. void list_available_events(const char *match)
  494. {
  495.     FILE *file;
  496.     char *line = NULL;

  497.     file = fopen(AVAILABLE_EVENTS_PATH, "r");
  498.     if (file == NULL)
  499.         handle_error("open " AVAILABLE_EVENTS_PATH " failed");

  500.     while (!feof(file)) {
  501.         int line_len;
  502.         size_t n;

  503.         line_len = getline(&line, &n, file);
  504.         if (line_len < 0 || !line)
  505.             break;

  506.         if (!match || strglobmatch(line, match))
  507.             printf("%s", line);
  508.     }

  509.     free(line);
  510.     fclose(file);
  511. }

  512. void process_available_tracepoints(const char *sys, const char *event,
  513.                    int (*process)(const char *sys,
  514.                           const char *event))
  515. {
  516.     char *line = NULL;
  517.     FILE *file;
  518.     char str[128] = {0};

  519.     /* add '\n' into tail */
  520.     snprintf(str, 64, "%s:%s\n", sys, event);

  521.     file = fopen(AVAILABLE_EVENTS_PATH, "r");
  522.     if (file == NULL)
  523.         handle_error("open " AVAILABLE_EVENTS_PATH " failed");

  524.     while (!feof(file)) {
  525.         int line_len;
  526.         size_t n;

  527.         line_len = getline(&line, &n, file);
  528.         if (line_len < 0 || !line)
  529.             break;

  530.         if (strglobmatch(line, str)) {
  531.             char match_sys[64] = {0};
  532.             char match_event[64] = {0};
  533.             char *sep;

  534.             sep = strchr(line, ':');
  535.             memcpy(match_sys, line, sep - line);
  536.             memcpy(match_event, sep + 1,
  537.                         line_len - (sep - line) - 2);

  538.             if (process(match_sys, match_event))
  539.                 break;
  540.         }
  541.     }

  542.     free(line);
  543.     fclose(file);
  544. }