diff options
author | Josh Matthews <josh@joshmatthews.net> | 2018-08-01 14:54:08 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2018-10-01 16:04:56 +0200 |
commit | 06bca43aeef990da8f02cd8b814329f7607365dd (patch) | |
tree | 364c331380a977e8cb0c8f3867a4bdfc578afe59 | |
parent | 5dc80dd07ad75d68cfea2babe64d421eb7b07ba3 (diff) | |
download | servo-06bca43aeef990da8f02cd8b814329f7607365dd.tar.gz servo-06bca43aeef990da8f02cd8b814329f7607365dd.zip |
script: Optionally store backtraces when throwing DOM exceptions.
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 30 | ||||
-rw-r--r-- | components/script/lib.rs | 2 | ||||
-rw-r--r-- | components/servo/Cargo.toml | 1 | ||||
-rw-r--r-- | ports/libsimpleservo/Cargo.toml | 3 | ||||
-rw-r--r-- | ports/servo/Cargo.toml | 1 | ||||
-rw-r--r-- | python/servo/build_commands.py | 5 | ||||
-rw-r--r-- | python/servo/command_base.py | 2 | ||||
-rw-r--r-- | servobuild.example | 8 |
9 files changed, 51 insertions, 2 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 5ad8c3df8ff..ca859bb472a 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -17,6 +17,7 @@ unstable = [] unrooted_must_root_lint = ["script_plugins/unrooted_must_root_lint"] default = ["unrooted_must_root_lint"] webgl_backtrace = ["backtrace", "canvas_traits/webgl_backtrace"] +js_backtrace = ["backtrace"] [build-dependencies] cmake = "0.1" diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index ce045b2c9d3..64b581f316d 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -4,6 +4,10 @@ //! Utilities to throw exceptions from Rust bindings. +#[cfg(feature = "js_backtrace")] +use backtrace::Backtrace; +#[cfg(feature = "js_backtrace")] +use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible}; @@ -24,6 +28,11 @@ use js::rust::wrappers::JS_SetPendingException; use libc::c_uint; use std::slice::from_raw_parts; +/// An optional stringified JS backtrace and stringified native backtrace from the +/// the last DOM exception that was reported. +#[cfg(feature = "js_backtrace")] +thread_local!(static LAST_EXCEPTION_BACKTRACE: DomRefCell<Option<(Option<String>, String)>> = DomRefCell::new(None)); + /// DOM exceptions that can be thrown by a native DOM method. #[derive(Clone, Debug, MallocSizeOf)] pub enum Error { @@ -90,6 +99,16 @@ pub type ErrorResult = Fallible<()>; /// Set a pending exception for the given `result` on `cx`. pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, result: Error) { + #[cfg(feature = "js_backtrace")] + { + capture_stack!(in(cx) let stack); + let js_stack = stack.and_then(|s| s.as_string(None)); + let rust_stack = Backtrace::new(); + LAST_EXCEPTION_BACKTRACE.with(|backtrace| { + *backtrace.borrow_mut() = Some((js_stack, format!("{:?}", rust_stack))); + }); + } + let code = match result { Error::IndexSize => DOMErrorName::IndexSizeError, Error::NotFound => DOMErrorName::NotFoundError, @@ -244,6 +263,17 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) "Error at {}:{}:{} {}", error_info.filename, error_info.lineno, error_info.column, error_info.message ); + #[cfg(feature = "js_backtrace")] + { + LAST_EXCEPTION_BACKTRACE.with(|backtrace| { + if let Some((js_backtrace, rust_backtrace)) = backtrace.borrow_mut().take() { + if let Some(stack) = js_backtrace { + eprintln!("JS backtrace:\n{}", stack); + } + eprintln!("Rust backtrace:\n{}", rust_backtrace); + } + }); + } if dispatch_event { GlobalScope::from_context(cx).report_an_error(error_info, value.handle()); diff --git a/components/script/lib.rs b/components/script/lib.rs index 66bc4ac40eb..097f69d7808 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -19,7 +19,7 @@ extern crate app_units; extern crate audio_video_metadata; -#[cfg(feature = "webgl_backtrace")] +#[cfg(any(feature = "webgl_backtrace", feature = "js_backtrace"))] extern crate backtrace; extern crate base64; #[macro_use] diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index ea0a3d1d3a2..7d2a7895215 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -17,6 +17,7 @@ webdriver = ["webdriver_server"] energy-profiling = ["profile_traits/energy-profiling"] debugmozjs = ["script/debugmozjs"] googlevr = ["webvr/googlevr"] +js_backtrace = ["script/js_backtrace"] webrender_debugger = ["webrender/debugger"] oculusvr = ["webvr/oculusvr"] unstable = [ diff --git a/ports/libsimpleservo/Cargo.toml b/ports/libsimpleservo/Cargo.toml index 75cde40fd23..5af57fe8e69 100644 --- a/ports/libsimpleservo/Cargo.toml +++ b/ports/libsimpleservo/Cargo.toml @@ -42,4 +42,5 @@ debugmozjs = ["libservo/debugmozjs"] unstable = ["libservo/unstable"] googlevr = ["libservo/googlevr"] oculusvr = ["libservo/oculusvr"] -webgl_backtrace = ["libservo/webgl_backtrace"]
\ No newline at end of file +webgl_backtrace = ["libservo/webgl_backtrace"] +js_backtrace = ["libservo/js_backtrace"] diff --git a/ports/servo/Cargo.toml b/ports/servo/Cargo.toml index e128738b365..298dae298f9 100644 --- a/ports/servo/Cargo.toml +++ b/ports/servo/Cargo.toml @@ -31,6 +31,7 @@ energy-profiling = ["libservo/energy-profiling"] debugmozjs = ["libservo/debugmozjs"] unstable = ["libservo/unstable"] webgl_backtrace = ["libservo/webgl_backtrace"] +js_backtrace = ["libservo/js_backtrace"] [target.'cfg(not(target_os = "android"))'.dependencies] backtrace = "0.3" diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 12287a0c8dc..ea942474063 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -257,6 +257,11 @@ class MachCommands(CommandBase): if debug_mozjs: features += ["debugmozjs"] + if self.config["build"]["webgl-backtrace"]: + features += ["webgl-backtrace"] + if self.config["build"]["dom-backtrace"]: + features += ["dom-backtrace"] + if features: opts += ["--features", "%s" % ' '.join(features)] diff --git a/python/servo/command_base.py b/python/servo/command_base.py index b335dcd69eb..8c9d5c61cbd 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -288,6 +288,8 @@ class CommandBase(object): self.config["build"].setdefault("rustflags", "") self.config["build"].setdefault("incremental", None) self.config["build"].setdefault("thinlto", False) + self.config["build"].setdefault("webgl-backtrace", False) + self.config["build"].setdefault("dom-backtrace", False) self.config.setdefault("android", {}) self.config["android"].setdefault("sdk", "") diff --git a/servobuild.example b/servobuild.example index 2df2dc256e1..2070da1a59c 100644 --- a/servobuild.example +++ b/servobuild.example @@ -32,6 +32,14 @@ android = false # Set "debug-mozjs" or use `mach build --debug-mozjs` to build a debug spidermonkey. debug-mozjs = false +# When a GL error occurs as a result of a WebGL operation, print the stack trace for the content +# JS and native Rust code that triggered the failed operation. Warning: very slow. +webgl-backtrace = false + +# When a DOM exception is reported, print the stack trace for the content JS and native Rust code +# that triggered it. +dom-backtrace = false + # Set to the path to your ccache binary to enable caching of compiler outputs #ccache = "/usr/local/bin/ccache" |