servo: Merge #10824 - Communicate a backtrace to the constellation when panicking (from asajeffrey:communicate-backtrace-on-panic); r=Manishearth
authorAlan Jeffrey <ajeffrey@mozilla.com>
Tue, 26 Apr 2016 13:17:33 -0700
changeset 476801 3a0df6e25177502d35df3afb9a6a947ecc6a852a
parent 476800 42d884c976de897eb26a224ccaf621b6ead9e58b
child 476802 ad878a49fcc43b074e42da2f27b88639c4edafdd
push id44079
push userbmo:gps@mozilla.com
push dateSat, 04 Feb 2017 00:14:49 +0000
reviewersManishearth
servo: Merge #10824 - Communicate a backtrace to the constellation when panicking (from asajeffrey:communicate-backtrace-on-panic); r=Manishearth Send a representation of the backtrace from a pipeline thread to the constellation in the case of panic. This is the next step in communicating the backtrace to the browser chrome (#10334). Source-Repo: https://github.com/servo/servo Source-Revision: f773dc182badef4a4afac240d0d6fcbf57b76452
servo/components/compositing/constellation.rs
servo/components/msg/constellation_msg.rs
servo/components/servo/Cargo.lock
servo/components/util/Cargo.toml
servo/components/util/lib.rs
servo/components/util/panicking.rs
servo/components/util/thread.rs
servo/ports/cef/Cargo.lock
servo/ports/geckolib/Cargo.lock
servo/ports/gonk/Cargo.lock
--- a/servo/components/compositing/constellation.rs
+++ b/servo/components/compositing/constellation.rs
@@ -49,17 +49,16 @@ use sandboxing;
 use script_traits::{AnimationState, CompositorEvent, ConstellationControlMsg};
 use script_traits::{DocumentState, LayoutControlMsg};
 use script_traits::{IFrameLoadInfo, IFrameSandboxState, MozBrowserEvent, TimerEventRequest};
 use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::env;
 use std::io::Error as IOError;
-use std::io::{self, Write};
 use std::marker::PhantomData;
 use std::mem::replace;
 use std::process;
 use std::sync::mpsc::{Sender, channel, Receiver};
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
 use timer_scheduler::TimerScheduler;
 use url::Url;
@@ -178,16 +177,19 @@ pub struct Constellation<LTF, STF> {
     child_processes: Vec<ChildProcess>,
 
     /// Document states for loaded pipelines (used only when writing screenshots).
     document_states: HashMap<PipelineId, DocumentState>,
 
     // Webrender interface, if enabled.
     webrender_api_sender: Option<webrender_traits::RenderApiSender>,
 
+    /// Have we seen any panics? Hopefully always false!
+    handled_panic: bool,
+
     /// The random number generator and probability for closing pipelines.
     /// This is for testing the hardening of the constellation.
     random_pipeline_closure: Option<(StdRng, f32)>,
 }
 
 /// State needed to construct a constellation.
 pub struct InitialConstellationState {
     /// A channel through which messages can be sent to the compositor.
@@ -364,16 +366,17 @@ impl<LTF: LayoutThreadFactory, STF: Scri
                 } else {
                     None
                 },
                 webdriver: WebDriverData::new(),
                 scheduler_chan: TimerScheduler::start(),
                 child_processes: Vec::new(),
                 document_states: HashMap::new(),
                 webrender_api_sender: state.webrender_api_sender,
+                handled_panic: false,
                 random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| {
                     let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random);
                     let rng = StdRng::from_seed(&[seed]);
                     warn!("Randomly closing pipelines.");
                     info!("Using seed {} for random pipeline closure.", seed);
                     (rng, prob)
                 }),
             };
@@ -805,19 +808,19 @@ impl<LTF: LayoutThreadFactory, STF: Scri
             Request::Layout(FromLayoutMsg::ViewportConstrained(pipeline_id, constraints)) => {
                 debug!("constellation got viewport-constrained event message");
                 self.handle_viewport_constrained_msg(pipeline_id, constraints);
             }
 
 
             // Panic messages
 
-            Request::Panic((pipeline_id, panic_reason)) => {
+            Request::Panic((pipeline_id, panic_reason, backtrace)) => {
                 debug!("handling panic message ({:?})", pipeline_id);
-                self.handle_panic(pipeline_id, panic_reason);
+                self.handle_panic(pipeline_id, panic_reason, backtrace);
             }
         }
         true
     }
 
     fn handle_exit(&mut self) {
         for (_id, ref pipeline) in &self.pipelines {
             pipeline.exit();
@@ -837,65 +840,68 @@ impl<LTF: LayoutThreadFactory, STF: Scri
         }
         self.font_cache_thread.exit();
         self.compositor_proxy.send(ToCompositorMsg::ShutdownComplete);
     }
 
     fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IOError) {
         // Treat send error the same as receiving a panic message
         debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
-        self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err));
+        self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err), String::from("<none>"));
     }
 
