Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "xpcprivate.h"
8 #include "jsprf.h"
9 #include "js/OldDebugAPI.h"
11 #ifdef XP_WIN
12 #include <windows.h>
13 #endif
15 static void DebugDump(const char* fmt, ...)
16 {
17 char buffer[2048];
18 va_list ap;
19 va_start(ap, fmt);
20 #ifdef XPWIN
21 _vsnprintf(buffer, sizeof(buffer), fmt, ap);
22 #else
23 vsnprintf(buffer, sizeof(buffer), fmt, ap);
24 #endif
25 buffer[sizeof(buffer)-1] = '\0';
26 va_end(ap);
27 #ifdef XP_WIN
28 if (IsDebuggerPresent()) {
29 OutputDebugStringA(buffer);
30 }
31 #endif
32 printf("%s", buffer);
33 }
35 bool
36 xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps)
37 {
38 if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
39 DebugDump("%s\n", buf);
40 JS_smprintf_free(buf);
41 }
42 return true;
43 }
45 char*
46 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
47 bool showThisProps)
48 {
49 JS::AutoSaveExceptionState state(cx);
51 char *buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
52 if (!buf)
53 DebugDump("%s", "Failed to format JavaScript stack for dump\n");
55 state.restore();
56 return buf;
57 }
59 /***************************************************************************/
61 static void
62 xpcDumpEvalErrorReporter(JSContext *cx, const char *message,
63 JSErrorReport *report)
64 {
65 DebugDump("Error: %s\n", message);
66 }
68 bool
69 xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text)
70 {
71 if (!cx || !text) {
72 DebugDump("%s", "invalid params passed to xpc_DumpEvalInJSStackFrame!\n");
73 return false;
74 }
76 DebugDump("js[%d]> %s\n", frameno, text);
78 uint32_t num = 0;
80 JSAbstractFramePtr frame = JSNullFramePtr();
82 JSBrokenFrameIterator iter(cx);
83 while (!iter.done()) {
84 if (num == frameno) {
85 frame = iter.abstractFramePtr();
86 break;
87 }
88 ++iter;
89 num++;
90 }
92 if (!frame) {
93 DebugDump("%s", "invalid frame number!\n");
94 return false;
95 }
97 JS::AutoSaveExceptionState exceptionState(cx);
98 JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter);
100 JS::RootedValue rval(cx);
101 JSString* str;
102 JSAutoByteString bytes;
103 if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) &&
104 nullptr != (str = ToString(cx, rval)) &&
105 bytes.encodeLatin1(cx, str)) {
106 DebugDump("%s\n", bytes.ptr());
107 } else {
108 DebugDump("%s", "eval failed!\n");
109 }
111 JS_SetErrorReporter(cx, older);
112 exceptionState.restore();
113 return true;
114 }
116 /***************************************************************************/
118 JSTrapStatus
119 xpc_DebuggerKeywordHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
120 jsval *rval, void *closure)
121 {
122 static const char line[] =
123 "------------------------------------------------------------------------\n";
124 DebugDump("%s", line);
125 DebugDump("%s", "Hit JavaScript \"debugger\" keyword. JS call stack...\n");
126 xpc_DumpJSStack(cx, true, true, false);
127 DebugDump("%s", line);
128 return JSTRAP_CONTINUE;
129 }
131 bool xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt)
132 {
133 return JS_SetDebuggerHandler(rt, xpc_DebuggerKeywordHandler, nullptr);
134 }