1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
6
7 #include "debugger/NoExecute.h"
8
9 #include "mozilla/Sprintf.h" // for SprintfLiteral
10
11 #include <stdio.h> // for fprintf, stdout
12
13 #include "debugger/Debugger.h" // for Debugger
14 #include "js/friend/DumpFunctions.h" // for DumpBacktrace
15 #include "js/friend/ErrorMessages.h" // for GetErrorMessage, JSMSG_DEBUGGEE_WOULD_RUN
16 #include "js/Promise.h" // for AutoDebuggerJobQueueInterruption
17 #include "js/RootingAPI.h" // for Handle
18 #include "vm/JSContext.h" // for ProtectedDataContextArg, JSContext
19 #include "vm/JSScript.h" // for JSScript
20 #include "vm/Realm.h" // for AutoRealm, Realm
21 #include "vm/Warnings.h" // for WarnNumberLatin1
22
23 #include "vm/Realm-inl.h" // for AutoRealm::AutoRealm
24
25 using namespace js;
26
EnterDebuggeeNoExecute(JSContext * cx,Debugger & dbg,const JS::AutoDebuggerJobQueueInterruption & adjqiProof)27 EnterDebuggeeNoExecute::EnterDebuggeeNoExecute(
28 JSContext* cx, Debugger& dbg,
29 const JS::AutoDebuggerJobQueueInterruption& adjqiProof)
30 : dbg_(dbg), unlocked_(nullptr), reported_(false) {
31 MOZ_ASSERT(adjqiProof.initialized());
32 stack_ = &cx->noExecuteDebuggerTop.ref();
33 prev_ = *stack_;
34 *stack_ = this;
35 }
36
37 #ifdef DEBUG
38 /* static */
isLockedInStack(JSContext * cx,Debugger & dbg)39 bool EnterDebuggeeNoExecute::isLockedInStack(JSContext* cx, Debugger& dbg) {
40 for (EnterDebuggeeNoExecute* it = cx->noExecuteDebuggerTop; it;
41 it = it->prev_) {
42 if (&it->debugger() == &dbg) {
43 return !it->unlocked_;
44 }
45 }
46 return false;
47 }
48 #endif
49
50 /* static */
findInStack(JSContext * cx)51 EnterDebuggeeNoExecute* EnterDebuggeeNoExecute::findInStack(JSContext* cx) {
52 Realm* debuggee = cx->realm();
53 for (EnterDebuggeeNoExecute* it = cx->noExecuteDebuggerTop; it;
54 it = it->prev_) {
55 Debugger& dbg = it->debugger();
56 if (!it->unlocked_ && dbg.observesGlobal(debuggee->maybeGlobal())) {
57 return it;
58 }
59 }
60 return nullptr;
61 }
62
63 /* static */
reportIfFoundInStack(JSContext * cx,HandleScript script)64 bool EnterDebuggeeNoExecute::reportIfFoundInStack(JSContext* cx,
65 HandleScript script) {
66 if (EnterDebuggeeNoExecute* nx = findInStack(cx)) {
67 bool warning = !cx->options().throwOnDebuggeeWouldRun();
68 if (!warning || !nx->reported_) {
69 AutoRealm ar(cx, nx->debugger().toJSObject());
70 nx->reported_ = true;
71 if (cx->options().dumpStackOnDebuggeeWouldRun()) {
72 fprintf(stdout, "Dumping stack for DebuggeeWouldRun:\n");
73 DumpBacktrace(cx);
74 }
75 const char* filename = script->filename() ? script->filename() : "(none)";
76 char linenoStr[15];
77 SprintfLiteral(linenoStr, "%u", script->lineno());
78 // FIXME: filename should be UTF-8 (bug 987069).
79 if (warning) {
80 return WarnNumberLatin1(cx, JSMSG_DEBUGGEE_WOULD_RUN, filename,
81 linenoStr);
82 }
83
84 JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
85 JSMSG_DEBUGGEE_WOULD_RUN, filename, linenoStr);
86 return false;
87 }
88 }
89 return true;
90 }
91