aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2018-08-01 14:54:08 -0400
committerJosh Matthews <josh@joshmatthews.net>2018-10-01 16:04:56 +0200
commit06bca43aeef990da8f02cd8b814329f7607365dd (patch)
tree364c331380a977e8cb0c8f3867a4bdfc578afe59
parent5dc80dd07ad75d68cfea2babe64d421eb7b07ba3 (diff)
downloadservo-06bca43aeef990da8f02cd8b814329f7607365dd.tar.gz
servo-06bca43aeef990da8f02cd8b814329f7607365dd.zip
script: Optionally store backtraces when throwing DOM exceptions.
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/bindings/error.rs30
-rw-r--r--components/script/lib.rs2
-rw-r--r--components/servo/Cargo.toml1
-rw-r--r--ports/libsimpleservo/Cargo.toml3
-rw-r--r--ports/servo/Cargo.toml1
-rw-r--r--python/servo/build_commands.py5
-rw-r--r--python/servo/command_base.py2
-rw-r--r--servobuild.example8
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"