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