NoExecute.cpp (3175B)
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 WarnNumberUTF8 22 23 #include "gc/StableCellHasher-inl.h" 24 #include "vm/Realm-inl.h" // for AutoRealm::AutoRealm 25 26 using namespace js; 27 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 */ 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 */ 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 */ 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 if (warning) { 80 return WarnNumberUTF8(cx, JSMSG_DEBUGGEE_WOULD_RUN, filename, 81 linenoStr); 82 } 83 84 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 85 JSMSG_DEBUGGEE_WOULD_RUN, filename, linenoStr); 86 return false; 87 } 88 } 89 return true; 90 }