michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set ts=8 sts=4 et sw=4 tw=99: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "xpcprivate.h" michael@0: #include "jsprf.h" michael@0: #include "js/OldDebugAPI.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #endif michael@0: michael@0: static void DebugDump(const char* fmt, ...) michael@0: { michael@0: char buffer[2048]; michael@0: va_list ap; michael@0: va_start(ap, fmt); michael@0: #ifdef XPWIN michael@0: _vsnprintf(buffer, sizeof(buffer), fmt, ap); michael@0: #else michael@0: vsnprintf(buffer, sizeof(buffer), fmt, ap); michael@0: #endif michael@0: buffer[sizeof(buffer)-1] = '\0'; michael@0: va_end(ap); michael@0: #ifdef XP_WIN michael@0: if (IsDebuggerPresent()) { michael@0: OutputDebugStringA(buffer); michael@0: } michael@0: #endif michael@0: printf("%s", buffer); michael@0: } michael@0: michael@0: bool michael@0: xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps) michael@0: { michael@0: if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) { michael@0: DebugDump("%s\n", buf); michael@0: JS_smprintf_free(buf); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: char* michael@0: xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals, michael@0: bool showThisProps) michael@0: { michael@0: JS::AutoSaveExceptionState state(cx); michael@0: michael@0: char *buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps); michael@0: if (!buf) michael@0: DebugDump("%s", "Failed to format JavaScript stack for dump\n"); michael@0: michael@0: state.restore(); michael@0: return buf; michael@0: } michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: static void michael@0: xpcDumpEvalErrorReporter(JSContext *cx, const char *message, michael@0: JSErrorReport *report) michael@0: { michael@0: DebugDump("Error: %s\n", message); michael@0: } michael@0: michael@0: bool michael@0: xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text) michael@0: { michael@0: if (!cx || !text) { michael@0: DebugDump("%s", "invalid params passed to xpc_DumpEvalInJSStackFrame!\n"); michael@0: return false; michael@0: } michael@0: michael@0: DebugDump("js[%d]> %s\n", frameno, text); michael@0: michael@0: uint32_t num = 0; michael@0: michael@0: JSAbstractFramePtr frame = JSNullFramePtr(); michael@0: michael@0: JSBrokenFrameIterator iter(cx); michael@0: while (!iter.done()) { michael@0: if (num == frameno) { michael@0: frame = iter.abstractFramePtr(); michael@0: break; michael@0: } michael@0: ++iter; michael@0: num++; michael@0: } michael@0: michael@0: if (!frame) { michael@0: DebugDump("%s", "invalid frame number!\n"); michael@0: return false; michael@0: } michael@0: michael@0: JS::AutoSaveExceptionState exceptionState(cx); michael@0: JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter); michael@0: michael@0: JS::RootedValue rval(cx); michael@0: JSString* str; michael@0: JSAutoByteString bytes; michael@0: if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) && michael@0: nullptr != (str = ToString(cx, rval)) && michael@0: bytes.encodeLatin1(cx, str)) { michael@0: DebugDump("%s\n", bytes.ptr()); michael@0: } else { michael@0: DebugDump("%s", "eval failed!\n"); michael@0: } michael@0: michael@0: JS_SetErrorReporter(cx, older); michael@0: exceptionState.restore(); michael@0: return true; michael@0: } michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: JSTrapStatus michael@0: xpc_DebuggerKeywordHandler(JSContext *cx, JSScript *script, jsbytecode *pc, michael@0: jsval *rval, void *closure) michael@0: { michael@0: static const char line[] = michael@0: "------------------------------------------------------------------------\n"; michael@0: DebugDump("%s", line); michael@0: DebugDump("%s", "Hit JavaScript \"debugger\" keyword. JS call stack...\n"); michael@0: xpc_DumpJSStack(cx, true, true, false); michael@0: DebugDump("%s", line); michael@0: return JSTRAP_CONTINUE; michael@0: } michael@0: michael@0: bool xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt) michael@0: { michael@0: return JS_SetDebuggerHandler(rt, xpc_DebuggerKeywordHandler, nullptr); michael@0: }