-    fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String) {
+    fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: String) {
+        error!("Panic: {}", reason);
+        if !self.handled_panic || opts::get().full_backtraces {
+            // For the first panic, we print the full backtrace
+            error!("Backtrace:\n{}", backtrace);
+        } else {
+            error!("Backtrace skipped (run with -Z full-backtraces to see every backtrace).");
+        }
+
         if opts::get().hard_fail {
             // It's quite difficult to make Servo exit cleanly if some threads have failed.
             // Hard fail exists for test runners so we crash and that's good enough.
-            let mut stderr = io::stderr();
-            stderr.write_all("Pipeline failed in hard-fail mode.  Crashing!\n".as_bytes())
-                .expect("Failed to write to stderr!");
+            error!("Pipeline failed in hard-fail mode.  Crashing!");
             process::exit(1);
         }
 
         debug!("Panic handler for pipeline {:?}: {}.", pipeline_id, reason);
 
         if let Some(pipeline_id) = pipeline_id {
-            self.replace_pipeline_with_about_failure(pipeline_id);
+
+            let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info);
+            let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size);
+
+            // Notify the browser chrome that the pipeline has failed
+            self.trigger_mozbrowsererror(pipeline_id);
+
+            self.close_pipeline(pipeline_id, ExitPipelineMode::Force);
+
+            while let Some(pending_pipeline_id) = self.pending_frames.iter().find(|pending| {
+                pending.old_pipeline_id == Some(pipeline_id)
+            }).map(|frame| frame.new_pipeline_id) {
+                warn!("removing pending frame change for failed pipeline");
+                self.close_pipeline(pending_pipeline_id, ExitPipelineMode::Force);
+            }
+
+            warn!("creating replacement pipeline for about:failure");
+
+            let new_pipeline_id = PipelineId::new();
+            self.new_pipeline(new_pipeline_id,
+                              parent_info,
+                              window_size,
+                              None,
+                              LoadData::new(Url::parse("about:failure").expect("infallible"), None, None));
+
+            self.push_pending_frame(new_pipeline_id, Some(pipeline_id));
+
         }
 
-    }
-
-    fn replace_pipeline_with_about_failure(&mut self, pipeline_id: PipelineId) {
-
-        let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info);
-        let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size);
-
-        // Notify the browser chrome that the pipeline has failed
-        self.trigger_mozbrowsererror(pipeline_id);
-
-        self.close_pipeline(pipeline_id, ExitPipelineMode::Force);
-
-        while let Some(pending_pipeline_id) = self.pending_frames.iter().find(|pending| {
-            pending.old_pipeline_id == Some(pipeline_id)
-        }).map(|frame| frame.new_pipeline_id) {
-            warn!("removing pending frame change for failed pipeline");
-            self.close_pipeline(pending_pipeline_id, ExitPipelineMode::Force);
-        }
-
-        warn!("creating replacement pipeline for about:failure");
-
-        let new_pipeline_id = PipelineId::new();
-        self.new_pipeline(new_pipeline_id,
-                          parent_info,
-                          window_size,
-                          None,
-                          LoadData::new(Url::parse("about:failure").expect("infallible"), None, None));
-
-        self.push_pending_frame(new_pipeline_id, Some(pipeline_id));
-
+        self.handled_panic = true;
     }
 
     fn handle_init_load(&mut self, url: Url) {
         let window_size = self.window_size.visible_viewport;
         let root_pipeline_id = PipelineId::new();
         debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id);
         self.new_pipeline(root_pipeline_id, None, Some(window_size), None, LoadData::new(url.clone(), None, None));
         self.handle_load_start_msg(&root_pipeline_id);
--- a/servo/components/msg/constellation_msg.rs
+++ b/servo/components/msg/constellation_msg.rs
@@ -30,17 +30,17 @@ impl<T: Deserialize + Serialize> Constel
 }
 
 impl<T: Serialize + Deserialize> Clone for ConstellationChan<T> {
     fn clone(&self) -> ConstellationChan<T> {
         ConstellationChan(self.0.clone())
     }
 }
 
