aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml3
-rw-r--r--components/script/dom/bindings/error.rs30
-rw-r--r--components/script/dom/webglrenderingcontext.rs28
-rw-r--r--components/script/lib.rs2
4 files changed, 60 insertions, 3 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 1c8feb0f17e..ca859bb472a 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -16,6 +16,8 @@ debugmozjs = ['mozjs/debugmozjs']
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"
@@ -29,6 +31,7 @@ tinyfiledialogs = "3.0"
[dependencies]
app_units = "0.7"
audio-video-metadata = "0.1.4"
+backtrace = {version = "0.3", optional = true}
base64 = "0.6"
bitflags = "1.0"
bluetooth_traits = {path = "../bluetooth_traits"}
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/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 7367a38fdcf..754637ad52b 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -2,9 +2,11 @@
* 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/. */
+#[cfg(feature = "webgl_backtrace")]
+use backtrace::Backtrace;
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
-use canvas_traits::webgl::{DOMToTextureCommand, Parameter};
+use canvas_traits::webgl::{DOMToTextureCommand, Parameter, WebGLCommandBacktrace};
use canvas_traits::webgl::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender};
@@ -316,7 +318,7 @@ impl WebGLRenderingContext {
#[inline]
pub fn send_command(&self, command: WebGLCommand) {
- self.webgl_sender.send(command).unwrap();
+ self.webgl_sender.send(command, capture_webgl_backtrace(self)).unwrap();
}
#[inline]
@@ -1189,6 +1191,25 @@ impl WebGLRenderingContext {
}
}
+#[cfg(not(feature = "webgl_backtrace"))]
+#[inline]
+pub fn capture_webgl_backtrace<T: DomObject>(_: &T) -> WebGLCommandBacktrace {
+ WebGLCommandBacktrace {}
+}
+
+#[cfg(feature = "webgl_backtrace")]
+#[cfg_attr(feature = "webgl_backtrace", allow(unsafe_code))]
+pub fn capture_webgl_backtrace<T: DomObject>(obj: &T) -> WebGLCommandBacktrace {
+ let bt = Backtrace::new();
+ unsafe {
+ capture_stack!(in(obj.global().get_cx()) let stack);
+ WebGLCommandBacktrace {
+ backtrace: format!("{:?}", bt),
+ js_backtrace: stack.and_then(|s| s.as_string(None)),
+ }
+ }
+}
+
impl Drop for WebGLRenderingContext {
fn drop(&mut self) {
let _ = self.webgl_sender.send_remove();
@@ -1521,9 +1542,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
let (sender, receiver) = webgl_channel().unwrap();
// If the send does not succeed, assume context lost
+ let backtrace = capture_webgl_backtrace(self);
if self
.webgl_sender
- .send(WebGLCommand::GetContextAttributes(sender))
+ .send(WebGLCommand::GetContextAttributes(sender), backtrace)
.is_err()
{
return None;
diff --git a/components/script/lib.rs b/components/script/lib.rs
index f8341323466..097f69d7808 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -19,6 +19,8 @@
extern crate app_units;
extern crate audio_video_metadata;
+#[cfg(any(feature = "webgl_backtrace", feature = "js_backtrace"))]
+extern crate backtrace;
extern crate base64;
#[macro_use]
extern crate bitflags;