xwm: Add an X11 error tracing infrastructure

This adds some infrastructure that records the current X11 sequence
number, file name, and line number at various places. When an X11 error
later comes in, this tracing infrastructure can use the sequence number
of the error to figure out which piece of code caused this X11 error.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2021-01-09 13:11:53 +01:00
parent c2f51f2705
commit 744fa2e1b7
5 changed files with 109 additions and 0 deletions

23
include/xwayland/trace.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef XWAYLAND_TRACE_H
#define XWAYLAND_TRACE_H
#include <xcb/xcb.h>
#include <wayland-util.h>
struct wlr_x11_trace {
struct wl_list trace_events; // trace_event::link
};
void wlr_x11_trace_init(struct wlr_x11_trace *trace);
void wlr_x11_trace_deinit(struct wlr_x11_trace *trace);
void wlr_x11_trace_received_event(struct wlr_x11_trace *trace, xcb_generic_event_t *event);
void wlr_x11_trace_log_error_trace(struct wlr_x11_trace *trace, uint32_t sequence);
void wlr_x11_trace_trace(struct wlr_x11_trace *trace, unsigned int sequence,
const char *file, unsigned int line);
#define WLR_X11_TRACE(trace, conn) \
wlr_x11_trace_trace((trace), xcb_no_operation(conn).sequence, __FILE__, __LINE__)
#endif

View file

@ -12,6 +12,7 @@
#include <xcb/xcb_errors.h>
#endif
#include "xwayland/selection.h"
#include "xwayland/trace.h"
/* This is in xcb/xcb_event.h, but pulling xcb-util just for a constant
* others redefine anyway is meh
@ -98,6 +99,7 @@ struct wlr_xwm {
struct wlr_xwayland *xwayland;
struct wl_event_source *event_source;
struct wlr_seat *seat;
struct wlr_x11_trace trace;
uint32_t ping_timeout;
xcb_atom_t atoms[ATOM_LAST];

View file

@ -56,6 +56,7 @@ wlr_files += files(
'selection/selection.c',
'server.c',
'sockets.c',
'trace.c',
'xwayland.c',
'xwm.c',
)

77
xwayland/trace.c Normal file
View file

@ -0,0 +1,77 @@
#include "xwayland/trace.h"
#include <stdlib.h>
#include <wlr/util/log.h>
struct trace_event {
const char *file;
unsigned int line;
unsigned int sequence;
struct wl_list link;
};
static void trace_event_free(struct trace_event *event) {
wl_list_remove(&event->link);
free(event);
}
void wlr_x11_trace_init(struct wlr_x11_trace *trace) {
wl_list_init(&trace->trace_events);
}
void wlr_x11_trace_deinit(struct wlr_x11_trace *trace) {
struct trace_event *event, *next;
wl_list_for_each_safe(event, next, &trace->trace_events, link) {
trace_event_free(event);
}
}
void wlr_x11_trace_trace(struct wlr_x11_trace *trace, unsigned int sequence,
const char *file, unsigned int line) {
struct trace_event *event = malloc(sizeof(*event));
if (event == NULL) {
return;
}
event->file = file;
event->line = line;
event->sequence = sequence;
wl_list_insert(trace->trace_events.prev, &event->link);
}
// Remove entries from the event queue which are no longer needed.
//
// This removes all but one event with an older sequence number than the given
// event.
void wlr_x11_trace_received_event(struct wlr_x11_trace *trace, xcb_generic_event_t *event) {
struct trace_event *entry, *next, *prev = NULL;
wl_list_for_each_safe(entry, next, &trace->trace_events, link) {
if (prev) {
if (entry->sequence >= event->full_sequence) {
break;
}
trace_event_free(prev);
}
prev = entry;
}
}
void wlr_x11_trace_log_error_trace(struct wlr_x11_trace *trace, uint32_t sequence) {
struct trace_event *entry, *prev = NULL;
wl_list_for_each(entry, &trace->trace_events, link) {
if (entry->sequence >= sequence) {
if (prev) {
wlr_log(WLR_ERROR, "X11 error happened somewhere after %s:%d",
prev->file, prev->line);
}
wlr_log(WLR_ERROR, "X11 error happened somewhere before %s:%d",
entry->file, entry->line);
return;
}
prev = entry;
}
if (prev) {
wlr_log(WLR_ERROR, "X11 error happened somewhere after %s:%d",
prev->file, prev->line);
}
}

View file

@ -1399,6 +1399,7 @@ static void xwm_handle_xcb_error(struct wlr_xwm *xwm, xcb_generic_error_t *ev) {
major_name, minor_name ? minor_name : "no minor",
error_name, extension ? extension : "no extension",
ev->sequence, ev->resource_id);
wlr_x11_trace_log_error_trace(&xwm->trace, ev->full_sequence);
return;
log_raw:
@ -1407,6 +1408,7 @@ log_raw:
"xcb error: op %"PRIu8":%"PRIu16", code %"PRIu8", sequence %"PRIu16", value %"PRIu32,
ev->major_code, ev->minor_code, ev->error_code,
ev->sequence, ev->resource_id);
wlr_x11_trace_log_error_trace(&xwm->trace, ev->full_sequence);
}
@ -1441,6 +1443,8 @@ static int x11_event_handler(int fd, uint32_t mask, void *data) {
while ((event = xcb_poll_for_event(xwm->xcb_conn))) {
count++;
wlr_x11_trace_received_event(&xwm->trace, event);
if (xwm->xwayland->user_event_handler &&
xwm->xwayland->user_event_handler(xwm, event)) {
break;
@ -1634,6 +1638,7 @@ void xwm_destroy(struct wlr_xwm *xwm) {
}
wl_list_remove(&xwm->compositor_new_surface.link);
wl_list_remove(&xwm->compositor_destroy.link);
wlr_x11_trace_deinit(&xwm->trace);
xcb_disconnect(xwm->xcb_conn);
xwm->xwayland->xwm = NULL;
@ -1850,6 +1855,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
xwm->xwayland = xwayland;
wl_list_init(&xwm->surfaces);
wl_list_init(&xwm->unpaired_surfaces);
wlr_x11_trace_init(&xwm->trace);
xwm->ping_timeout = 10000;
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);