From 2c9a971b050f2a6b5b8509b7a6d91be8e6270566 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Sep 2014 15:20:09 +1000 Subject: [PATCH libinput] Add an event backtrace in case of a bug Store the last 64 events and print them to the log in case a bug condition is triggered. Key events that may comprise parts of passwords are converted to KEY_A to avoid accidental leakage. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 6 +++--- src/evdev-mt-touchpad-tap.c | 8 ++++---- src/evdev.c | 29 +++++++++++++++++++++++++++++ src/libinput-private.h | 33 +++++++++++++++++++++++++++------ src/libinput.c | 39 +++++++++++++++++++++++++++++++++++++++ src/timer.c | 2 +- 6 files changed, 103 insertions(+), 14 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 6af3fcf..64b9d0c 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -467,9 +467,9 @@ tp_process_button(struct tp_dispatch *tp, /* Ignore other buttons on clickpads */ if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { - log_bug_kernel(libinput, - "received %s button event on a clickpad\n", - libevdev_event_code_get_name(EV_KEY, e->code)); + log_bug_kernel_bt(libinput, + "received %s button event on a clickpad\n", + libevdev_event_code_get_name(EV_KEY, e->code)); return 0; } diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 0e37c5e..546fe02 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -146,8 +146,8 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, break; case TAP_EVENT_RELEASE: case TAP_EVENT_MOTION: - log_bug_libinput(libinput, - "invalid event, no fingers are down\n"); + log_bug_libinput_bt(libinput, + "invalid event, no fingers are down\n"); break; case TAP_EVENT_TIMEOUT: break; @@ -217,8 +217,8 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp, switch (event) { case TAP_EVENT_MOTION: case TAP_EVENT_RELEASE: - log_bug_libinput(libinput, - "invalid event when fingers are up\n"); + log_bug_libinput_bt(libinput, + "invalid event when fingers are up\n"); break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DRAGGING_OR_DOUBLETAP; diff --git a/src/evdev.c b/src/evdev.c index 6edacba..86026f9 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1114,6 +1114,33 @@ evdev_device_dispatch_one(struct evdev_device *device, } } +static inline void +store_event(struct evdev_device *device, + const struct input_event *ev) +{ + struct libinput *li = device->base.seat->libinput; + size_t size = ARRAY_LENGTH(li->backtrace.events); + size_t tail = li->backtrace.tail, + head = li->backtrace.head; + + li->backtrace.events[head] = *ev; + head = (head + 1) % size; + + if (tail == head) { + tail = (tail + 1) % size; + + while(tail != li->backtrace.head) { + if (li->backtrace.events[tail].type == EV_SYN) + break; + tail = (tail + 1) % size; + } + + li->backtrace.tail = tail; + } + + li->backtrace.head = head; +} + static int evdev_sync_device(struct evdev_device *device) { @@ -1125,6 +1152,7 @@ evdev_sync_device(struct evdev_device *device) LIBEVDEV_READ_FLAG_SYNC, &ev); if (rc < 0) break; + evdev_device_dispatch_one(device, &ev); } while (rc == LIBEVDEV_READ_STATUS_SYNC); @@ -1171,6 +1199,7 @@ evdev_device_dispatch(void *data) if (rc == 0) rc = LIBEVDEV_READ_STATUS_SUCCESS; } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { + store_event(device, &ev); evdev_device_dispatch_one(device, &ev); } } while (rc == LIBEVDEV_READ_STATUS_SUCCESS); diff --git a/src/libinput-private.h b/src/libinput-private.h index 012c82d..252d120 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -24,6 +24,7 @@ #define LIBINPUT_PRIVATE_H #include +#include #include "linux/input.h" @@ -65,6 +66,12 @@ struct libinput { enum libinput_log_priority log_priority; void *user_data; int refcount; + + struct { + struct input_event events[64]; + size_t tail; + size_t head; + } backtrace; }; typedef void (*libinput_seat_destroy_func) (struct libinput_seat *seat); @@ -179,16 +186,19 @@ struct libinput_event_listener { typedef void (*libinput_source_dispatch_t)(void *data); -#define log_debug(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__) -#define log_info(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__) -#define log_error(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__) -#define log_bug_kernel(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__) -#define log_bug_libinput(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__) -#define log_bug_client(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__) +#define log_debug(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_DEBUG, false, __VA_ARGS__) +#define log_info(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_INFO, false, __VA_ARGS__) +#define log_error(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, false, __VA_ARGS__) +#define log_bug_kernel(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, false, "kernel bug: " __VA_ARGS__) +#define log_bug_libinput(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, false, "libinput bug: " __VA_ARGS__) +#define log_bug_client(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, false, "client bug: " __VA_ARGS__) +#define log_bug_libinput_bt(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, true, "libinput bug: " __VA_ARGS__) +#define log_bug_kernel_bt(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, true, "kernel bug: " __VA_ARGS__) void log_msg(struct libinput *libinput, enum libinput_log_priority priority, + bool want_backtrace, const char *format, ...); void @@ -197,6 +207,17 @@ log_msg_va(struct libinput *libinput, const char *format, va_list args); + +#define libinput_assert(libinput_, cond) \ + if (!(cond)) { \ + libinput_backtrace_events(libinput_);\ + abort(); \ + } + +void +libinput_backtrace_events(const struct libinput *li); + + int libinput_init(struct libinput *libinput, const struct libinput_interface *interface, diff --git a/src/libinput.c b/src/libinput.c index 6f45405..3154ae3 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -97,6 +97,41 @@ libinput_default_log_func(struct libinput *libinput, vfprintf(stderr, format, args); } +static void +log_backtrace(struct libinput *li, + enum libinput_log_priority priority) +{ + size_t size = ARRAY_LENGTH(li->backtrace.events); + size_t tail = li->backtrace.tail, + head = li->backtrace.head; + const struct input_event *ev; + unsigned int code; + + log_msg(li, priority, false, "Event backtrace:\n"); + do { + tail = (tail + 1) % size; + ev = &li->backtrace.events[tail]; + + /* any key that could be part of a password, just use 'a' */ + if (ev->type == EV_KEY && + (ev->code > KEY_ESC && ev->code < KEY_ZENKAKUHANKAKU)) + code = KEY_A; + else + code = ev->code; + + log_msg(li, + priority, + false, + "E: %lu.%06u %04x %04x %04d # %s / %s %d\n", + ev->time.tv_sec, (unsigned int)ev->time.tv_usec, + ev->type, code, ev->value, + libevdev_event_type_get_name(ev->type), + libevdev_event_code_get_name(ev->type, ev->code), + ev->value + ); + } while (tail != head); +} + void log_msg_va(struct libinput *libinput, enum libinput_log_priority priority, @@ -111,6 +146,7 @@ log_msg_va(struct libinput *libinput, void log_msg(struct libinput *libinput, enum libinput_log_priority priority, + bool want_backtrace, const char *format, ...) { va_list args; @@ -118,6 +154,9 @@ log_msg(struct libinput *libinput, va_start(args, format); log_msg_va(libinput, priority, format, args); va_end(args); + + if (want_backtrace) + log_backtrace(libinput, priority); } LIBINPUT_EXPORT void diff --git a/src/timer.c b/src/timer.c index f6c8e42..57f540c 100644 --- a/src/timer.c +++ b/src/timer.c @@ -69,7 +69,7 @@ libinput_timer_set(struct libinput_timer *timer, uint64_t expire) #ifndef NDEBUG uint64_t now = libinput_now(timer->libinput); if (abs(expire - now) > 5000) - log_bug_libinput(timer->libinput, + log_bug_libinput_bt(timer->libinput, "timer offset more than 5s, now %" PRIu64 " expire %" PRIu64 "\n", now, expire); -- 2.1.0