1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/xre/nsX11ErrorHandler.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,172 @@ 1.4 +/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsX11ErrorHandler.h" 1.10 + 1.11 +#include "prenv.h" 1.12 +#include "nsXULAppAPI.h" 1.13 +#include "nsExceptionHandler.h" 1.14 +#include "nsDebug.h" 1.15 + 1.16 +#include "mozilla/X11Util.h" 1.17 +#include <X11/Xlib.h> 1.18 + 1.19 +#define BUFSIZE 2048 // What Xlib uses with XGetErrorDatabaseText 1.20 + 1.21 +extern "C" { 1.22 +static int 1.23 +X11Error(Display *display, XErrorEvent *event) { 1.24 + // Get an indication of how long ago the request that caused the error was 1.25 + // made. 1.26 + unsigned long age = NextRequest(display) - event->serial; 1.27 + 1.28 + // Get a string to represent the request that caused the error. 1.29 + nsAutoCString message; 1.30 + if (event->request_code < 128) { 1.31 + // Core protocol request 1.32 + message.AppendInt(event->request_code); 1.33 + } else { 1.34 + // Extension request 1.35 + 1.36 + // man XSetErrorHandler says "the error handler should not call any 1.37 + // functions (directly or indirectly) on the display that will generate 1.38 + // protocol requests or that will look for input events" so we use another 1.39 + // temporary Display to request extension information. This assumes on 1.40 + // the DISPLAY environment variable has been set and matches what was used 1.41 + // to open |display|. 1.42 + Display *tmpDisplay = XOpenDisplay(nullptr); 1.43 + if (tmpDisplay) { 1.44 + int nExts; 1.45 + char** extNames = XListExtensions(tmpDisplay, &nExts); 1.46 + int first_error; 1.47 + if (extNames) { 1.48 + for (int i = 0; i < nExts; ++i) { 1.49 + int major_opcode, first_event; 1.50 + if (XQueryExtension(tmpDisplay, extNames[i], 1.51 + &major_opcode, &first_event, &first_error) 1.52 + && major_opcode == event->request_code) { 1.53 + message.Append(extNames[i]); 1.54 + message.Append('.'); 1.55 + message.AppendInt(event->minor_code); 1.56 + break; 1.57 + } 1.58 + } 1.59 + 1.60 + XFreeExtensionList(extNames); 1.61 + } 1.62 + XCloseDisplay(tmpDisplay); 1.63 + 1.64 +#if (MOZ_WIDGET_GTK == 2) 1.65 + // GDK2 calls XCloseDevice the devices that it opened on startup, but 1.66 + // the XI protocol no longer ensures that the devices will still exist. 1.67 + // If they have been removed, then a BadDevice error results. Ignore 1.68 + // this error. 1.69 + if (message.EqualsLiteral("XInputExtension.4") && 1.70 + event->error_code == first_error + 0) { 1.71 + return 0; 1.72 + } 1.73 +#endif 1.74 + } 1.75 + } 1.76 + 1.77 + char buffer[BUFSIZE]; 1.78 + if (message.IsEmpty()) { 1.79 + buffer[0] = '\0'; 1.80 + } else { 1.81 + XGetErrorDatabaseText(display, "XRequest", message.get(), "", 1.82 + buffer, sizeof(buffer)); 1.83 + } 1.84 + 1.85 + nsAutoCString notes; 1.86 + if (buffer[0]) { 1.87 + notes.Append(buffer); 1.88 + } else { 1.89 + notes.Append("Request "); 1.90 + notes.AppendInt(event->request_code); 1.91 + notes.Append('.'); 1.92 + notes.AppendInt(event->minor_code); 1.93 + } 1.94 + 1.95 + notes.Append(": "); 1.96 + 1.97 + // Get a string to describe the error. 1.98 + XGetErrorText(display, event->error_code, buffer, sizeof(buffer)); 1.99 + notes.Append(buffer); 1.100 + 1.101 + // For requests where Xlib gets the reply synchronously, |age| will be 1 1.102 + // and the stack will include the function making the request. For 1.103 + // asynchronous requests, the current stack will often be unrelated to the 1.104 + // point of making the request, even if |age| is 1, but sometimes this may 1.105 + // help us count back to the point of the request. With XSynchronize on, 1.106 + // the stack will include the function making the request, even though 1.107 + // |age| will be 2 for asynchronous requests because XSynchronize is 1.108 + // implemented by an empty request from an XSync, which has not yet been 1.109 + // processed. 1.110 + if (age > 1) { 1.111 + // XSynchronize returns the previous "after function". If a second 1.112 + // XSynchronize call returns the same function after an enable call then 1.113 + // synchronization must have already been enabled. 1.114 + if (XSynchronize(display, True) == XSynchronize(display, False)) { 1.115 + notes.Append("; sync"); 1.116 + } else { 1.117 + notes.Append("; "); 1.118 + notes.AppendInt(uint32_t(age)); 1.119 + notes.Append(" requests ago"); 1.120 + } 1.121 + } 1.122 + 1.123 +#ifdef MOZ_CRASHREPORTER 1.124 + switch (XRE_GetProcessType()) { 1.125 + case GeckoProcessType_Default: 1.126 + case GeckoProcessType_Plugin: 1.127 + case GeckoProcessType_Content: 1.128 + CrashReporter::AppendAppNotesToCrashReport(notes); 1.129 + break; 1.130 + default: 1.131 + ; // crash report notes not supported. 1.132 + } 1.133 +#endif 1.134 + 1.135 +#ifdef DEBUG 1.136 + // The resource id is unlikely to be useful in a crash report without 1.137 + // context of other ids, but add it to the debug console output. 1.138 + notes.Append("; id=0x"); 1.139 + notes.AppendInt(uint32_t(event->resourceid), 16); 1.140 +#ifdef MOZ_X11 1.141 + // Actually, for requests where Xlib gets the reply synchronously, 1.142 + // MOZ_X_SYNC=1 will not be necessary, but we don't have a table to tell us 1.143 + // which requests get a synchronous reply. 1.144 + if (!PR_GetEnv("MOZ_X_SYNC")) { 1.145 + notes.Append("\nRe-running with MOZ_X_SYNC=1 in the environment may give a more helpful backtrace."); 1.146 + } 1.147 +#endif 1.148 +#endif 1.149 + 1.150 +#ifdef MOZ_WIDGET_QT 1.151 + // We should not abort here if MOZ_X_SYNC is not set 1.152 + // until http://bugreports.qt.nokia.com/browse/QTBUG-4042 1.153 + // not fixed, just print error value 1.154 + if (!PR_GetEnv("MOZ_X_SYNC")) { 1.155 + fprintf(stderr, "XError: %s\n", notes.get()); 1.156 + return 0; // temporary workaround for bug 161472 1.157 + } 1.158 +#endif 1.159 + 1.160 + NS_RUNTIMEABORT(notes.get()); 1.161 + return 0; // not reached 1.162 +} 1.163 +} 1.164 + 1.165 +void 1.166 +InstallX11ErrorHandler() 1.167 +{ 1.168 + XSetErrorHandler(X11Error); 1.169 + 1.170 + Display *display = mozilla::DefaultXDisplay(); 1.171 + NS_ASSERTION(display, "No X display"); 1.172 + if (PR_GetEnv("MOZ_X_SYNC")) { 1.173 + XSynchronize(display, True); 1.174 + } 1.175 +}