JsrtDiag.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "JsrtPch.h"
  6. #ifdef ENABLE_SCRIPT_DEBUGGING
  7. #include "JsrtInternal.h"
  8. #include "RuntimeDebugPch.h"
  9. #include "ThreadContextTlsEntry.h"
  10. #include "JsrtDebugUtils.h"
  11. #include "Codex/Utf8Helper.h"
  12. #define VALIDATE_IS_DEBUGGING(jsrtDebugManager) \
  13. if (jsrtDebugManager == nullptr || !jsrtDebugManager->IsDebugEventCallbackSet()) \
  14. { \
  15. return JsErrorDiagNotInDebugMode; \
  16. }
  17. #define VALIDATE_RUNTIME_IS_AT_BREAK(runtime) \
  18. if (runtime->GetThreadContext()->GetDebugManager() == nullptr || !runtime->GetThreadContext()->GetDebugManager()->IsAtDispatchHalt()) \
  19. { \
  20. return JsErrorDiagNotAtBreak; \
  21. }
  22. #define VALIDATE_RUNTIME_STATE_FOR_START_STOP_DEBUGGING(threadContext) \
  23. if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress()) \
  24. { \
  25. return JsErrorHeapEnumInProgress; \
  26. } \
  27. else if (threadContext->IsInThreadServiceCallback()) \
  28. { \
  29. return JsErrorInThreadServiceCallback; \
  30. } \
  31. else if (threadContext->IsInScript()) \
  32. { \
  33. return JsErrorRuntimeInUse; \
  34. } \
  35. ThreadContextScope scope(threadContext); \
  36. if (!scope.IsValid()) \
  37. { \
  38. return JsErrorWrongThread; \
  39. }
  40. #endif
  41. CHAKRA_API JsDiagStartDebugging(
  42. _In_ JsRuntimeHandle runtimeHandle,
  43. _In_ JsDiagDebugEventCallback debugEventCallback,
  44. _In_opt_ void* callbackState)
  45. {
  46. #ifndef ENABLE_SCRIPT_DEBUGGING
  47. return JsErrorCategoryUsage;
  48. #else
  49. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  50. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  51. PARAM_NOT_NULL(debugEventCallback);
  52. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  53. ThreadContext * threadContext = runtime->GetThreadContext();
  54. VALIDATE_RUNTIME_STATE_FOR_START_STOP_DEBUGGING(threadContext);
  55. if (runtime->GetJsrtDebugManager() != nullptr && runtime->GetJsrtDebugManager()->IsDebugEventCallbackSet())
  56. {
  57. return JsErrorDiagAlreadyInDebugMode;
  58. }
  59. // Create the debug object to save callback function and data
  60. runtime->EnsureJsrtDebugManager();
  61. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  62. jsrtDebugManager->SetDebugEventCallback(debugEventCallback, callbackState);
  63. if (threadContext->GetDebugManager() != nullptr)
  64. {
  65. threadContext->GetDebugManager()->SetLocalsDisplayFlags(Js::DebugManager::LocalsDisplayFlags::LocalsDisplayFlags_NoGroupMethods);
  66. }
  67. for (Js::ScriptContext *scriptContext = runtime->GetThreadContext()->GetScriptContextList();
  68. scriptContext != nullptr && !scriptContext->IsClosed();
  69. scriptContext = scriptContext->next)
  70. {
  71. Assert(!scriptContext->IsScriptContextInDebugMode());
  72. Js::DebugContext* debugContext = scriptContext->GetDebugContext();
  73. if (debugContext->GetHostDebugContext() == nullptr)
  74. {
  75. debugContext->SetHostDebugContext(jsrtDebugManager);
  76. }
  77. HRESULT hr;
  78. if (FAILED(hr = scriptContext->OnDebuggerAttached()))
  79. {
  80. Debugger_AttachDetach_unrecoverable_error(hr); // Inconsistent state, we can't continue from here
  81. return JsErrorFatal;
  82. }
  83. // ScriptContext might get closed in OnDebuggerAttached
  84. if (!scriptContext->IsClosed())
  85. {
  86. Js::ProbeContainer* probeContainer = debugContext->GetProbeContainer();
  87. probeContainer->InitializeInlineBreakEngine(jsrtDebugManager);
  88. probeContainer->InitializeDebuggerScriptOptionCallback(jsrtDebugManager);
  89. }
  90. }
  91. return JsNoError;
  92. });
  93. #endif
  94. }
  95. CHAKRA_API JsDiagStopDebugging(
  96. _In_ JsRuntimeHandle runtimeHandle,
  97. _Out_opt_ void** callbackState)
  98. {
  99. #ifndef ENABLE_SCRIPT_DEBUGGING
  100. return JsErrorCategoryUsage;
  101. #else
  102. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  103. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  104. if (callbackState != nullptr)
  105. {
  106. *callbackState = nullptr;
  107. }
  108. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  109. ThreadContext * threadContext = runtime->GetThreadContext();
  110. VALIDATE_RUNTIME_STATE_FOR_START_STOP_DEBUGGING(threadContext);
  111. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  112. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  113. for (Js::ScriptContext *scriptContext = runtime->GetThreadContext()->GetScriptContextList();
  114. scriptContext != nullptr && !scriptContext->IsClosed();
  115. scriptContext = scriptContext->next)
  116. {
  117. Assert(scriptContext->IsScriptContextInDebugMode());
  118. HRESULT hr;
  119. if (FAILED(hr = scriptContext->OnDebuggerDetached()))
  120. {
  121. Debugger_AttachDetach_unrecoverable_error(hr); // Inconsistent state, we can't continue from here
  122. return JsErrorFatal;
  123. }
  124. Js::DebugContext* debugContext = scriptContext->GetDebugContext();
  125. Js::ProbeContainer* probeContainer = debugContext->GetProbeContainer();
  126. probeContainer->UninstallInlineBreakpointProbe(nullptr);
  127. probeContainer->UninstallDebuggerScriptOptionCallback();
  128. jsrtDebugManager->ClearBreakpointDebugDocumentDictionary();
  129. }
  130. void* cbState = jsrtDebugManager->GetAndClearCallbackState();
  131. if (callbackState != nullptr)
  132. {
  133. *callbackState = cbState;
  134. }
  135. return JsNoError;
  136. });
  137. #endif
  138. }
  139. CHAKRA_API JsDiagGetScripts(
  140. _Out_ JsValueRef *scriptsArray)
  141. {
  142. #ifndef ENABLE_SCRIPT_DEBUGGING
  143. return JsErrorCategoryUsage;
  144. #else
  145. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  146. PARAM_NOT_NULL(scriptsArray);
  147. *scriptsArray = JS_INVALID_REFERENCE;
  148. JsrtContext *currentContext = JsrtContext::GetCurrent();
  149. JsrtDebugManager* jsrtDebugManager = currentContext->GetRuntime()->GetJsrtDebugManager();
  150. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  151. Js::JavascriptArray* scripts = jsrtDebugManager->GetScripts(scriptContext);
  152. if (scripts != nullptr)
  153. {
  154. *scriptsArray = scripts;
  155. return JsNoError;
  156. }
  157. return JsErrorDiagUnableToPerformAction;
  158. });
  159. #endif
  160. }
  161. CHAKRA_API JsDiagGetSource(
  162. _In_ unsigned int scriptId,
  163. _Out_ JsValueRef *source)
  164. {
  165. #ifndef ENABLE_SCRIPT_DEBUGGING
  166. return JsErrorCategoryUsage;
  167. #else
  168. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  169. PARAM_NOT_NULL(source);
  170. *source = JS_INVALID_REFERENCE;
  171. JsrtContext *currentContext = JsrtContext::GetCurrent();
  172. JsrtDebugManager* jsrtDebugManager = currentContext->GetRuntime()->GetJsrtDebugManager();
  173. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  174. Js::DynamicObject* sourceObject = jsrtDebugManager->GetSource(scriptContext, scriptId);
  175. if (sourceObject != nullptr)
  176. {
  177. *source = sourceObject;
  178. return JsNoError;
  179. }
  180. return JsErrorInvalidArgument;
  181. });
  182. #endif
  183. }
  184. CHAKRA_API JsDiagRequestAsyncBreak(
  185. _In_ JsRuntimeHandle runtimeHandle)
  186. {
  187. #ifndef ENABLE_SCRIPT_DEBUGGING
  188. return JsErrorCategoryUsage;
  189. #else
  190. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  191. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  192. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  193. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  194. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  195. for (Js::ScriptContext *scriptContext = runtime->GetThreadContext()->GetScriptContextList();
  196. scriptContext != nullptr && !scriptContext->IsClosed();
  197. scriptContext = scriptContext->next)
  198. {
  199. jsrtDebugManager->EnableAsyncBreak(scriptContext);
  200. }
  201. return JsNoError;
  202. });
  203. #endif
  204. }
  205. CHAKRA_API JsDiagGetBreakpoints(
  206. _Out_ JsValueRef *breakpoints)
  207. {
  208. #ifndef ENABLE_SCRIPT_DEBUGGING
  209. return JsErrorCategoryUsage;
  210. #else
  211. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
  212. PARAM_NOT_NULL(breakpoints);
  213. *breakpoints = JS_INVALID_REFERENCE;
  214. JsrtContext* currentContext = JsrtContext::GetCurrent();
  215. JsrtRuntime* runtime = currentContext->GetRuntime();
  216. ThreadContextScope scope(runtime->GetThreadContext());
  217. if (!scope.IsValid())
  218. {
  219. return JsErrorWrongThread;
  220. }
  221. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  222. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  223. Js::JavascriptArray* bpsArray = currentContext->GetScriptContext()->GetLibrary()->CreateArray();
  224. for (Js::ScriptContext* currentScriptContext = runtime->GetThreadContext()->GetScriptContextList();
  225. currentScriptContext != nullptr && !currentScriptContext->IsClosed();
  226. currentScriptContext = currentScriptContext->next)
  227. {
  228. jsrtDebugManager->GetBreakpoints(&bpsArray, currentScriptContext);
  229. }
  230. *breakpoints = bpsArray;
  231. return JsNoError;
  232. });
  233. #endif
  234. }
  235. CHAKRA_API JsDiagSetBreakpoint(
  236. _In_ unsigned int scriptId,
  237. _In_ unsigned int lineNumber,
  238. _In_ unsigned int columnNumber,
  239. _Out_ JsValueRef *breakpoint)
  240. {
  241. #ifndef ENABLE_SCRIPT_DEBUGGING
  242. return JsErrorCategoryUsage;
  243. #else
  244. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
  245. PARAM_NOT_NULL(breakpoint);
  246. *breakpoint = JS_INVALID_REFERENCE;
  247. JsrtContext* currentContext = JsrtContext::GetCurrent();
  248. JsrtRuntime* runtime = currentContext->GetRuntime();
  249. ThreadContextScope scope(runtime->GetThreadContext());
  250. if (!scope.IsValid())
  251. {
  252. return JsErrorWrongThread;
  253. }
  254. VALIDATE_IS_DEBUGGING(runtime->GetJsrtDebugManager());
  255. Js::Utf8SourceInfo* utf8SourceInfo = nullptr;
  256. for (Js::ScriptContext* currentScriptContext = runtime->GetThreadContext()->GetScriptContextList();
  257. currentScriptContext != nullptr && utf8SourceInfo == nullptr && !currentScriptContext->IsClosed();
  258. currentScriptContext = currentScriptContext->next)
  259. {
  260. currentScriptContext->MapScript([&](Js::Utf8SourceInfo* sourceInfo) -> bool
  261. {
  262. if (sourceInfo->GetSourceInfoId() == scriptId)
  263. {
  264. utf8SourceInfo = sourceInfo;
  265. return true;
  266. }
  267. return false;
  268. });
  269. }
  270. if (utf8SourceInfo != nullptr && utf8SourceInfo->HasDebugDocument())
  271. {
  272. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  273. Js::DynamicObject* bpObject = jsrtDebugManager->SetBreakPoint(currentContext->GetScriptContext(), utf8SourceInfo, lineNumber, columnNumber);
  274. if(bpObject != nullptr)
  275. {
  276. *breakpoint = bpObject;
  277. return JsNoError;
  278. }
  279. return JsErrorDiagUnableToPerformAction;
  280. }
  281. return JsErrorDiagObjectNotFound;
  282. });
  283. #endif
  284. }
  285. CHAKRA_API JsDiagRemoveBreakpoint(
  286. _In_ unsigned int breakpointId)
  287. {
  288. #ifndef ENABLE_SCRIPT_DEBUGGING
  289. return JsErrorCategoryUsage;
  290. #else
  291. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
  292. JsrtContext* currentContext = JsrtContext::GetCurrent();
  293. JsrtRuntime* runtime = currentContext->GetRuntime();
  294. ThreadContextScope scope(runtime->GetThreadContext());
  295. if (!scope.IsValid())
  296. {
  297. return JsErrorWrongThread;
  298. }
  299. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  300. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  301. if (!jsrtDebugManager->RemoveBreakpoint(breakpointId))
  302. {
  303. return JsErrorInvalidArgument;
  304. }
  305. return JsNoError;
  306. });
  307. #endif
  308. }
  309. CHAKRA_API JsDiagSetBreakOnException(
  310. _In_ JsRuntimeHandle runtimeHandle,
  311. _In_ JsDiagBreakOnExceptionAttributes exceptionAttributes)
  312. {
  313. #ifndef ENABLE_SCRIPT_DEBUGGING
  314. return JsErrorCategoryUsage;
  315. #else
  316. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  317. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  318. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  319. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  320. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  321. jsrtDebugManager->SetBreakOnException(exceptionAttributes);
  322. return JsNoError;
  323. });
  324. #endif
  325. }
  326. CHAKRA_API JsDiagGetBreakOnException(
  327. _In_ JsRuntimeHandle runtimeHandle,
  328. _Out_ JsDiagBreakOnExceptionAttributes* exceptionAttributes)
  329. {
  330. #ifndef ENABLE_SCRIPT_DEBUGGING
  331. return JsErrorCategoryUsage;
  332. #else
  333. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  334. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  335. PARAM_NOT_NULL(exceptionAttributes);
  336. *exceptionAttributes = JsDiagBreakOnExceptionAttributeNone;
  337. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  338. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  339. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  340. *exceptionAttributes = jsrtDebugManager->GetBreakOnException();
  341. return JsNoError;
  342. });
  343. #endif
  344. }
  345. CHAKRA_API JsDiagSetStepType(
  346. _In_ JsDiagStepType stepType)
  347. {
  348. #ifndef ENABLE_SCRIPT_DEBUGGING
  349. return JsErrorCategoryUsage;
  350. #else
  351. return ContextAPIWrapper_NoRecord<true>([&](Js::ScriptContext * scriptContext) -> JsErrorCode {
  352. JsrtContext *currentContext = JsrtContext::GetCurrent();
  353. JsrtRuntime* runtime = currentContext->GetRuntime();
  354. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  355. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  356. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  357. if (stepType == JsDiagStepTypeStepIn)
  358. {
  359. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_INTO);
  360. }
  361. else if (stepType == JsDiagStepTypeStepOut)
  362. {
  363. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_OUT);
  364. }
  365. else if (stepType == JsDiagStepTypeStepOver)
  366. {
  367. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_OVER);
  368. }
  369. else if (stepType == JsDiagStepTypeStepBack)
  370. {
  371. #if ENABLE_TTD
  372. ThreadContext* threadContext = runtime->GetThreadContext();
  373. if(!threadContext->IsRuntimeInTTDMode())
  374. {
  375. //Don't want to fail hard when user accidentally clicks this so pring message and step forward
  376. fprintf(stderr, "Must be in replay mode to use reverse-step - launch with \"--replay-debug\" flag in Node.");
  377. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_OVER);
  378. }
  379. else
  380. {
  381. threadContext->TTDExecutionInfo->SetPendingTTDStepBackMove();
  382. //don't worry about BP suppression because we are just going to throw after we return
  383. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE);
  384. }
  385. #else
  386. return JsErrorInvalidArgument;
  387. #endif
  388. }
  389. else if (stepType == JsDiagStepTypeReverseContinue)
  390. {
  391. #if ENABLE_TTD
  392. ThreadContext* threadContext = runtime->GetThreadContext();
  393. if(!threadContext->IsRuntimeInTTDMode())
  394. {
  395. //Don't want to fail hard when user accidentally clicks this so pring message and step forward
  396. fprintf(stderr, "Must be in replay mode to use reverse-continue - launch with \"--replay-debug\" flag in Node.");
  397. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE);
  398. }
  399. else
  400. {
  401. threadContext->TTDExecutionInfo->SetPendingTTDReverseContinueMove(JsTTDMoveMode::JsTTDMoveScanIntervalForContinue);
  402. //don't worry about BP suppression because we are just going to throw after we return
  403. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE);
  404. }
  405. #else
  406. return JsErrorInvalidArgument;
  407. #endif
  408. }
  409. else if (stepType == JsDiagStepTypeContinue)
  410. {
  411. jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE);
  412. }
  413. return JsNoError;
  414. });
  415. #endif
  416. }
  417. CHAKRA_API JsTTDDiagWriteLog(_In_reads_(uriLength) const char* uri, _In_ size_t uriLength)
  418. {
  419. #if !ENABLE_TTD
  420. return JsErrorCategoryUsage;
  421. #else
  422. return ContextAPIWrapper_NoRecord<true>([&](Js::ScriptContext * scriptContext) -> JsErrorCode {
  423. if (!scriptContext->GetThreadContext()->IsRuntimeInTTDMode() || !scriptContext->GetThreadContext()->TTDLog->CanWriteInnerLoopTrace())
  424. {
  425. return JsErrorDiagUnableToPerformAction;
  426. }
  427. JsrtContext *currentContext = JsrtContext::GetCurrent();
  428. JsrtRuntime* runtime = currentContext->GetRuntime();
  429. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  430. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  431. TTD::TTDebuggerSourceLocation cloc;
  432. jsrtDebugManager->GetThreadContext()->TTDExecutionInfo->GetTimeAndPositionForDebugger(cloc);
  433. jsrtDebugManager->GetThreadContext()->TTDLog->InnerLoopEmitLog(cloc, uri, uriLength);
  434. return JsNoError;
  435. });
  436. #endif
  437. }
  438. CHAKRA_API JsDiagGetFunctionPosition(
  439. _In_ JsValueRef function,
  440. _Out_ JsValueRef *functionPosition)
  441. {
  442. #ifndef ENABLE_SCRIPT_DEBUGGING
  443. return JsErrorCategoryUsage;
  444. #else
  445. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  446. VALIDATE_INCOMING_REFERENCE(function, scriptContext);
  447. PARAM_NOT_NULL(functionPosition);
  448. *functionPosition = JS_INVALID_REFERENCE;
  449. if (!Js::RecyclableObject::Is(function) || !Js::ScriptFunction::Is(function))
  450. {
  451. return JsErrorInvalidArgument;
  452. }
  453. Js::ScriptFunction* jsFunction = Js::ScriptFunction::FromVar(function);
  454. BOOL fParsed = jsFunction->GetParseableFunctionInfo()->IsFunctionParsed();
  455. if (!fParsed)
  456. {
  457. Js::JavascriptFunction::DeferredParseCore(&jsFunction, fParsed);
  458. }
  459. if (fParsed)
  460. {
  461. Js::FunctionBody* functionBody = jsFunction->GetFunctionBody();
  462. if (functionBody != nullptr)
  463. {
  464. Js::Utf8SourceInfo* utf8SourceInfo = functionBody->GetUtf8SourceInfo();
  465. if (utf8SourceInfo != nullptr && !utf8SourceInfo->GetIsLibraryCode())
  466. {
  467. ULONG lineNumber = functionBody->GetLineNumber();
  468. ULONG columnNumber = functionBody->GetColumnNumber();
  469. uint startOffset = functionBody->GetStatementStartOffset(0);
  470. ULONG firstStatementLine;
  471. LONG firstStatementColumn;
  472. if (functionBody->GetLineCharOffsetFromStartChar(startOffset, &firstStatementLine, &firstStatementColumn))
  473. {
  474. Js::DynamicObject* funcPositionObject = (Js::DynamicObject*)Js::CrossSite::MarshalVar(utf8SourceInfo->GetScriptContext(), scriptContext->GetLibrary()->CreateObject());
  475. if (funcPositionObject != nullptr)
  476. {
  477. JsrtDebugUtils::AddScriptIdToObject(funcPositionObject, utf8SourceInfo);
  478. JsrtDebugUtils::AddFileNameOrScriptTypeToObject(funcPositionObject, utf8SourceInfo);
  479. JsrtDebugUtils::AddPropertyToObject(funcPositionObject, JsrtDebugPropertyId::line, (uint32)lineNumber, scriptContext);
  480. JsrtDebugUtils::AddPropertyToObject(funcPositionObject, JsrtDebugPropertyId::column, (uint32)columnNumber, scriptContext);
  481. JsrtDebugUtils::AddPropertyToObject(funcPositionObject, JsrtDebugPropertyId::firstStatementLine, (uint32)firstStatementLine, scriptContext);
  482. JsrtDebugUtils::AddPropertyToObject(funcPositionObject, JsrtDebugPropertyId::firstStatementColumn, (int32)firstStatementColumn, scriptContext);
  483. *functionPosition = funcPositionObject;
  484. return JsNoError;
  485. }
  486. }
  487. }
  488. }
  489. }
  490. return JsErrorDiagObjectNotFound;
  491. });
  492. #endif
  493. }
  494. CHAKRA_API JsDiagGetStackTrace(
  495. _Out_ JsValueRef *stackTrace)
  496. {
  497. #ifndef ENABLE_SCRIPT_DEBUGGING
  498. return JsErrorCategoryUsage;
  499. #else
  500. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  501. PARAM_NOT_NULL(stackTrace);
  502. *stackTrace = JS_INVALID_REFERENCE;
  503. JsrtContext* context = JsrtContext::GetCurrent();
  504. JsrtRuntime* runtime = context->GetRuntime();
  505. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  506. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  507. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  508. *stackTrace = jsrtDebugManager->GetStackFrames(scriptContext);
  509. return JsNoError;
  510. });
  511. #endif
  512. }
  513. CHAKRA_API JsDiagGetStackProperties(
  514. _In_ unsigned int stackFrameIndex,
  515. _Out_ JsValueRef *properties)
  516. {
  517. #ifndef ENABLE_SCRIPT_DEBUGGING
  518. return JsErrorCategoryUsage;
  519. #else
  520. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  521. PARAM_NOT_NULL(properties);
  522. *properties = JS_INVALID_REFERENCE;
  523. JsrtContext* context = JsrtContext::GetCurrent();
  524. JsrtRuntime* runtime = context->GetRuntime();
  525. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  526. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  527. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  528. JsrtDebuggerStackFrame* debuggerStackFrame = nullptr;
  529. if (!jsrtDebugManager->TryGetFrameObjectFromFrameIndex(scriptContext, stackFrameIndex, &debuggerStackFrame))
  530. {
  531. return JsErrorDiagObjectNotFound;
  532. }
  533. Js::DynamicObject* localsObject = debuggerStackFrame->GetLocalsObject(scriptContext);
  534. if (localsObject != nullptr)
  535. {
  536. *properties = localsObject;
  537. return JsNoError;
  538. }
  539. return JsErrorDiagUnableToPerformAction;
  540. });
  541. #endif
  542. }
  543. CHAKRA_API JsDiagGetProperties(
  544. _In_ unsigned int objectHandle,
  545. _In_ unsigned int fromCount,
  546. _In_ unsigned int totalCount,
  547. _Out_ JsValueRef *propertiesObject)
  548. {
  549. #ifndef ENABLE_SCRIPT_DEBUGGING
  550. return JsErrorCategoryUsage;
  551. #else
  552. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  553. PARAM_NOT_NULL(propertiesObject);
  554. *propertiesObject = JS_INVALID_REFERENCE;
  555. JsrtContext* context = JsrtContext::GetCurrent();
  556. JsrtRuntime* runtime = context->GetRuntime();
  557. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  558. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  559. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  560. JsrtDebuggerObjectBase* debuggerObject = nullptr;
  561. if (!jsrtDebugManager->GetDebuggerObjectsManager()->TryGetDebuggerObjectFromHandle(objectHandle, &debuggerObject) || debuggerObject == nullptr)
  562. {
  563. return JsErrorDiagInvalidHandle;
  564. }
  565. Js::DynamicObject* properties = debuggerObject->GetChildren(scriptContext, fromCount, totalCount);
  566. if (properties != nullptr)
  567. {
  568. *propertiesObject = properties;
  569. return JsNoError;
  570. }
  571. return JsErrorDiagUnableToPerformAction;
  572. });
  573. #endif
  574. }
  575. CHAKRA_API JsDiagGetObjectFromHandle(
  576. _In_ unsigned int objectHandle,
  577. _Out_ JsValueRef *handleObject)
  578. {
  579. #ifndef ENABLE_SCRIPT_DEBUGGING
  580. return JsErrorCategoryUsage;
  581. #else
  582. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  583. PARAM_NOT_NULL(handleObject);
  584. *handleObject = JS_INVALID_REFERENCE;
  585. JsrtContext* context = JsrtContext::GetCurrent();
  586. JsrtRuntime* runtime = context->GetRuntime();
  587. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  588. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  589. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  590. JsrtDebuggerObjectBase* debuggerObject = nullptr;
  591. if (!jsrtDebugManager->GetDebuggerObjectsManager()->TryGetDebuggerObjectFromHandle(objectHandle, &debuggerObject) || debuggerObject == nullptr)
  592. {
  593. return JsErrorDiagInvalidHandle;
  594. }
  595. Js::DynamicObject* object = debuggerObject->GetJSONObject(scriptContext, /* forceSetValueProp */ false);
  596. if (object != nullptr)
  597. {
  598. *handleObject = object;
  599. return JsNoError;
  600. }
  601. return JsErrorDiagUnableToPerformAction;
  602. });
  603. #endif
  604. }
  605. CHAKRA_API JsDiagEvaluate(
  606. _In_ JsValueRef expressionVal,
  607. _In_ unsigned int stackFrameIndex,
  608. _In_ JsParseScriptAttributes parseAttributes,
  609. _In_ bool forceSetValueProp,
  610. _Out_ JsValueRef *evalResult)
  611. {
  612. #ifndef ENABLE_SCRIPT_DEBUGGING
  613. return JsErrorCategoryUsage;
  614. #else
  615. return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  616. PARAM_NOT_NULL(expressionVal);
  617. PARAM_NOT_NULL(evalResult);
  618. bool isArrayBuffer = Js::ArrayBuffer::Is(expressionVal),
  619. isString = false;
  620. bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);
  621. if (!isArrayBuffer)
  622. {
  623. isString = Js::JavascriptString::Is(expressionVal);
  624. if (!isString)
  625. {
  626. return JsErrorInvalidArgument;
  627. }
  628. }
  629. const size_t len = isArrayBuffer ?
  630. Js::ArrayBuffer::FromVar(expressionVal)->GetByteLength() :
  631. Js::JavascriptString::FromVar(expressionVal)->GetLength();
  632. if (len > INT_MAX)
  633. {
  634. return JsErrorInvalidArgument;
  635. }
  636. const WCHAR* expression;
  637. utf8::NarrowToWide wide_expression;
  638. if (isArrayBuffer && isUtf8)
  639. {
  640. wide_expression.Initialize(
  641. (const char*)Js::ArrayBuffer::FromVar(expressionVal)->GetBuffer(), len);
  642. if (!wide_expression)
  643. {
  644. return JsErrorOutOfMemory;
  645. }
  646. expression = wide_expression;
  647. }
  648. else
  649. {
  650. expression = !isArrayBuffer ?
  651. Js::JavascriptString::FromVar(expressionVal)->GetSz() // String
  652. :
  653. (const WCHAR*)Js::ArrayBuffer::FromVar(expressionVal)->GetBuffer(); // ArrayBuffer;
  654. }
  655. *evalResult = JS_INVALID_REFERENCE;
  656. JsrtContext* context = JsrtContext::GetCurrent();
  657. JsrtRuntime* runtime = context->GetRuntime();
  658. VALIDATE_RUNTIME_IS_AT_BREAK(runtime);
  659. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  660. VALIDATE_IS_DEBUGGING(jsrtDebugManager);
  661. JsrtDebuggerStackFrame* debuggerStackFrame = nullptr;
  662. if (!jsrtDebugManager->TryGetFrameObjectFromFrameIndex(scriptContext, stackFrameIndex, &debuggerStackFrame))
  663. {
  664. return JsErrorDiagObjectNotFound;
  665. }
  666. Js::DynamicObject* result = nullptr;
  667. bool success = debuggerStackFrame->Evaluate(scriptContext, expression, static_cast<int>(len), false, forceSetValueProp, &result);
  668. if (result != nullptr)
  669. {
  670. *evalResult = result;
  671. }
  672. return success ? JsNoError : JsErrorScriptException;
  673. }, false /*allowInObjectBeforeCollectCallback*/, true /*scriptExceptionAllowed*/);
  674. #endif
  675. }