-pub type PanicMsg = (Option<PipelineId>, String);
+pub type PanicMsg = (Option<PipelineId>, String, String);
 
 #[derive(Copy, Clone, Deserialize, Serialize, HeapSizeOf)]
 pub struct WindowSizeData {
     /// The size of the initial layout viewport, before parsing an
     /// http://www.w3.org/TR/css-device-adapt/#initial-viewport
     pub initial_viewport: TypedSize2D<ViewportPx, f32>,
 
     /// The "viewing area" in page px. See `PagePx` documentation for details.
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -112,16 +112,37 @@ dependencies = [
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-skia 0.20130412.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "backtrace"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "bincode"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -376,16 +397,25 @@ dependencies = [
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "debug_unreachable"
 version = "0.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "unreachable 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2248,16 +2278,17 @@ name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "util"
 version = "0.0.1"
 dependencies = [
  "app_units 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.2.2 (git+https://github.com/servo/ipc-channel)",
  "js 0.1.2 (git+https://github.com/servo/rust-mozjs)",
--- a/servo/components/util/Cargo.toml
+++ b/servo/components/util/Cargo.toml
@@ -24,16 +24,17 @@ path = "../plugins"
 git = "https://github.com/servo/rust-mozjs"
 optional = true
 
 [dependencies.ipc-channel]
 git = "https://github.com/servo/ipc-channel"
 
 [dependencies]
 app_units = {version = "0.2.3", features = ["plugins"]}
+backtrace = "0.2.1"
 bitflags = "0.3"
 deque = "0.3.1"
 euclid = {version = "0.6.4", features = ["unstable", "plugins"]}
 getopts = "0.2.11"
 heapsize = "0.3.0"
 heapsize_plugin = "0.1.2"
 lazy_static = "0.1"
 libc = "0.2"
--- a/servo/components/util/lib.rs
+++ b/servo/components/util/lib.rs
@@ -13,16 +13,17 @@
 #![feature(reflect_marker)]
 #![feature(step_by)]
 
 #![plugin(heapsize_plugin, plugins, serde_macros)]
 
 #![deny(unsafe_code)]
 
 extern crate app_units;
+extern crate backtrace;
 #[allow(unused_extern_crates)]
 #[macro_use]
 extern crate bitflags;
 extern crate deque;
 extern crate euclid;
 extern crate getopts;
 extern crate heapsize;
 extern crate ipc_channel;
--- a/servo/components/util/panicking.rs
+++ b/servo/components/util/panicking.rs
@@ -1,17 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use opts;
 use std::any::Any;
 use std::boxed::FnBox;
 use std::cell::RefCell;
-use std::io::{Write, stderr};
 use std::panic::{PanicInfo, take_hook, set_hook};
 use std::sync::{Once, ONCE_INIT};
 use std::thread;
 
 // only set the panic hook once
 static HOOK_SET: Once = ONCE_INIT;
 
 /// TLS data pertaining to how failures should be reported
@@ -26,52 +24,30 @@ thread_local!(pub static LOCAL_INFO: Ref
 pub fn set_thread_local_hook(local: Box<FnBox(&Any)>) {
     LOCAL_INFO.with(|i| *i.borrow_mut() = Some(PanicHandlerLocal { fail: local }));
 }
 
 /// Initiates the custom panic hook
 /// Should be called in main() after arguments have been parsed
 pub fn initiate_panic_hook() {
 
-    // store it locally, we can't trust that opts::get() will work whilst panicking
-    let full_backtraces = opts::get().full_backtraces;
-
     // Set the panic handler only once. It is global.
     HOOK_SET.call_once(|| {
         // The original backtrace-printing hook. We still want to call this
         let hook = take_hook();
 
         let new_hook = move |info: &PanicInfo| {
             let payload = info.payload();
             let name = thread::current().name().unwrap_or("<unknown thread>").to_string();
             // Notify error handlers stored in LOCAL_INFO if any
             LOCAL_INFO.with(|i| {
-                if let Some(info) = i.borrow_mut().take() {
+                if let Some(local_info) = i.borrow_mut().take() {
                     debug!("Thread `{}` failed, notifying error handlers", name);
-                    (info.fail).call_box((payload, ));
+                    (local_info.fail).call_box((payload, ));
+                } else {
+                    hook(&info);
                 }
             });
-
-            // Skip cascading SendError/RecvError backtraces if allowed
-            if !full_backtraces {
-                if let Some(s) = payload.downcast_ref::<String>() {
-                    if s.contains("SendError") {
-                        let err = stderr();
-                        let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
-                                                    `SendError` (backtrace skipped)\n", name);
-                        return;
-                    } else if s.contains("RecvError")  {
-                        let err = stderr();
-                        let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \
-                                                    `RecvError` (backtrace skipped)\n", name);
-                        return;
-                    }
-                }
-            }
-
-            // Call the old hook to get the backtrace
-            hook(&info);
         };
         set_hook(Box::new(new_hook));
     });
 
-
 }
--- a/servo/components/util/thread.rs
+++ b/servo/components/util/thread.rs
@@ -1,12 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+use backtrace::Backtrace;
 use ipc_channel::ipc::IpcSender;
 use panicking;
 use serde::Serialize;
 use std::any::Any;
 use std::thread;
 use thread_state;
 
 pub fn spawn_named<F>(name: String, f: F)
@@ -15,24 +16,37 @@ pub fn spawn_named<F>(name: String, f: F
     thread::Builder::new().name(name).spawn(f).expect("Thread spawn failed");
 }
 
 /// Arrange to send a particular message to a channel if the thread fails.
 pub fn spawn_named_with_send_on_panic<F, Id>(name: String,
                                              state: thread_state::ThreadState,
                                              f: F,
                                              id: Id,
-                                             panic_chan: IpcSender<(Id, String)>)
+                                             panic_chan: IpcSender<(Id, String, String)>)
     where F: FnOnce() + Send + 'static,
           Id: Copy + Send + Serialize + 'static,
 {
     thread::Builder::new().name(name).spawn(move || {
         thread_state::initialize(state);
         panicking::set_thread_local_hook(Box::new(move |payload: &Any| {
             debug!("Thread failed, notifying constellation");
             let reason = payload.downcast_ref::<String>().map(|s| String::from(&**s))
                 .or(payload.downcast_ref::<&'static str>().map(|s| String::from(*s)))
                 .unwrap_or_else(|| String::from("<unknown reason>"));
-            let _ = panic_chan.send((id, reason));
+            // FIXME(ajeffrey): Really we should send the backtrace itself,
+            // not just a string representation. Unfortunately we can't, because
+            // Servo won't compile backtrace with the serialize-serde feature:
+            //
+            // .../quasi_macros-0.9.0/src/lib.rs:19:29: 19:32 error: mismatched types:
+            //  expected `&mut syntex::Registry`,
+            //     found `&mut rustc_plugin::Registry<'_>`
+            // (expected struct `syntex::Registry`,
+            //     found struct `rustc_plugin::Registry`) [E0308]
+            // .../quasi_macros-0.9.0/src/lib.rs:19     quasi_codegen::register(reg);
+            //
+            // so for the moment we just send a debug string.
+            let backtrace = format!("{:?}", Backtrace::new());
+            let _ = panic_chan.send((id, reason, backtrace));
         }));
         f()
     }).expect("Thread spawn failed");
 }
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -97,16 +97,37 @@ dependencies = [
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-skia 0.20130412.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "backtrace"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "bincode"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -346,16 +367,25 @@ dependencies = [
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "debug_unreachable"
 version = "0.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "unreachable 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2125,16 +2155,17 @@ name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "util"
 version = "0.0.1"
 dependencies = [
  "app_units 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.2.2 (git+https://github.com/servo/ipc-channel)",
  "js 0.1.2 (git+https://github.com/servo/rust-mozjs)",
--- a/servo/ports/geckolib/Cargo.lock
+++ b/servo/ports/geckolib/Cargo.lock
@@ -35,16 +35,37 @@ dependencies = [
 ]
 
 [[package]]
 name = "aster"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "backtrace"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "bincode"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -61,29 +82,43 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "byteorder"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "cfg-if"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "cssparser"
 version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "debug_unreachable"
 version = "0.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "unreachable 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -540,16 +575,17 @@ dependencies = [
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "util"
 version = "0.0.1"
 dependencies = [
  "app_units 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.2.2 (git+https://github.com/servo/ipc-channel)",
  "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/servo/ports/gonk/Cargo.lock
+++ b/servo/ports/gonk/Cargo.lock
@@ -90,16 +90,37 @@ dependencies = [
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 2.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-skia 0.20130412.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "backtrace"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "bincode"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -339,16 +360,25 @@ dependencies = [
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_macros 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "debug_unreachable"
 version = "0.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "unreachable 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2106,16 +2136,17 @@ name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "util"
 version = "0.0.1"
 dependencies = [
  "app_units 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_plugin 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.2.2 (git+https://github.com/servo/ipc-channel)",
  "js 0.1.2 (git+https://github.com/servo/rust-mozjs)",