1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/OldDebugAPI.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1348 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JS debugging API. 1.12 + */ 1.13 + 1.14 +#include "js/OldDebugAPI.h" 1.15 + 1.16 +#include <string.h> 1.17 + 1.18 +#include "jscntxt.h" 1.19 +#include "jsfun.h" 1.20 +#include "jsgc.h" 1.21 +#include "jsobj.h" 1.22 +#include "jsopcode.h" 1.23 +#include "jsprf.h" 1.24 +#include "jsscript.h" 1.25 +#include "jsstr.h" 1.26 +#include "jstypes.h" 1.27 +#include "jswatchpoint.h" 1.28 + 1.29 +#include "frontend/SourceNotes.h" 1.30 +#include "jit/AsmJSModule.h" 1.31 +#include "vm/Debugger.h" 1.32 +#include "vm/Shape.h" 1.33 + 1.34 +#include "jsatominlines.h" 1.35 +#include "jsinferinlines.h" 1.36 +#include "jsscriptinlines.h" 1.37 + 1.38 +#include "vm/Debugger-inl.h" 1.39 +#include "vm/Interpreter-inl.h" 1.40 +#include "vm/Stack-inl.h" 1.41 + 1.42 +using namespace js; 1.43 +using namespace js::gc; 1.44 + 1.45 +using mozilla::PodZero; 1.46 + 1.47 +JS_PUBLIC_API(bool) 1.48 +JS_GetDebugMode(JSContext *cx) 1.49 +{ 1.50 + return cx->compartment()->debugMode(); 1.51 +} 1.52 + 1.53 +JS_PUBLIC_API(bool) 1.54 +JS_SetDebugMode(JSContext *cx, bool debug) 1.55 +{ 1.56 + return JS_SetDebugModeForCompartment(cx, cx->compartment(), debug); 1.57 +} 1.58 + 1.59 +JS_PUBLIC_API(void) 1.60 +JS_SetRuntimeDebugMode(JSRuntime *rt, bool debug) 1.61 +{ 1.62 + rt->debugMode = !!debug; 1.63 +} 1.64 + 1.65 +static bool 1.66 +IsTopFrameConstructing(JSContext *cx, AbstractFramePtr frame) 1.67 +{ 1.68 + ScriptFrameIter iter(cx); 1.69 + JS_ASSERT(iter.abstractFramePtr() == frame); 1.70 + return iter.isConstructing(); 1.71 +} 1.72 + 1.73 +JSTrapStatus 1.74 +js::ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc) 1.75 +{ 1.76 + JS_ASSERT_IF(frame.isInterpreterFrame(), frame.asInterpreterFrame() == cx->interpreterFrame()); 1.77 + 1.78 + if (!frame.script()->selfHosted()) { 1.79 + JSAbstractFramePtr jsframe(frame.raw(), pc); 1.80 + if (frame.isFramePushedByExecute()) { 1.81 + if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook) 1.82 + frame.setHookData(hook(cx, jsframe, IsTopFrameConstructing(cx, frame), 1.83 + true, 0, cx->runtime()->debugHooks.executeHookData)); 1.84 + } else { 1.85 + if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook) 1.86 + frame.setHookData(hook(cx, jsframe, IsTopFrameConstructing(cx, frame), 1.87 + true, 0, cx->runtime()->debugHooks.callHookData)); 1.88 + } 1.89 + } 1.90 + 1.91 + RootedValue rval(cx); 1.92 + JSTrapStatus status = Debugger::onEnterFrame(cx, frame, &rval); 1.93 + switch (status) { 1.94 + case JSTRAP_CONTINUE: 1.95 + break; 1.96 + case JSTRAP_THROW: 1.97 + cx->setPendingException(rval); 1.98 + break; 1.99 + case JSTRAP_ERROR: 1.100 + cx->clearPendingException(); 1.101 + break; 1.102 + case JSTRAP_RETURN: 1.103 + frame.setReturnValue(rval); 1.104 + break; 1.105 + default: 1.106 + MOZ_ASSUME_UNREACHABLE("bad Debugger::onEnterFrame JSTrapStatus value"); 1.107 + } 1.108 + return status; 1.109 +} 1.110 + 1.111 +bool 1.112 +js::ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc, bool okArg) 1.113 +{ 1.114 + JS_ASSERT_IF(frame.isInterpreterFrame(), frame.asInterpreterFrame() == cx->interpreterFrame()); 1.115 + 1.116 + bool ok = okArg; 1.117 + 1.118 + // We don't add hook data for self-hosted scripts, so we don't need to check for them, here. 1.119 + if (void *hookData = frame.maybeHookData()) { 1.120 + JSAbstractFramePtr jsframe(frame.raw(), pc); 1.121 + if (frame.isFramePushedByExecute()) { 1.122 + if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook) 1.123 + hook(cx, jsframe, IsTopFrameConstructing(cx, frame), false, &ok, hookData); 1.124 + } else { 1.125 + if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook) 1.126 + hook(cx, jsframe, IsTopFrameConstructing(cx, frame), false, &ok, hookData); 1.127 + } 1.128 + } 1.129 + 1.130 + return Debugger::onLeaveFrame(cx, frame, ok); 1.131 +} 1.132 + 1.133 +JSTrapStatus 1.134 +js::DebugExceptionUnwind(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc) 1.135 +{ 1.136 + JS_ASSERT(cx->compartment()->debugMode()); 1.137 + 1.138 + if (!cx->runtime()->debugHooks.throwHook && cx->compartment()->getDebuggees().empty()) 1.139 + return JSTRAP_CONTINUE; 1.140 + 1.141 + /* Call debugger throw hook if set. */ 1.142 + RootedValue rval(cx); 1.143 + JSTrapStatus status = Debugger::onExceptionUnwind(cx, &rval); 1.144 + if (status == JSTRAP_CONTINUE) { 1.145 + if (JSThrowHook handler = cx->runtime()->debugHooks.throwHook) { 1.146 + RootedScript script(cx, frame.script()); 1.147 + status = handler(cx, script, pc, rval.address(), cx->runtime()->debugHooks.throwHookData); 1.148 + } 1.149 + } 1.150 + 1.151 + switch (status) { 1.152 + case JSTRAP_ERROR: 1.153 + cx->clearPendingException(); 1.154 + break; 1.155 + 1.156 + case JSTRAP_RETURN: 1.157 + cx->clearPendingException(); 1.158 + frame.setReturnValue(rval); 1.159 + break; 1.160 + 1.161 + case JSTRAP_THROW: 1.162 + cx->setPendingException(rval); 1.163 + break; 1.164 + 1.165 + case JSTRAP_CONTINUE: 1.166 + break; 1.167 + 1.168 + default: 1.169 + MOZ_ASSUME_UNREACHABLE("Invalid trap status"); 1.170 + } 1.171 + 1.172 + return status; 1.173 +} 1.174 + 1.175 +JS_FRIEND_API(bool) 1.176 +JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug) 1.177 +{ 1.178 + for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) { 1.179 + // Invalidate a zone at a time to avoid doing a zone-wide CellIter 1.180 + // per compartment. 1.181 + AutoDebugModeInvalidation invalidate(zone); 1.182 + for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { 1.183 + // Ignore special compartments (atoms, JSD compartments) 1.184 + if (c->principals) { 1.185 + if (!c->setDebugModeFromC(cx, !!debug, invalidate)) 1.186 + return false; 1.187 + } 1.188 + } 1.189 + } 1.190 + return true; 1.191 +} 1.192 + 1.193 +JS_FRIEND_API(bool) 1.194 +JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, bool debug) 1.195 +{ 1.196 + AutoDebugModeInvalidation invalidate(comp); 1.197 + return comp->setDebugModeFromC(cx, !!debug, invalidate); 1.198 +} 1.199 + 1.200 +static bool 1.201 +CheckDebugMode(JSContext *cx) 1.202 +{ 1.203 + bool debugMode = JS_GetDebugMode(cx); 1.204 + /* 1.205 + * :TODO: 1.206 + * This probably should be an assertion, since it's indicative of a severe 1.207 + * API misuse. 1.208 + */ 1.209 + if (!debugMode) { 1.210 + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, 1.211 + nullptr, JSMSG_NEED_DEBUG_MODE); 1.212 + } 1.213 + return debugMode; 1.214 +} 1.215 + 1.216 +JS_PUBLIC_API(bool) 1.217 +JS_SetSingleStepMode(JSContext *cx, HandleScript script, bool singleStep) 1.218 +{ 1.219 + assertSameCompartment(cx, script); 1.220 + 1.221 + if (!CheckDebugMode(cx)) 1.222 + return false; 1.223 + 1.224 + return script->setStepModeFlag(cx, singleStep); 1.225 +} 1.226 + 1.227 +JS_PUBLIC_API(bool) 1.228 +JS_SetTrap(JSContext *cx, HandleScript script, jsbytecode *pc, JSTrapHandler handler, 1.229 + HandleValue closure) 1.230 +{ 1.231 + assertSameCompartment(cx, script, closure); 1.232 + 1.233 + if (!CheckDebugMode(cx)) 1.234 + return false; 1.235 + 1.236 + BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc); 1.237 + if (!site) 1.238 + return false; 1.239 + site->setTrap(cx->runtime()->defaultFreeOp(), handler, closure); 1.240 + return true; 1.241 +} 1.242 + 1.243 +JS_PUBLIC_API(void) 1.244 +JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, 1.245 + JSTrapHandler *handlerp, jsval *closurep) 1.246 +{ 1.247 + if (BreakpointSite *site = script->getBreakpointSite(pc)) { 1.248 + site->clearTrap(cx->runtime()->defaultFreeOp(), handlerp, closurep); 1.249 + } else { 1.250 + if (handlerp) 1.251 + *handlerp = nullptr; 1.252 + if (closurep) 1.253 + *closurep = JSVAL_VOID; 1.254 + } 1.255 +} 1.256 + 1.257 +JS_PUBLIC_API(void) 1.258 +JS_ClearScriptTraps(JSRuntime *rt, JSScript *script) 1.259 +{ 1.260 + script->clearTraps(rt->defaultFreeOp()); 1.261 +} 1.262 + 1.263 +JS_PUBLIC_API(void) 1.264 +JS_ClearAllTrapsForCompartment(JSContext *cx) 1.265 +{ 1.266 + cx->compartment()->clearTraps(cx->runtime()->defaultFreeOp()); 1.267 +} 1.268 + 1.269 +JS_PUBLIC_API(bool) 1.270 +JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure) 1.271 +{ 1.272 + rt->debugHooks.interruptHook = hook; 1.273 + rt->debugHooks.interruptHookData = closure; 1.274 + 1.275 + for (ActivationIterator iter(rt); !iter.done(); ++iter) { 1.276 + if (iter->isInterpreter()) 1.277 + iter->asInterpreter()->enableInterruptsUnconditionally(); 1.278 + } 1.279 + 1.280 + return true; 1.281 +} 1.282 + 1.283 +JS_PUBLIC_API(bool) 1.284 +JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep) 1.285 +{ 1.286 + if (hoop) 1.287 + *hoop = rt->debugHooks.interruptHook; 1.288 + if (closurep) 1.289 + *closurep = rt->debugHooks.interruptHookData; 1.290 + rt->debugHooks.interruptHook = 0; 1.291 + rt->debugHooks.interruptHookData = 0; 1.292 + return true; 1.293 +} 1.294 + 1.295 +/************************************************************************/ 1.296 + 1.297 +JS_PUBLIC_API(bool) 1.298 +JS_SetWatchPoint(JSContext *cx, HandleObject origobj, HandleId id, 1.299 + JSWatchPointHandler handler, HandleObject closure) 1.300 +{ 1.301 + assertSameCompartment(cx, origobj); 1.302 + 1.303 + RootedObject obj(cx, GetInnerObject(cx, origobj)); 1.304 + if (!obj) 1.305 + return false; 1.306 + 1.307 + RootedId propid(cx); 1.308 + 1.309 + if (JSID_IS_INT(id)) { 1.310 + propid = id; 1.311 + } else if (JSID_IS_OBJECT(id)) { 1.312 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH_PROP); 1.313 + return false; 1.314 + } else { 1.315 + RootedValue val(cx, IdToValue(id)); 1.316 + if (!ValueToId<CanGC>(cx, val, &propid)) 1.317 + return false; 1.318 + } 1.319 + 1.320 + if (!obj->isNative() || obj->is<TypedArrayObject>()) { 1.321 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_WATCH, 1.322 + obj->getClass()->name); 1.323 + return false; 1.324 + } 1.325 + 1.326 + /* 1.327 + * Use sparse indexes for watched objects, as dense elements can be written 1.328 + * to without checking the watchpoint map. 1.329 + */ 1.330 + if (!JSObject::sparsifyDenseElements(cx, obj)) 1.331 + return false; 1.332 + 1.333 + types::MarkTypePropertyNonData(cx, obj, propid); 1.334 + 1.335 + WatchpointMap *wpmap = cx->compartment()->watchpointMap; 1.336 + if (!wpmap) { 1.337 + wpmap = cx->runtime()->new_<WatchpointMap>(); 1.338 + if (!wpmap || !wpmap->init()) { 1.339 + js_ReportOutOfMemory(cx); 1.340 + return false; 1.341 + } 1.342 + cx->compartment()->watchpointMap = wpmap; 1.343 + } 1.344 + return wpmap->watch(cx, obj, propid, handler, closure); 1.345 +} 1.346 + 1.347 +JS_PUBLIC_API(bool) 1.348 +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id, 1.349 + JSWatchPointHandler *handlerp, JSObject **closurep) 1.350 +{ 1.351 + assertSameCompartment(cx, obj, id); 1.352 + 1.353 + if (WatchpointMap *wpmap = cx->compartment()->watchpointMap) 1.354 + wpmap->unwatch(obj, id, handlerp, closurep); 1.355 + return true; 1.356 +} 1.357 + 1.358 +JS_PUBLIC_API(bool) 1.359 +JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj) 1.360 +{ 1.361 + assertSameCompartment(cx, obj); 1.362 + 1.363 + if (WatchpointMap *wpmap = cx->compartment()->watchpointMap) 1.364 + wpmap->unwatchObject(obj); 1.365 + return true; 1.366 +} 1.367 + 1.368 +/************************************************************************/ 1.369 + 1.370 +JS_PUBLIC_API(unsigned) 1.371 +JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) 1.372 +{ 1.373 + return js::PCToLineNumber(script, pc); 1.374 +} 1.375 + 1.376 +JS_PUBLIC_API(jsbytecode *) 1.377 +JS_LineNumberToPC(JSContext *cx, JSScript *script, unsigned lineno) 1.378 +{ 1.379 + return js_LineNumberToPC(script, lineno); 1.380 +} 1.381 + 1.382 +JS_PUBLIC_API(jsbytecode *) 1.383 +JS_EndPC(JSContext *cx, JSScript *script) 1.384 +{ 1.385 + return script->codeEnd(); 1.386 +} 1.387 + 1.388 +JS_PUBLIC_API(bool) 1.389 +JS_GetLinePCs(JSContext *cx, JSScript *script, 1.390 + unsigned startLine, unsigned maxLines, 1.391 + unsigned* count, unsigned** retLines, jsbytecode*** retPCs) 1.392 +{ 1.393 + size_t len = (script->length() > maxLines ? maxLines : script->length()); 1.394 + unsigned *lines = cx->pod_malloc<unsigned>(len); 1.395 + if (!lines) 1.396 + return false; 1.397 + 1.398 + jsbytecode **pcs = cx->pod_malloc<jsbytecode*>(len); 1.399 + if (!pcs) { 1.400 + js_free(lines); 1.401 + return false; 1.402 + } 1.403 + 1.404 + unsigned lineno = script->lineno(); 1.405 + unsigned offset = 0; 1.406 + unsigned i = 0; 1.407 + for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { 1.408 + offset += SN_DELTA(sn); 1.409 + SrcNoteType type = (SrcNoteType) SN_TYPE(sn); 1.410 + if (type == SRC_SETLINE || type == SRC_NEWLINE) { 1.411 + if (type == SRC_SETLINE) 1.412 + lineno = (unsigned) js_GetSrcNoteOffset(sn, 0); 1.413 + else 1.414 + lineno++; 1.415 + 1.416 + if (lineno >= startLine) { 1.417 + lines[i] = lineno; 1.418 + pcs[i] = script->offsetToPC(offset); 1.419 + if (++i >= maxLines) 1.420 + break; 1.421 + } 1.422 + } 1.423 + } 1.424 + 1.425 + *count = i; 1.426 + if (retLines) 1.427 + *retLines = lines; 1.428 + else 1.429 + js_free(lines); 1.430 + 1.431 + if (retPCs) 1.432 + *retPCs = pcs; 1.433 + else 1.434 + js_free(pcs); 1.435 + 1.436 + return true; 1.437 +} 1.438 + 1.439 +JS_PUBLIC_API(unsigned) 1.440 +JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun) 1.441 +{ 1.442 + return fun->nargs(); 1.443 +} 1.444 + 1.445 +JS_PUBLIC_API(bool) 1.446 +JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun) 1.447 +{ 1.448 + return fun->nonLazyScript()->bindings.count() > 0; 1.449 +} 1.450 + 1.451 +extern JS_PUBLIC_API(uintptr_t *) 1.452 +JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **memp) 1.453 +{ 1.454 + RootedScript script(cx, fun->nonLazyScript()); 1.455 + BindingVector bindings(cx); 1.456 + if (!FillBindingVector(script, &bindings)) 1.457 + return nullptr; 1.458 + 1.459 + LifoAlloc &lifo = cx->tempLifoAlloc(); 1.460 + 1.461 + // Store the LifoAlloc::Mark right before the allocation. 1.462 + LifoAlloc::Mark mark = lifo.mark(); 1.463 + void *mem = lifo.alloc(sizeof(LifoAlloc::Mark) + bindings.length() * sizeof(uintptr_t)); 1.464 + if (!mem) { 1.465 + js_ReportOutOfMemory(cx); 1.466 + return nullptr; 1.467 + } 1.468 + *memp = mem; 1.469 + *reinterpret_cast<LifoAlloc::Mark*>(mem) = mark; 1.470 + 1.471 + // Munge data into the API this method implements. Avert your eyes! 1.472 + uintptr_t *names = reinterpret_cast<uintptr_t*>((char*)mem + sizeof(LifoAlloc::Mark)); 1.473 + for (size_t i = 0; i < bindings.length(); i++) 1.474 + names[i] = reinterpret_cast<uintptr_t>(bindings[i].name()); 1.475 + 1.476 + return names; 1.477 +} 1.478 + 1.479 +extern JS_PUBLIC_API(JSAtom *) 1.480 +JS_LocalNameToAtom(uintptr_t w) 1.481 +{ 1.482 + return reinterpret_cast<JSAtom *>(w); 1.483 +} 1.484 + 1.485 +extern JS_PUBLIC_API(JSString *) 1.486 +JS_AtomKey(JSAtom *atom) 1.487 +{ 1.488 + return atom; 1.489 +} 1.490 + 1.491 +extern JS_PUBLIC_API(void) 1.492 +JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mem) 1.493 +{ 1.494 + cx->tempLifoAlloc().release(*reinterpret_cast<LifoAlloc::Mark*>(mem)); 1.495 +} 1.496 + 1.497 +JS_PUBLIC_API(JSScript *) 1.498 +JS_GetFunctionScript(JSContext *cx, HandleFunction fun) 1.499 +{ 1.500 + if (fun->isNative()) 1.501 + return nullptr; 1.502 + if (fun->isInterpretedLazy()) { 1.503 + AutoCompartment funCompartment(cx, fun); 1.504 + JSScript *script = fun->getOrCreateScript(cx); 1.505 + if (!script) 1.506 + MOZ_CRASH(); 1.507 + return script; 1.508 + } 1.509 + return fun->nonLazyScript(); 1.510 +} 1.511 + 1.512 +JS_PUBLIC_API(JSNative) 1.513 +JS_GetFunctionNative(JSContext *cx, JSFunction *fun) 1.514 +{ 1.515 + return fun->maybeNative(); 1.516 +} 1.517 + 1.518 +JS_PUBLIC_API(JSPrincipals *) 1.519 +JS_GetScriptPrincipals(JSScript *script) 1.520 +{ 1.521 + return script->principals(); 1.522 +} 1.523 + 1.524 +JS_PUBLIC_API(JSPrincipals *) 1.525 +JS_GetScriptOriginPrincipals(JSScript *script) 1.526 +{ 1.527 + return script->originPrincipals(); 1.528 +} 1.529 + 1.530 +/************************************************************************/ 1.531 + 1.532 +JS_PUBLIC_API(JSFunction *) 1.533 +JS_GetScriptFunction(JSContext *cx, JSScript *script) 1.534 +{ 1.535 + script->ensureNonLazyCanonicalFunction(cx); 1.536 + return script->functionNonDelazifying(); 1.537 +} 1.538 + 1.539 +JS_PUBLIC_API(JSObject *) 1.540 +JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj) 1.541 +{ 1.542 + return obj->enclosingScope(); 1.543 +} 1.544 + 1.545 +JS_PUBLIC_API(const char *) 1.546 +JS_GetDebugClassName(JSObject *obj) 1.547 +{ 1.548 + if (obj->is<DebugScopeObject>()) 1.549 + return obj->as<DebugScopeObject>().scope().getClass()->name; 1.550 + return obj->getClass()->name; 1.551 +} 1.552 + 1.553 +/************************************************************************/ 1.554 + 1.555 +JS_PUBLIC_API(const char *) 1.556 +JS_GetScriptFilename(JSScript *script) 1.557 +{ 1.558 + return script->filename(); 1.559 +} 1.560 + 1.561 +JS_PUBLIC_API(const jschar *) 1.562 +JS_GetScriptSourceMap(JSContext *cx, JSScript *script) 1.563 +{ 1.564 + ScriptSource *source = script->scriptSource(); 1.565 + JS_ASSERT(source); 1.566 + return source->hasSourceMapURL() ? source->sourceMapURL() : nullptr; 1.567 +} 1.568 + 1.569 +JS_PUBLIC_API(unsigned) 1.570 +JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script) 1.571 +{ 1.572 + return script->lineno(); 1.573 +} 1.574 + 1.575 +JS_PUBLIC_API(unsigned) 1.576 +JS_GetScriptLineExtent(JSContext *cx, JSScript *script) 1.577 +{ 1.578 + return js_GetScriptLineExtent(script); 1.579 +} 1.580 + 1.581 +JS_PUBLIC_API(JSVersion) 1.582 +JS_GetScriptVersion(JSContext *cx, JSScript *script) 1.583 +{ 1.584 + return VersionNumber(script->getVersion()); 1.585 +} 1.586 + 1.587 +JS_PUBLIC_API(bool) 1.588 +JS_GetScriptIsSelfHosted(JSScript *script) 1.589 +{ 1.590 + return script->selfHosted(); 1.591 +} 1.592 + 1.593 +/***************************************************************************/ 1.594 + 1.595 +JS_PUBLIC_API(void) 1.596 +JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) 1.597 +{ 1.598 + rt->debugHooks.newScriptHook = hook; 1.599 + rt->debugHooks.newScriptHookData = callerdata; 1.600 +} 1.601 + 1.602 +JS_PUBLIC_API(void) 1.603 +JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, 1.604 + void *callerdata) 1.605 +{ 1.606 + rt->debugHooks.destroyScriptHook = hook; 1.607 + rt->debugHooks.destroyScriptHookData = callerdata; 1.608 +} 1.609 + 1.610 +/***************************************************************************/ 1.611 + 1.612 +/* This all should be reworked to avoid requiring JSScopeProperty types. */ 1.613 + 1.614 +static bool 1.615 +GetPropertyDesc(JSContext *cx, JSObject *obj_, HandleShape shape, JSPropertyDesc *pd) 1.616 +{ 1.617 + assertSameCompartment(cx, obj_); 1.618 + pd->id = IdToValue(shape->propid()); 1.619 + 1.620 + RootedObject obj(cx, obj_); 1.621 + 1.622 + bool wasThrowing = cx->isExceptionPending(); 1.623 + RootedValue lastException(cx, UndefinedValue()); 1.624 + if (wasThrowing) { 1.625 + if (!cx->getPendingException(&lastException)) 1.626 + return false; 1.627 + } 1.628 + cx->clearPendingException(); 1.629 + 1.630 + Rooted<jsid> id(cx, shape->propid()); 1.631 + RootedValue value(cx); 1.632 + if (!baseops::GetProperty(cx, obj, id, &value)) { 1.633 + if (!cx->isExceptionPending()) { 1.634 + pd->flags = JSPD_ERROR; 1.635 + pd->value = JSVAL_VOID; 1.636 + } else { 1.637 + pd->flags = JSPD_EXCEPTION; 1.638 + if (!cx->getPendingException(&value)) 1.639 + return false; 1.640 + pd->value = value; 1.641 + } 1.642 + } else { 1.643 + pd->flags = 0; 1.644 + pd->value = value; 1.645 + } 1.646 + 1.647 + if (wasThrowing) 1.648 + cx->setPendingException(lastException); 1.649 + 1.650 + pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0) 1.651 + | (!shape->writable() ? JSPD_READONLY : 0) 1.652 + | (!shape->configurable() ? JSPD_PERMANENT : 0); 1.653 + pd->spare = 0; 1.654 + pd->alias = JSVAL_VOID; 1.655 + 1.656 + return true; 1.657 +} 1.658 + 1.659 +JS_PUBLIC_API(bool) 1.660 +JS_GetPropertyDescArray(JSContext *cx, JS::HandleObject obj, JSPropertyDescArray *pda) 1.661 +{ 1.662 + assertSameCompartment(cx, obj); 1.663 + uint32_t i = 0; 1.664 + JSPropertyDesc *pd = nullptr; 1.665 + 1.666 + if (obj->is<DebugScopeObject>()) { 1.667 + AutoIdVector props(cx); 1.668 + if (!Proxy::enumerate(cx, obj, props)) 1.669 + return false; 1.670 + 1.671 + pd = cx->pod_calloc<JSPropertyDesc>(props.length()); 1.672 + if (!pd) 1.673 + return false; 1.674 + 1.675 + for (i = 0; i < props.length(); ++i) { 1.676 + pd[i].id = JSVAL_NULL; 1.677 + pd[i].value = JSVAL_NULL; 1.678 + if (!AddValueRoot(cx, &pd[i].id, nullptr)) 1.679 + goto bad; 1.680 + pd[i].id = IdToValue(props[i]); 1.681 + if (!AddValueRoot(cx, &pd[i].value, nullptr)) 1.682 + goto bad; 1.683 + if (!Proxy::get(cx, obj, obj, props.handleAt(i), MutableHandleValue::fromMarkedLocation(&pd[i].value))) 1.684 + goto bad; 1.685 + } 1.686 + 1.687 + pda->length = props.length(); 1.688 + pda->array = pd; 1.689 + return true; 1.690 + } 1.691 + 1.692 + const Class *clasp; 1.693 + clasp = obj->getClass(); 1.694 + if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { 1.695 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.696 + JSMSG_CANT_DESCRIBE_PROPS, clasp->name); 1.697 + return false; 1.698 + } 1.699 + if (!clasp->enumerate(cx, obj)) 1.700 + return false; 1.701 + 1.702 + /* Return an empty pda early if obj has no own properties. */ 1.703 + if (obj->nativeEmpty()) { 1.704 + pda->length = 0; 1.705 + pda->array = nullptr; 1.706 + return true; 1.707 + } 1.708 + 1.709 + pd = cx->pod_malloc<JSPropertyDesc>(obj->propertyCount()); 1.710 + if (!pd) 1.711 + return false; 1.712 + 1.713 + { 1.714 + Shape::Range<CanGC> r(cx, obj->lastProperty()); 1.715 + RootedShape shape(cx); 1.716 + for (; !r.empty(); r.popFront()) { 1.717 + pd[i].id = JSVAL_NULL; 1.718 + pd[i].value = JSVAL_NULL; 1.719 + pd[i].alias = JSVAL_NULL; 1.720 + if (!AddValueRoot(cx, &pd[i].id, nullptr)) 1.721 + goto bad; 1.722 + if (!AddValueRoot(cx, &pd[i].value, nullptr)) 1.723 + goto bad; 1.724 + shape = const_cast<Shape *>(&r.front()); 1.725 + if (!GetPropertyDesc(cx, obj, shape, &pd[i])) 1.726 + goto bad; 1.727 + if ((pd[i].flags & JSPD_ALIAS) && !AddValueRoot(cx, &pd[i].alias, nullptr)) 1.728 + goto bad; 1.729 + if (++i == obj->propertyCount()) 1.730 + break; 1.731 + } 1.732 + } 1.733 + 1.734 + pda->length = i; 1.735 + pda->array = pd; 1.736 + return true; 1.737 + 1.738 +bad: 1.739 + pda->length = i + 1; 1.740 + pda->array = pd; 1.741 + JS_PutPropertyDescArray(cx, pda); 1.742 + return false; 1.743 +} 1.744 + 1.745 +JS_PUBLIC_API(void) 1.746 +JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda) 1.747 +{ 1.748 + JSPropertyDesc *pd; 1.749 + uint32_t i; 1.750 + 1.751 + pd = pda->array; 1.752 + for (i = 0; i < pda->length; i++) { 1.753 + RemoveRoot(cx->runtime(), &pd[i].id); 1.754 + RemoveRoot(cx->runtime(), &pd[i].value); 1.755 + if (pd[i].flags & JSPD_ALIAS) 1.756 + RemoveRoot(cx->runtime(), &pd[i].alias); 1.757 + } 1.758 + js_free(pd); 1.759 + pda->array = nullptr; 1.760 + pda->length = 0; 1.761 +} 1.762 + 1.763 +/************************************************************************/ 1.764 + 1.765 +JS_PUBLIC_API(bool) 1.766 +JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler handler, void *closure) 1.767 +{ 1.768 + rt->debugHooks.debuggerHandler = handler; 1.769 + rt->debugHooks.debuggerHandlerData = closure; 1.770 + return true; 1.771 +} 1.772 + 1.773 +JS_PUBLIC_API(bool) 1.774 +JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure) 1.775 +{ 1.776 + rt->debugHooks.sourceHandler = handler; 1.777 + rt->debugHooks.sourceHandlerData = closure; 1.778 + return true; 1.779 +} 1.780 + 1.781 +JS_PUBLIC_API(bool) 1.782 +JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) 1.783 +{ 1.784 + rt->debugHooks.executeHook = hook; 1.785 + rt->debugHooks.executeHookData = closure; 1.786 + return true; 1.787 +} 1.788 + 1.789 +JS_PUBLIC_API(bool) 1.790 +JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) 1.791 +{ 1.792 + rt->debugHooks.callHook = hook; 1.793 + rt->debugHooks.callHookData = closure; 1.794 + return true; 1.795 +} 1.796 + 1.797 +JS_PUBLIC_API(bool) 1.798 +JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure) 1.799 +{ 1.800 + rt->debugHooks.throwHook = hook; 1.801 + rt->debugHooks.throwHookData = closure; 1.802 + return true; 1.803 +} 1.804 + 1.805 +JS_PUBLIC_API(bool) 1.806 +JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure) 1.807 +{ 1.808 + rt->debugHooks.debugErrorHook = hook; 1.809 + rt->debugHooks.debugErrorHookData = closure; 1.810 + return true; 1.811 +} 1.812 + 1.813 +/************************************************************************/ 1.814 + 1.815 +JS_PUBLIC_API(const JSDebugHooks *) 1.816 +JS_GetGlobalDebugHooks(JSRuntime *rt) 1.817 +{ 1.818 + return &rt->debugHooks; 1.819 +} 1.820 + 1.821 +/************************************************************************/ 1.822 + 1.823 +extern JS_PUBLIC_API(void) 1.824 +JS_DumpPCCounts(JSContext *cx, HandleScript script) 1.825 +{ 1.826 + JS_ASSERT(script->hasScriptCounts()); 1.827 + 1.828 + Sprinter sprinter(cx); 1.829 + if (!sprinter.init()) 1.830 + return; 1.831 + 1.832 + fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename(), (int) script->lineno()); 1.833 + js_DumpPCCounts(cx, script, &sprinter); 1.834 + fputs(sprinter.string(), stdout); 1.835 + fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename(), (int) script->lineno()); 1.836 +} 1.837 + 1.838 +JS_PUBLIC_API(void) 1.839 +JS_DumpCompartmentPCCounts(JSContext *cx) 1.840 +{ 1.841 + for (CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { 1.842 + RootedScript script(cx, i.get<JSScript>()); 1.843 + if (script->compartment() != cx->compartment()) 1.844 + continue; 1.845 + 1.846 + if (script->hasScriptCounts()) 1.847 + JS_DumpPCCounts(cx, script); 1.848 + } 1.849 +} 1.850 + 1.851 +JS_FRIEND_API(bool) 1.852 +js::CanCallContextDebugHandler(JSContext *cx) 1.853 +{ 1.854 + return !!cx->runtime()->debugHooks.debuggerHandler; 1.855 +} 1.856 + 1.857 +static JSTrapStatus 1.858 +CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *rval) 1.859 +{ 1.860 + if (!cx->runtime()->debugHooks.debuggerHandler) 1.861 + return JSTRAP_RETURN; 1.862 + 1.863 + return cx->runtime()->debugHooks.debuggerHandler(cx, script, bc, rval, 1.864 + cx->runtime()->debugHooks.debuggerHandlerData); 1.865 +} 1.866 + 1.867 +JS_FRIEND_API(bool) 1.868 +js_CallContextDebugHandler(JSContext *cx) 1.869 +{ 1.870 + NonBuiltinFrameIter iter(cx); 1.871 + 1.872 + // If there is no script to debug, then abort execution even if the user 1.873 + // clicks 'Debug' in the slow-script dialog. 1.874 + if (!iter.hasScript()) 1.875 + return false; 1.876 + 1.877 + // Even if script was running during the operation callback, it's possible 1.878 + // it was a builtin which 'iter' will have skipped over. 1.879 + if (iter.done()) 1.880 + return false; 1.881 + 1.882 + RootedValue rval(cx); 1.883 + RootedScript script(cx, iter.script()); 1.884 + switch (CallContextDebugHandler(cx, script, iter.pc(), rval.address())) { 1.885 + case JSTRAP_ERROR: 1.886 + JS_ClearPendingException(cx); 1.887 + return false; 1.888 + case JSTRAP_THROW: 1.889 + JS_SetPendingException(cx, rval); 1.890 + return false; 1.891 + case JSTRAP_RETURN: 1.892 + case JSTRAP_CONTINUE: 1.893 + default: 1.894 + return true; 1.895 + } 1.896 +} 1.897 + 1.898 +/* 1.899 + * A contructor that crates a FrameDescription from a ScriptFrameIter, to avoid 1.900 + * constructing a FrameDescription on the stack just to append it to a vector. 1.901 + * FrameDescription contains Heap<T> fields that should not live on the stack. 1.902 + */ 1.903 +JS::FrameDescription::FrameDescription(const ScriptFrameIter& iter) 1.904 + : script_(iter.script()), 1.905 + funDisplayName_(nullptr), 1.906 + pc_(iter.pc()), 1.907 + linenoComputed(false) 1.908 +{ 1.909 + if (JSFunction *fun = iter.maybeCallee()) 1.910 + funDisplayName_ = fun->displayAtom(); 1.911 +} 1.912 + 1.913 +JS_PUBLIC_API(JS::StackDescription *) 1.914 +JS::DescribeStack(JSContext *cx, unsigned maxFrames) 1.915 +{ 1.916 + Vector<FrameDescription> frames(cx); 1.917 + 1.918 + NonBuiltinScriptFrameIter i(cx, ScriptFrameIter::ALL_CONTEXTS, 1.919 + ScriptFrameIter::GO_THROUGH_SAVED, 1.920 + cx->compartment()->principals); 1.921 + for ( ; !i.done(); ++i) { 1.922 + if (!frames.append(i)) 1.923 + return nullptr; 1.924 + if (frames.length() == maxFrames) 1.925 + break; 1.926 + } 1.927 + 1.928 + JS::StackDescription *desc = js_new<JS::StackDescription>(); 1.929 + if (!desc) 1.930 + return nullptr; 1.931 + 1.932 + desc->nframes = frames.length(); 1.933 + desc->frames = frames.extractRawBuffer(); 1.934 + return desc; 1.935 +} 1.936 + 1.937 +JS_PUBLIC_API(void) 1.938 +JS::FreeStackDescription(JSContext *cx, JS::StackDescription *desc) 1.939 +{ 1.940 + for (size_t i = 0; i < desc->nframes; ++i) 1.941 + desc->frames[i].~FrameDescription(); 1.942 + js_free(desc->frames); 1.943 + js_delete(desc); 1.944 +} 1.945 + 1.946 +namespace { 1.947 + 1.948 +class AutoPropertyDescArray 1.949 +{ 1.950 + JSContext *cx_; 1.951 + JSPropertyDescArray descArray_; 1.952 + 1.953 + public: 1.954 + AutoPropertyDescArray(JSContext *cx) 1.955 + : cx_(cx) 1.956 + { 1.957 + PodZero(&descArray_); 1.958 + } 1.959 + ~AutoPropertyDescArray() 1.960 + { 1.961 + if (descArray_.array) 1.962 + JS_PutPropertyDescArray(cx_, &descArray_); 1.963 + } 1.964 + 1.965 + void fetch(JS::HandleObject obj) { 1.966 + JS_ASSERT(!descArray_.array); 1.967 + if (!JS_GetPropertyDescArray(cx_, obj, &descArray_)) 1.968 + descArray_.array = nullptr; 1.969 + } 1.970 + 1.971 + JSPropertyDescArray * operator ->() { 1.972 + return &descArray_; 1.973 + } 1.974 +}; 1.975 + 1.976 +} /* anonymous namespace */ 1.977 + 1.978 +static const char * 1.979 +FormatValue(JSContext *cx, const Value &vArg, JSAutoByteString &bytes) 1.980 +{ 1.981 + RootedValue v(cx, vArg); 1.982 + 1.983 + /* 1.984 + * We could use Maybe<AutoCompartment> here, but G++ can't quite follow 1.985 + * that, and warns about uninitialized members being used in the 1.986 + * destructor. 1.987 + */ 1.988 + RootedString str(cx); 1.989 + if (v.isObject()) { 1.990 + AutoCompartment ac(cx, &v.toObject()); 1.991 + str = ToString<CanGC>(cx, v); 1.992 + } else { 1.993 + str = ToString<CanGC>(cx, v); 1.994 + } 1.995 + 1.996 + if (!str) 1.997 + return nullptr; 1.998 + const char *buf = bytes.encodeLatin1(cx, str); 1.999 + if (!buf) 1.1000 + return nullptr; 1.1001 + const char *found = strstr(buf, "function "); 1.1002 + if (found && (found - buf <= 2)) 1.1003 + return "[function]"; 1.1004 + return buf; 1.1005 +} 1.1006 + 1.1007 +static char * 1.1008 +FormatFrame(JSContext *cx, const NonBuiltinScriptFrameIter &iter, char *buf, int num, 1.1009 + bool showArgs, bool showLocals, bool showThisProps) 1.1010 +{ 1.1011 + JS_ASSERT(!cx->isExceptionPending()); 1.1012 + RootedScript script(cx, iter.script()); 1.1013 + jsbytecode* pc = iter.pc(); 1.1014 + 1.1015 + RootedObject scopeChain(cx, iter.scopeChain()); 1.1016 + JSAutoCompartment ac(cx, scopeChain); 1.1017 + 1.1018 + const char *filename = script->filename(); 1.1019 + unsigned lineno = PCToLineNumber(script, pc); 1.1020 + RootedFunction fun(cx, iter.maybeCallee()); 1.1021 + RootedString funname(cx); 1.1022 + if (fun) 1.1023 + funname = fun->atom(); 1.1024 + 1.1025 + RootedValue thisVal(cx); 1.1026 + AutoPropertyDescArray thisProps(cx); 1.1027 + if (iter.computeThis(cx)) { 1.1028 + thisVal = iter.computedThisValue(); 1.1029 + if (showThisProps && !thisVal.isPrimitive()) { 1.1030 + RootedObject thisObj(cx, &thisVal.toObject()); 1.1031 + thisProps.fetch(thisObj); 1.1032 + } 1.1033 + } 1.1034 + 1.1035 + // print the frame number and function name 1.1036 + if (funname) { 1.1037 + JSAutoByteString funbytes; 1.1038 + buf = JS_sprintf_append(buf, "%d %s(", num, funbytes.encodeLatin1(cx, funname)); 1.1039 + } else if (fun) { 1.1040 + buf = JS_sprintf_append(buf, "%d anonymous(", num); 1.1041 + } else { 1.1042 + buf = JS_sprintf_append(buf, "%d <TOP LEVEL>", num); 1.1043 + } 1.1044 + if (!buf) 1.1045 + return buf; 1.1046 + 1.1047 + if (showArgs && iter.hasArgs()) { 1.1048 + BindingVector bindings(cx); 1.1049 + if (fun && fun->isInterpreted()) { 1.1050 + if (!FillBindingVector(script, &bindings)) 1.1051 + return buf; 1.1052 + } 1.1053 + 1.1054 + 1.1055 + bool first = true; 1.1056 + for (unsigned i = 0; i < iter.numActualArgs(); i++) { 1.1057 + RootedValue arg(cx); 1.1058 + if (i < iter.numFormalArgs() && script->formalIsAliased(i)) { 1.1059 + for (AliasedFormalIter fi(script); ; fi++) { 1.1060 + if (fi.frameIndex() == i) { 1.1061 + arg = iter.callObj().aliasedVar(fi); 1.1062 + break; 1.1063 + } 1.1064 + } 1.1065 + } else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) { 1.1066 + arg = iter.argsObj().arg(i); 1.1067 + } else { 1.1068 + arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING); 1.1069 + } 1.1070 + 1.1071 + JSAutoByteString valueBytes; 1.1072 + const char *value = FormatValue(cx, arg, valueBytes); 1.1073 + 1.1074 + JSAutoByteString nameBytes; 1.1075 + const char *name = nullptr; 1.1076 + 1.1077 + if (i < bindings.length()) { 1.1078 + name = nameBytes.encodeLatin1(cx, bindings[i].name()); 1.1079 + if (!buf) 1.1080 + return nullptr; 1.1081 + } 1.1082 + 1.1083 + if (value) { 1.1084 + buf = JS_sprintf_append(buf, "%s%s%s%s%s%s", 1.1085 + !first ? ", " : "", 1.1086 + name ? name :"", 1.1087 + name ? " = " : "", 1.1088 + arg.isString() ? "\"" : "", 1.1089 + value ? value : "?unknown?", 1.1090 + arg.isString() ? "\"" : ""); 1.1091 + if (!buf) 1.1092 + return buf; 1.1093 + 1.1094 + first = false; 1.1095 + } else { 1.1096 + buf = JS_sprintf_append(buf, " <Failed to get argument while inspecting stack frame>\n"); 1.1097 + if (!buf) 1.1098 + return buf; 1.1099 + cx->clearPendingException(); 1.1100 + 1.1101 + } 1.1102 + } 1.1103 + } 1.1104 + 1.1105 + // print filename and line number 1.1106 + buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n", 1.1107 + fun ? ")" : "", 1.1108 + filename ? filename : "<unknown>", 1.1109 + lineno); 1.1110 + if (!buf) 1.1111 + return buf; 1.1112 + 1.1113 + 1.1114 + // Note: Right now we don't dump the local variables anymore, because 1.1115 + // that is hard to support across all the JITs etc. 1.1116 + 1.1117 + // print the value of 'this' 1.1118 + if (showLocals) { 1.1119 + if (!thisVal.isUndefined()) { 1.1120 + JSAutoByteString thisValBytes; 1.1121 + RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal)); 1.1122 + const char *str = nullptr; 1.1123 + if (thisValStr && 1.1124 + (str = thisValBytes.encodeLatin1(cx, thisValStr))) 1.1125 + { 1.1126 + buf = JS_sprintf_append(buf, " this = %s\n", str); 1.1127 + if (!buf) 1.1128 + return buf; 1.1129 + } else { 1.1130 + buf = JS_sprintf_append(buf, " <failed to get 'this' value>\n"); 1.1131 + cx->clearPendingException(); 1.1132 + } 1.1133 + } 1.1134 + } 1.1135 + 1.1136 + // print the properties of 'this', if it is an object 1.1137 + if (showThisProps && thisProps->array) { 1.1138 + for (uint32_t i = 0; i < thisProps->length; i++) { 1.1139 + JSPropertyDesc* desc = &thisProps->array[i]; 1.1140 + if (desc->flags & JSPD_ENUMERATE) { 1.1141 + JSAutoByteString nameBytes; 1.1142 + JSAutoByteString valueBytes; 1.1143 + const char *name = FormatValue(cx, desc->id, nameBytes); 1.1144 + const char *value = FormatValue(cx, desc->value, valueBytes); 1.1145 + if (name && value) { 1.1146 + buf = JS_sprintf_append(buf, " this.%s = %s%s%s\n", 1.1147 + name, 1.1148 + desc->value.isString() ? "\"" : "", 1.1149 + value, 1.1150 + desc->value.isString() ? "\"" : ""); 1.1151 + if (!buf) 1.1152 + return buf; 1.1153 + } else { 1.1154 + buf = JS_sprintf_append(buf, " <Failed to format values while inspecting stack frame>\n"); 1.1155 + cx->clearPendingException(); 1.1156 + } 1.1157 + } 1.1158 + } 1.1159 + } 1.1160 + 1.1161 + JS_ASSERT(!cx->isExceptionPending()); 1.1162 + return buf; 1.1163 +} 1.1164 + 1.1165 +JS_PUBLIC_API(char *) 1.1166 +JS::FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool showThisProps) 1.1167 +{ 1.1168 + int num = 0; 1.1169 + 1.1170 + for (NonBuiltinScriptFrameIter i(cx); !i.done(); ++i) { 1.1171 + buf = FormatFrame(cx, i, buf, num, showArgs, showLocals, showThisProps); 1.1172 + num++; 1.1173 + } 1.1174 + 1.1175 + if (!num) 1.1176 + buf = JS_sprintf_append(buf, "JavaScript stack is empty\n"); 1.1177 + 1.1178 + return buf; 1.1179 +} 1.1180 + 1.1181 +JSAbstractFramePtr::JSAbstractFramePtr(void *raw, jsbytecode *pc) 1.1182 + : ptr_(uintptr_t(raw)), pc_(pc) 1.1183 +{ } 1.1184 + 1.1185 +JSObject * 1.1186 +JSAbstractFramePtr::scopeChain(JSContext *cx) 1.1187 +{ 1.1188 + AbstractFramePtr frame(*this); 1.1189 + RootedObject scopeChain(cx, frame.scopeChain()); 1.1190 + AutoCompartment ac(cx, scopeChain); 1.1191 + return GetDebugScopeForFrame(cx, frame, pc()); 1.1192 +} 1.1193 + 1.1194 +JSObject * 1.1195 +JSAbstractFramePtr::callObject(JSContext *cx) 1.1196 +{ 1.1197 + AbstractFramePtr frame(*this); 1.1198 + if (!frame.isFunctionFrame()) 1.1199 + return nullptr; 1.1200 + 1.1201 + JSObject *o = GetDebugScopeForFrame(cx, frame, pc()); 1.1202 + 1.1203 + /* 1.1204 + * Given that fp is a function frame and GetDebugScopeForFrame always fills 1.1205 + * in missing scopes, we can expect to find fp's CallObject on 'o'. Note: 1.1206 + * - GetDebugScopeForFrame wraps every ScopeObject (missing or not) with 1.1207 + * a DebugScopeObject proxy. 1.1208 + * - If fp is an eval-in-function, then fp has no callobj of its own and 1.1209 + * JS_GetFrameCallObject will return the innermost function's callobj. 1.1210 + */ 1.1211 + while (o) { 1.1212 + ScopeObject &scope = o->as<DebugScopeObject>().scope(); 1.1213 + if (scope.is<CallObject>()) 1.1214 + return o; 1.1215 + o = o->enclosingScope(); 1.1216 + } 1.1217 + return nullptr; 1.1218 +} 1.1219 + 1.1220 +JSFunction * 1.1221 +JSAbstractFramePtr::maybeFun() 1.1222 +{ 1.1223 + AbstractFramePtr frame(*this); 1.1224 + return frame.maybeFun(); 1.1225 +} 1.1226 + 1.1227 +JSScript * 1.1228 +JSAbstractFramePtr::script() 1.1229 +{ 1.1230 + AbstractFramePtr frame(*this); 1.1231 + return frame.script(); 1.1232 +} 1.1233 + 1.1234 +bool 1.1235 +JSAbstractFramePtr::getThisValue(JSContext *cx, MutableHandleValue thisv) 1.1236 +{ 1.1237 + AbstractFramePtr frame(*this); 1.1238 + 1.1239 + RootedObject scopeChain(cx, frame.scopeChain()); 1.1240 + js::AutoCompartment ac(cx, scopeChain); 1.1241 + if (!ComputeThis(cx, frame)) 1.1242 + return false; 1.1243 + 1.1244 + thisv.set(frame.thisValue()); 1.1245 + return true; 1.1246 +} 1.1247 + 1.1248 +bool 1.1249 +JSAbstractFramePtr::isDebuggerFrame() 1.1250 +{ 1.1251 + AbstractFramePtr frame(*this); 1.1252 + return frame.isDebuggerFrame(); 1.1253 +} 1.1254 + 1.1255 +bool 1.1256 +JSAbstractFramePtr::evaluateInStackFrame(JSContext *cx, 1.1257 + const char *bytes, unsigned length, 1.1258 + const char *filename, unsigned lineno, 1.1259 + MutableHandleValue rval) 1.1260 +{ 1.1261 + if (!CheckDebugMode(cx)) 1.1262 + return false; 1.1263 + 1.1264 + size_t len = length; 1.1265 + jschar *chars = InflateString(cx, bytes, &len); 1.1266 + if (!chars) 1.1267 + return false; 1.1268 + length = (unsigned) len; 1.1269 + 1.1270 + bool ok = evaluateUCInStackFrame(cx, chars, length, filename, lineno, rval); 1.1271 + js_free(chars); 1.1272 + 1.1273 + return ok; 1.1274 +} 1.1275 + 1.1276 +bool 1.1277 +JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx, 1.1278 + const jschar *chars, unsigned length, 1.1279 + const char *filename, unsigned lineno, 1.1280 + MutableHandleValue rval) 1.1281 +{ 1.1282 + if (!CheckDebugMode(cx)) 1.1283 + return false; 1.1284 + 1.1285 + RootedObject scope(cx, scopeChain(cx)); 1.1286 + Rooted<Env*> env(cx, scope); 1.1287 + if (!env) 1.1288 + return false; 1.1289 + 1.1290 + AbstractFramePtr frame(*this); 1.1291 + if (!ComputeThis(cx, frame)) 1.1292 + return false; 1.1293 + RootedValue thisv(cx, frame.thisValue()); 1.1294 + 1.1295 + js::AutoCompartment ac(cx, env); 1.1296 + return EvaluateInEnv(cx, env, thisv, frame, ConstTwoByteChars(chars, length), length, 1.1297 + filename, lineno, rval); 1.1298 +} 1.1299 + 1.1300 +JSBrokenFrameIterator::JSBrokenFrameIterator(JSContext *cx) 1.1301 +{ 1.1302 + // Show all frames on the stack whose principal is subsumed by the current principal. 1.1303 + NonBuiltinScriptFrameIter iter(cx, 1.1304 + ScriptFrameIter::ALL_CONTEXTS, 1.1305 + ScriptFrameIter::GO_THROUGH_SAVED, 1.1306 + cx->compartment()->principals); 1.1307 + data_ = iter.copyData(); 1.1308 +} 1.1309 + 1.1310 +JSBrokenFrameIterator::~JSBrokenFrameIterator() 1.1311 +{ 1.1312 + js_free((ScriptFrameIter::Data *)data_); 1.1313 +} 1.1314 + 1.1315 +bool 1.1316 +JSBrokenFrameIterator::done() const 1.1317 +{ 1.1318 + NonBuiltinScriptFrameIter iter(*(ScriptFrameIter::Data *)data_); 1.1319 + return iter.done(); 1.1320 +} 1.1321 + 1.1322 +JSBrokenFrameIterator & 1.1323 +JSBrokenFrameIterator::operator++() 1.1324 +{ 1.1325 + ScriptFrameIter::Data *data = (ScriptFrameIter::Data *)data_; 1.1326 + NonBuiltinScriptFrameIter iter(*data); 1.1327 + ++iter; 1.1328 + *data = iter.data_; 1.1329 + return *this; 1.1330 +} 1.1331 + 1.1332 +JSAbstractFramePtr 1.1333 +JSBrokenFrameIterator::abstractFramePtr() const 1.1334 +{ 1.1335 + NonBuiltinScriptFrameIter iter(*(ScriptFrameIter::Data *)data_); 1.1336 + return JSAbstractFramePtr(iter.abstractFramePtr().raw(), iter.pc()); 1.1337 +} 1.1338 + 1.1339 +jsbytecode * 1.1340 +JSBrokenFrameIterator::pc() const 1.1341 +{ 1.1342 + NonBuiltinScriptFrameIter iter(*(ScriptFrameIter::Data *)data_); 1.1343 + return iter.pc(); 1.1344 +} 1.1345 + 1.1346 +bool 1.1347 +JSBrokenFrameIterator::isConstructing() const 1.1348 +{ 1.1349 + NonBuiltinScriptFrameIter iter(*(ScriptFrameIter::Data *)data_); 1.1350 + return iter.isConstructing(); 1.1351 +}