runtime/lib_kdebug.c - ktap

Global variables defined

Functions defined

Source code

  1. /*
  2. * lib_kdebug.c - kdebug library support for ktap
  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 <linux/module.h>
  22. #include <linux/ctype.h>
  23. #include <linux/slab.h>
  24. #include <linux/version.h>
  25. #include <linux/ftrace_event.h>
  26. #include "../include/ktap_types.h"
  27. #include "ktap.h"
  28. #include "kp_obj.h"
  29. #include "kp_str.h"
  30. #include "kp_transport.h"
  31. #include "kp_vm.h"
  32. #include "kp_events.h"

  33. /**
  34. * function kdebug.trace_by_id
  35. *
  36. * @uaddr: userspace address refer to ktap_eventdesc_t
  37. * @closure
  38. */
  39. static int kplib_kdebug_trace_by_id(ktap_state_t *ks)
  40. {
  41.     unsigned long uaddr = kp_arg_checknumber(ks, 1);
  42.     ktap_func_t *fn = kp_arg_checkfunction(ks, 2);
  43.     struct task_struct *task = G(ks)->trace_task;
  44.     ktap_eventdesc_t eventsdesc;
  45.     char *filter = NULL;
  46.     int *id_arr;
  47.     int ret, i;

  48.     if (G(ks)->mainthread != ks) {
  49.         kp_error(ks,
  50.             "kdebug.trace_by_id only can be called in mainthread\n");
  51.         return -1;
  52.     }

  53.     /* kdebug.trace_by_id cannot be called in trace_end state */
  54.     if (G(ks)->state != KTAP_RUNNING) {
  55.         kp_error(ks,
  56.             "kdebug.trace_by_id only can be called in RUNNING state\n");
  57.         return -1;
  58.     }

  59.     /* copy ktap_eventdesc_t from userspace */
  60.     ret = copy_from_user(&eventsdesc, (void *)uaddr,
  61.                  sizeof(ktap_eventdesc_t));
  62.     if (ret < 0)
  63.         return -1;

  64.     if (eventsdesc.filter) {
  65.         int len;

  66.         len = strlen_user(eventsdesc.filter);
  67.         if (len > 0x1000)
  68.             return -1;

  69.         filter = kmalloc(len + 1, GFP_KERNEL);
  70.         if (!filter)
  71.             return -1;

  72.         /* copy filter string from userspace */
  73.         if (strncpy_from_user(filter, eventsdesc.filter, len) < 0) {
  74.             kfree(filter);
  75.             return -1;
  76.         }
  77.     }

  78.     id_arr = kmalloc(eventsdesc.nr * sizeof(int), GFP_KERNEL);
  79.     if (!id_arr) {
  80.         kfree(filter);
  81.         return -1;
  82.     }

  83.     /* copy all event id from userspace */
  84.     ret = copy_from_user(id_arr, eventsdesc.id_arr,
  85.                  eventsdesc.nr * sizeof(int));
  86.     if (ret < 0) {
  87.         kfree(filter);
  88.         kfree(id_arr);
  89.         return -1;
  90.     }

  91.     fn = clvalue(kp_arg(ks, 2));

  92.     for (i = 0; i < eventsdesc.nr; i++) {
  93.         struct perf_event_attr attr;

  94.         cond_resched();

  95.         if (signal_pending(current)) {
  96.             flush_signals(current);
  97.             kfree(filter);
  98.             kfree(id_arr);
  99.             return -1;
  100.         }

  101.         memset(&attr, 0, sizeof(attr));
  102.         attr.type = PERF_TYPE_TRACEPOINT;
  103.         attr.config = id_arr[i];
  104.         attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
  105.                    PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD;
  106.         attr.sample_period = 1;
  107.         attr.size = sizeof(attr);
  108.         attr.disabled = 0;

  109.         /* register event one by one */
  110.         ret = kp_event_create(ks, &attr, task, filter, fn);
  111.         if (ret < 0)
  112.             break;
  113.     }

  114.     kfree(filter);
  115.     kfree(id_arr);
  116.     return 0;
  117. }

  118. static int kplib_kdebug_trace_end(ktap_state_t *ks)
  119. {
  120.     /* trace_end_closure will be called when ktap main thread exit */
  121.     G(ks)->trace_end_closure = kp_arg_checkfunction(ks, 1);
  122.     return 0;
  123. }

  124. #if 0
  125. static int kplib_kdebug_tracepoint(ktap_state_t *ks)
  126. {
  127.     const char *event_name = kp_arg_checkstring(ks, 1);
  128.     ktap_func_t *fn = kp_arg_checkfunction(ks, 2);

  129.     if (G(ks)->mainthread != ks) {
  130.         kp_error(ks,
  131.             "kdebug.tracepoint only can be called in mainthread\n");
  132.         return -1;
  133.     }

  134.     /* kdebug.tracepoint cannot be called in trace_end state */
  135.     if (G(ks)->state != KTAP_RUNNING) {
  136.         kp_error(ks,
  137.             "kdebug.tracepoint only can be called in RUNNING state\n");
  138.         return -1;
  139.     }

  140.     return kp_event_create_tracepoint(ks, event_name, fn);
  141. }
  142. #endif

  143. static int kplib_kdebug_kprobe(ktap_state_t *ks)
  144. {
  145.     const char *event_name = kp_arg_checkstring(ks, 1);
  146.     ktap_func_t *fn = kp_arg_checkfunction(ks, 2);

  147.     if (G(ks)->mainthread != ks) {
  148.         kp_error(ks,
  149.             "kdebug.kprobe only can be called in mainthread\n");
  150.         return -1;
  151.     }

  152.     /* kdebug.kprobe cannot be called in trace_end state */
  153.     if (G(ks)->state != KTAP_RUNNING) {
  154.         kp_error(ks,
  155.             "kdebug.kprobe only can be called in RUNNING state\n");
  156.         return -1;
  157.     }

  158.     return kp_event_create_kprobe(ks, event_name, fn);
  159. }
  160. static const ktap_libfunc_t kdebug_lib_funcs[] = {
  161.     {"trace_by_id", kplib_kdebug_trace_by_id},
  162.     {"trace_end", kplib_kdebug_trace_end},

  163. #if 0
  164.     {"tracepoint", kplib_kdebug_tracepoint},
  165. #endif
  166.     {"kprobe", kplib_kdebug_kprobe},
  167.     {NULL}
  168. };

  169. int kp_lib_init_kdebug(ktap_state_t *ks)
  170. {
  171.     return kp_vm_register_lib(ks, "kdebug", kdebug_lib_funcs);
  172. }