lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 17 Dec 2013 12:29:30 -0600
From:	Tom Zanussi <tom.zanussi@...ux.intel.com>
To:	Jean-Jacques Hiblot <jjhiblot@...phandler.com>
Cc:	Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>,
	rostedt@...dmis.org, linux-gpio@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH] Tracing events with GPIOs

Hi Jean-Jacques,

On Tue, 2013-12-17 at 18:22 +0100, Jean-Jacques Hiblot wrote:
> 2013/12/17 Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>:
> > (2013/12/17 9:22), Jean-Jacques Hiblot wrote:
> >> This patch implements a new tracing mechanism based on kprobes and using GPIO.
> >> Debugging with GPIO is very common in the embedded world. At least for those of us
> >> fortunate enough to have an oscilloscope or a logic analyzer on their bench...
> >> This is especially true if the issue results of a hardware/sofware interaction.
> >>
> >> Typical use cases are :
> >> * mixed software/hardware debugging. For example when the software detects a
> >>   situation of interest (typically an error) it toggles a GPIO to trigger the
> >>   oscilloscope acquisition.
> >> * direct latency/duration measurements.
> >
> > Ah, it's interesting to me :)
> >
> > And I think this feature should be built on the event triggers which
> > Tom is working on, instead of kprobes directly, because it allows
> > you to take gpio actions on normal tracepoints, and uprobes too :)
> >
> 
> I'll make a version that uses this framework then. When it's ready
> I'll make some measurements to check the overhead of both solutions.
> 

Yeah, this does look like an interesting application for event triggers
- looking forward to seeing what you come up with...

> Tom,
> is git://git.yoctoproject.org/linux-yocto-contrib
> tzanussi/event-triggers-v11 the right starting point ?
> 

Yep, that's the last iteration - I haven't changed anything since then.

Tom

