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: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CACh+v5NgwyAD5xy-feykUDXpzVUuF2yFxP35TsnGk3r+LFtRPA@mail.gmail.com>
Date:	Tue, 17 Dec 2013 18:22:53 +0100
From:	Jean-Jacques Hiblot <jjhiblot@...phandler.com>
To:	Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>,
	tom.zanussi@...ux.intel.com
Cc:	Jean-Jacques Hiblot <jjhiblot@...phandler.com>,
	rostedt@...dmis.org, linux-gpio@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH] Tracing events with GPIOs

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.

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

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