toolkit/xre/nsX11ErrorHandler.cpp

changeset 0
6474c204b198
     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 +}

mercurial