> Thanks,
> 
> Jean-Jacques
> 
> > Thank you!
> >
> >>
> >> examples:
> >> To trig the oscilloscope whenever a mmc command error:
> >>   echo "p:my_mmc_blk_error mmc_blk_cmd_error gpiopulse@13" > /sys/kernel/debug/tracing/kprobe_events
> >>   echo 1 > /sys/kernel/debug/tracing/events/kprobes/my_mmc_blk_error/enable
> >>
> >> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@...phandler.com>
> >> ---
> >>  kernel/trace/Kconfig        |  12 ++++
> >>  kernel/trace/trace_kprobe.c | 167 +++++++++++++++++++++++++++++++++++++++++++-
> >>  2 files changed, 177 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> >> index 015f85a..4228768 100644
> >> --- a/kernel/trace/Kconfig
> >> +++ b/kernel/trace/Kconfig
> >> @@ -420,6 +420,18 @@ config KPROBE_EVENT
> >>         This option is also required by perf-probe subcommand of perf tools.
> >>         If you want to use perf tools, this option is strongly recommended.
> >>
> >> +config KPROBE_EVENT_GPIO
> >> +     depends on KPROBE_EVENT
> >> +     depends on GPIOLIB
> >> +     bool "Enable kprobes-based tracing of events via GPIO"
> >> +     default n
> >> +     help
> >> +             This allows the user to use GPIOs as a tracing tool.The primary
> >> +             purpose of this option is to allow the user to trigger an
> >> +             oscilloscope on software events.
> >> +             The GPIO can be set, cleared, toggled, or pulsed when the event
> >> +             is hit.
> >> +
> >>  config UPROBE_EVENT
> >>       bool "Enable uprobes-based dynamic events"
> >>       depends on ARCH_SUPPORTS_UPROBES
> >> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> >> index dae9541..5d297f5 100644
> >> --- a/kernel/trace/trace_kprobe.c
> >> +++ b/kernel/trace/trace_kprobe.c
> >> @@ -19,6 +19,7 @@
> >>
> >>  #include <linux/module.h>
> >>  #include <linux/uaccess.h>
> >> +#include <linux/gpio.h>
> >>
> >>  #include "trace_probe.h"
> >>
> >> @@ -27,6 +28,33 @@
> >>  /**
> >>   * Kprobe event core functions
> >>   */
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +#define TP_GPIO_UNDEFINED      0
> >> +#define TP_GPIO_CMD_SET                1
> >> +#define TP_GPIO_CMD_CLEAR      2
> >> +#define TP_GPIO_CMD_TOGGLE     3
> >> +#define TP_GPIO_CMD_PULSE      4
> >> +#define TP_GPIO_CMD_PULSE_HIGH 5
> >> +#define TP_GPIO_CMD_PULSE_LOW  6
> >> +
> >> +static const struct {
> >> +     const char *name;
> >> +     int action;
> >> +} gpio_actions[] = {
> >> +     {"gpioset", TP_GPIO_CMD_SET},
> >> +     {"gpioclear", TP_GPIO_CMD_CLEAR},
> >> +     {"gpiotoggle", TP_GPIO_CMD_TOGGLE},
> >> +     {"gpiopulse", TP_GPIO_CMD_PULSE},
> >> +     {"gpiopulsehigh", TP_GPIO_CMD_PULSE_HIGH},
> >> +     {"gpiopulselow", TP_GPIO_CMD_PULSE_LOW},
> >> +};
> >> +
> >> +struct gpio_trace {
> >> +     int gpio;
> >> +     int action;
> >> +};
> >> +#endif
> >> +
> >>  struct trace_probe {
> >>       struct list_head        list;
> >>       struct kretprobe        rp;     /* Use rp.kp for kprobe use */
> >> @@ -38,6 +66,9 @@ struct trace_probe {
> >>       struct list_head        files;
> >>       ssize_t                 size;           /* trace entry size */
> >>       unsigned int            nr_args;
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +     struct gpio_trace               gpio_trace;
> >> +#endif
> >>       struct probe_arg        args[];
> >>  };
> >>
> >> @@ -164,10 +195,24 @@ error:
> >>       return ERR_PTR(ret);
> >>  }
> >>
> >> +static struct trace_probe *find_gpio_probe(int gpio)
> >> +{
> >> +     struct trace_probe *tp;
> >> +
> >> +     list_for_each_entry(tp, &probe_list, list)
> >> +     if ((tp->gpio_trace.action) && (tp->gpio_trace.gpio == gpio))
> >> +             return tp;
> >> +     return NULL;
> >> +}
> >> +
> >>  static void free_trace_probe(struct trace_probe *tp)
> >>  {
> >>       int i;
> >>
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +     if (tp->gpio_trace.action && !find_gpio_probe(tp->gpio_trace.gpio))
> >> +             gpio_free(tp->gpio_trace.gpio);
> >> +#endif
> >>       for (i = 0; i < tp->nr_args; i++)
> >>               traceprobe_free_probe_arg(&tp->args[i]);
> >>
> >> @@ -435,8 +480,14 @@ static int create_trace_probe(int argc, char **argv)
> >>  {
> >>       /*
> >>        * Argument syntax:
> >> -      *  - Add kprobe: p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS]
> >> -      *  - Add kretprobe: r[:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS]
> >> +      *  - Add kprobe: p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR
> >> +      *                [GPIOACTION@...ONUM] [FETCHARGS]
> >> +      *  - Add kretprobe: r[:[GRP/]EVENT] [MOD:]KSYM[+0]
> >> +      *                   [GPIOACTION@...ONUM] [FETCHARGS]
> >> +      * Gpio tracing:
> >> +      *   gpio action can be : gpioset, gpioclear, gpiotoggle, gpiopulse,
> >> +      *                        gpiopulsehigh and gpiopulselow
> >> +      *   gpionum is the id of the gpio
> >>        * Fetch args:
> >>        *  $retval     : fetch return value
> >>        *  $stack      : fetch stack address
> >> @@ -459,6 +510,9 @@ static int create_trace_probe(int argc, char **argv)
> >>       unsigned long offset = 0;
> >>       void *addr = NULL;
> >>       char buf[MAX_EVENT_NAME_LEN];
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +     int len;
> >> +#endif
> >>
> >>       /* argc must be >= 1 */
> >>       if (argv[0][0] == 'p')
> >> @@ -541,6 +595,7 @@ static int create_trace_probe(int argc, char **argv)
> >>                       return -EINVAL;
> >>               }
> >>       }
> >> +
> >>       argc -= 2; argv += 2;
> >>
> >>       /* setup a probe */
> >> @@ -562,6 +617,66 @@ static int create_trace_probe(int argc, char **argv)
> >>               return PTR_ERR(tp);
> >>       }
> >>
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +     /* parse the optionnal gpio action argument */
> >> +     for (i = 0; argc && (i < ARRAY_SIZE(gpio_actions)); i++) {
> >> +             len = strlen(gpio_actions[i].name);
> >> +             if (strncmp(argv[0], gpio_actions[i].name, len) == 0)
> >> +                     break;
> >> +     }
> >> +
> >> +     if (argc && (i < ARRAY_SIZE(gpio_actions))) {
> >> +             int gpio;
> >> +             unsigned long ul;
> >> +             int gpio_requested = 0;
> >> +             ret = -EINVAL;
> >> +             if (argv[0][len] != '@') {
> >> +                     pr_info("Syntax error. wrong gpio syntax\n");
> >> +                     goto error;
> >> +             }
> >> +
> >> +             if (kstrtoul(&argv[0][len+1], 0, &ul)) {
> >> +                     pr_info("Failed to parse gpio number.\n");
> >> +                     goto error;
> >> +             }
> >> +             gpio = ul;
> >> +
> >> +             if (!gpio_is_valid(gpio)) {
> >> +                     pr_info("gpio %d is not valid.\n", gpio);
> >> +                     goto error;
> >> +             }
> >> +
> >> +             if (gpio_cansleep(gpio))
> >> +                     pr_info("gpio %d can sleep. This may break your"
> >> +                             "kernel!!!!!!\n", gpio);
> >> +
> >> +             if (!find_gpio_probe(gpio)) {
> >> +                     ret = gpio_request(gpio, event);
> >> +                     if (ret) {
> >> +                             pr_info("can't request gpio %d.\n", gpio);
> >> +                             goto error;
> >> +                     }
> >> +                     gpio_requested = 1;
> >> +             }
> >> +
> >> +             if ((gpio_actions[i].action == TP_GPIO_CMD_CLEAR) ||
> >> +                     (gpio_actions[i].action == TP_GPIO_CMD_PULSE_LOW))
> >> +                     ret = gpio_direction_output(gpio, 1);
> >> +             else
> >> +                     ret = gpio_direction_output(gpio, 0);
> >> +             if (ret) {
> >> +                     pr_info("can't make gpio %d an output.\n", gpio);
> >> +                     if (gpio_requested)
> >> +                             gpio_free(gpio);
> >> +                     goto error;
> >> +             }
> >> +
> >> +             tp->gpio_trace.gpio = gpio;
> >> +             tp->gpio_trace.action = gpio_actions[i].action;
> >> +             argc -= 1; argv += 1;
> >> +     }
> >> +#endif
> >> +
> >>       /* parse arguments */
> >>       ret = 0;
> >>       for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
> >> @@ -1145,12 +1260,54 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri,
> >>  }
> >>  #endif       /* CONFIG_PERF_EVENTS */
> >>
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +static __kprobes void kprobe_gpio_take_action(int gpio, int action)
> >> +{
> >> +     int val;
> >> +     switch (action) {
> >> +     case TP_GPIO_CMD_PULSE_HIGH:
> >> +             gpio_set_value(gpio, 1);
> >> +             /* intentionnaly don't break here */
> >> +     case TP_GPIO_CMD_CLEAR:
> >> +             gpio_set_value(gpio, 0);
> >> +     break;
> >> +
> >> +     case TP_GPIO_CMD_PULSE_LOW:
> >> +             gpio_set_value(gpio, 0);
> >> +             /* intentionnaly don't break here */
> >> +     case TP_GPIO_CMD_SET:
> >> +             gpio_set_value(gpio, 1);
> >> +     break;
> >> +
> >> +     case TP_GPIO_CMD_TOGGLE:
> >> +             val = gpio_get_value(gpio);
> >> +             gpio_set_value(gpio, val ? 0 : 1);
> >> +     break;
> >> +
> >> +     case TP_GPIO_CMD_PULSE:
> >> +             val = gpio_get_value(gpio);
> >> +             gpio_set_value(gpio, val ? 0 : 1);
> >> +             gpio_set_value(gpio, val);
> >> +     break;
> >> +     }
> >> +}
> >> +
> >>  /*
> >>   * called by perf_trace_init() or __ftrace_set_clr_event() under event_mutex.
> >>   *
> >>   * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe
> >>   * lockless, but we can't race with this __init function.
> >>   */
> >> +/* Kprobe gpio handler */
> >> +static inline __kprobes void kprobe_gpio_func(struct trace_probe *tp,
> >> +                                           struct pt_regs *regs)
> >> +{
> >> +     if (tp->gpio_trace.action)
> >> +             kprobe_gpio_take_action(tp->gpio_trace.gpio,
> >> +                                     tp->gpio_trace.action);
> >> +}
> >> +#endif /* CONFIG_KPROBE_EVENT_GPIO */
> >> +
> >>  static __kprobes
> >>  int kprobe_register(struct ftrace_event_call *event,
> >>                   enum trace_reg type, void *data)
> >> @@ -1186,6 +1343,9 @@ int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
> >>
> >>       tp->nhit++;
> >>
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +     kprobe_gpio_func(tp, regs);
> >> +#endif
> >>       if (tp->flags & TP_FLAG_TRACE)
> >>               kprobe_trace_func(tp, regs);
> >>  #ifdef CONFIG_PERF_EVENTS
> >> @@ -1202,6 +1362,9 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
> >>
> >>       tp->nhit++;
> >>
> >> +#ifdef CONFIG_KPROBE_EVENT_GPIO
> >> +     kprobe_gpio_func(tp, regs);
> >> +#endif
> >>       if (tp->flags & TP_FLAG_TRACE)
> >>               kretprobe_trace_func(tp, ri, regs);
> >>  #ifdef CONFIG_PERF_EVENTS
> >>
> >
> >
> > --
> > Masami HIRAMATSU
> > IT Management Research Dept. Linux Technology Center
> > Hitachi, Ltd., Yokohama Research Laboratory
> > E-mail: masami.hiramatsu.pt@...achi.com
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
> > the body of a message to majordomo@...r.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