Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
7 /*
8 * JavaScript Debugging support - Script support
9 */
11 #include "jsd.h"
12 #include "jsfriendapi.h"
13 #include "nsCxPusher.h"
15 using mozilla::AutoSafeJSContext;
17 /* Comment this out to disable (NT specific) dumping as we go */
18 /*
19 ** #ifdef DEBUG
20 ** #define JSD_DUMP 1
21 ** #endif
22 */
24 #define NOT_SET_YET -1
26 /***************************************************************************/
28 #ifdef DEBUG
29 void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript)
30 {
31 MOZ_ASSERT(jsdscript);
32 MOZ_ASSERT(jsdscript->script);
33 }
34 void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook)
35 {
36 MOZ_ASSERT(jsdhook);
37 MOZ_ASSERT(jsdhook->hook);
38 }
39 #endif
41 static JSDScript*
42 _newJSDScript(JSDContext* jsdc,
43 JSContext *cx,
44 JSScript *script_)
45 {
46 JS::RootedScript script(cx, script_);
47 if ( JS_GetScriptIsSelfHosted(script) )
48 return nullptr;
50 JSDScript* jsdscript;
51 unsigned lineno;
52 const char* raw_filename;
54 MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
56 /* these are inlined javascript: urls and we can't handle them now */
57 lineno = (unsigned) JS_GetScriptBaseLineNumber(cx, script);
58 if( lineno == 0 )
59 return nullptr;
61 jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript));
62 if( ! jsdscript )
63 return nullptr;
65 raw_filename = JS_GetScriptFilename(script);
67 JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript);
68 JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts);
69 jsdscript->jsdc = jsdc;
70 jsdscript->script = script;
71 jsdscript->lineBase = lineno;
72 jsdscript->lineExtent = (unsigned)NOT_SET_YET;
73 jsdscript->data = nullptr;
74 jsdscript->url = (char*) jsd_BuildNormalizedURL(raw_filename);
76 JS_INIT_CLIST(&jsdscript->hooks);
78 return jsdscript;
79 }
81 static void
82 _destroyJSDScript(JSDContext* jsdc,
83 JSDScript* jsdscript)
84 {
85 MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
87 /* destroy all hooks */
88 jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
90 JS_REMOVE_LINK(&jsdscript->links);
91 if(jsdscript->url)
92 free(jsdscript->url);
94 if (jsdscript->profileData)
95 free(jsdscript->profileData);
97 free(jsdscript);
98 }
100 /***************************************************************************/
102 #ifdef JSD_DUMP
103 #ifndef XP_WIN
104 void
105 OutputDebugString (char *buf)
106 {
107 fprintf (stderr, "%s", buf);
108 }
109 #endif
111 static void
112 _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
113 {
114 const char* name;
115 JSString* fun;
116 unsigned base;
117 unsigned extent;
118 char Buf[256];
119 size_t n;
121 name = jsd_GetScriptFilename(jsdc, jsdscript);
122 fun = jsd_GetScriptFunctionId(jsdc, jsdscript);
123 base = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
124 extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
125 n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
126 leadingtext, (unsigned) jsdscript->script,
127 name ? name : "no URL"));
128 if (n + 1 < sizeof(Buf)) {
129 if (fun) {
130 n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
131 } else {
132 n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n,
133 MOZ_ASSERT_STRING_IS_FLAT(fun), 0);
134 Buf[sizeof(Buf) - 1] = '\0';
135 }
136 if (n + 1 < sizeof(Buf))
137 snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
138 }
139 OutputDebugString( Buf );
140 }
142 static void
143 _dumpJSDScriptList( JSDContext* jsdc )
144 {
145 JSDScript* iterp = nullptr;
146 JSDScript* jsdscript = nullptr;
148 OutputDebugString( "*** JSDScriptDump\n" );
149 while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
150 _dumpJSDScript( jsdc, jsdscript, " script: " );
151 }
152 #endif /* JSD_DUMP */
154 /***************************************************************************/
155 static JSHashNumber
156 jsd_hash_script(const void *key)
157 {
158 return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */
159 }
161 static void *
162 jsd_alloc_script_table(void *priv, size_t size)
163 {
164 return malloc(size);
165 }
167 static void
168 jsd_free_script_table(void *priv, void *item, size_t size)
169 {
170 free(item);
171 }
173 static JSHashEntry *
174 jsd_alloc_script_entry(void *priv, const void *item)
175 {
176 return (JSHashEntry*) malloc(sizeof(JSHashEntry));
177 }
179 static void
180 jsd_free_script_entry(void *priv, JSHashEntry *he, unsigned flag)
181 {
182 if (flag == HT_FREE_ENTRY)
183 {
184 _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value);
185 free(he);
186 }
187 }
189 static const JSHashAllocOps script_alloc_ops = {
190 jsd_alloc_script_table, jsd_free_script_table,
191 jsd_alloc_script_entry, jsd_free_script_entry
192 };
194 #ifndef JSD_SCRIPT_HASH_SIZE
195 #define JSD_SCRIPT_HASH_SIZE 1024
196 #endif
198 bool
199 jsd_InitScriptManager(JSDContext* jsdc)
200 {
201 JS_INIT_CLIST(&jsdc->scripts);
202 jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script,
203 JS_CompareValues, JS_CompareValues,
204 &script_alloc_ops, (void*) jsdc);
205 return !!jsdc->scriptsTable;
206 }
208 void
209 jsd_DestroyScriptManager(JSDContext* jsdc)
210 {
211 JSD_LOCK_SCRIPTS(jsdc);
212 if (jsdc->scriptsTable)
213 JS_HashTableDestroy(jsdc->scriptsTable);
214 JSD_UNLOCK_SCRIPTS(jsdc);
215 }
217 JSDScript*
218 jsd_FindJSDScript( JSDContext* jsdc,
219 JSScript *script )
220 {
221 MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
222 return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script);
223 }
225 JSDScript *
226 jsd_FindOrCreateJSDScript(JSDContext *jsdc,
227 JSContext *cx,
228 JSScript *script_,
229 JSAbstractFramePtr frame)
230 {
231 JS::RootedScript script(cx, script_);
232 JSDScript *jsdscript;
233 MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
235 jsdscript = jsd_FindJSDScript(jsdc, script);
236 if (jsdscript)
237 return jsdscript;
239 /* Fallback for unknown scripts: create a new script. */
240 if (!frame) {
241 JSBrokenFrameIterator iter(cx);
242 if (!iter.done())
243 frame = iter.abstractFramePtr();
244 }
245 if (frame)
246 jsdscript = _newJSDScript(jsdc, cx, script);
248 return jsdscript;
249 }
251 JSDProfileData*
252 jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script)
253 {
254 if (!script->profileData)
255 script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData));
257 return script->profileData;
258 }
260 uint32_t
261 jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script)
262 {
263 return script->flags;
264 }
266 void
267 jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags)
268 {
269 script->flags = flags;
270 }
272 unsigned
273 jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script)
274 {
275 if (script->profileData)
276 return script->profileData->callCount;
278 return 0;
279 }
281 unsigned
282 jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script)
283 {
284 if (script->profileData)
285 return script->profileData->maxRecurseDepth;
287 return 0;
288 }
290 double
291 jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script)
292 {
293 if (script->profileData)
294 return script->profileData->minExecutionTime;
296 return 0.0;
297 }
299 double
300 jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script)
301 {
302 if (script->profileData)
303 return script->profileData->maxExecutionTime;
305 return 0.0;
306 }
308 double
309 jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script)
310 {
311 if (script->profileData)
312 return script->profileData->totalExecutionTime;
314 return 0.0;
315 }
317 double
318 jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
319 {
320 if (script->profileData)
321 return script->profileData->minOwnExecutionTime;
323 return 0.0;
324 }
326 double
327 jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
328 {
329 if (script->profileData)
330 return script->profileData->maxOwnExecutionTime;
332 return 0.0;
333 }
335 double
336 jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script)
337 {
338 if (script->profileData)
339 return script->profileData->totalOwnExecutionTime;
341 return 0.0;
342 }
344 void
345 jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script)
346 {
347 if (script->profileData)
348 {
349 free(script->profileData);
350 script->profileData = nullptr;
351 }
352 }
354 JSScript *
355 jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
356 {
357 return script->script;
358 }
360 JSFunction *
361 jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
362 {
363 AutoSafeJSContext cx;
364 return JS_GetScriptFunction(cx, script->script);
365 }
367 JSDScript*
368 jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
369 {
370 JSDScript *jsdscript = *iterp;
372 MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
374 if( !jsdscript )
375 jsdscript = (JSDScript *)jsdc->scripts.next;
376 if( jsdscript == (JSDScript *)&jsdc->scripts )
377 return nullptr;
378 *iterp = (JSDScript*) jsdscript->links.next;
379 return jsdscript;
380 }
382 void *
383 jsd_SetScriptPrivate(JSDScript *jsdscript, void *data)
384 {
385 void *rval = jsdscript->data;
386 jsdscript->data = data;
387 return rval;
388 }
390 void *
391 jsd_GetScriptPrivate(JSDScript *jsdscript)
392 {
393 return jsdscript->data;
394 }
396 bool
397 jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript)
398 {
399 JSDScript *current;
401 MOZ_ASSERT(JSD_SCRIPTS_LOCKED(jsdc));
403 for( current = (JSDScript *)jsdc->scripts.next;
404 current != (JSDScript *)&jsdc->scripts;
405 current = (JSDScript *)current->links.next )
406 {
407 if(jsdscript == current)
408 return true;
409 }
410 return false;
411 }
413 const char*
414 jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
415 {
416 return jsdscript->url;
417 }
419 JSString*
420 jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript)
421 {
422 JSString* str;
423 JSFunction *fun = jsd_GetJSFunction(jsdc, jsdscript);
425 if( ! fun )
426 return nullptr;
427 str = JS_GetFunctionId(fun);
429 /* For compatibility we return "anonymous", not an empty string here. */
430 return str ? str : JS_GetAnonymousString(jsdc->jsrt);
431 }
433 unsigned
434 jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
435 {
436 return jsdscript->lineBase;
437 }
439 unsigned
440 jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript)
441 {
442 AutoSafeJSContext cx;
443 JSAutoCompartment ac(cx, jsdc->glob); // Just in case.
444 if( NOT_SET_YET == (int)jsdscript->lineExtent )
445 jsdscript->lineExtent = JS_GetScriptLineExtent(cx, jsdscript->script);
446 return jsdscript->lineExtent;
447 }
449 uintptr_t
450 jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line)
451 {
452 uintptr_t pc;
454 if( !jsdscript )
455 return 0;
457 AutoSafeJSContext cx;
458 JSAutoCompartment ac(cx, jsdscript->script);
459 pc = (uintptr_t) JS_LineNumberToPC(cx, jsdscript->script, line );
460 return pc;
461 }
463 unsigned
464 jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
465 {
466 unsigned first = jsdscript->lineBase;
467 unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
468 unsigned line = 0;
470 if (pc) {
471 AutoSafeJSContext cx;
472 JSAutoCompartment ac(cx, jsdscript->script);
473 line = JS_PCToLineNumber(cx, jsdscript->script, (jsbytecode*)pc);
474 }
476 if( line < first )
477 return first;
478 if( line > last )
479 return last;
481 return line;
482 }
484 bool
485 jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript,
486 unsigned startLine, unsigned maxLines,
487 unsigned* count, unsigned** retLines, uintptr_t** retPCs)
488 {
489 unsigned first = jsdscript->lineBase;
490 unsigned last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
491 bool ok;
492 jsbytecode **pcs;
493 unsigned i;
495 if (last < startLine)
496 return true;
498 AutoSafeJSContext cx;
499 JSAutoCompartment ac(cx, jsdscript->script);
501 ok = JS_GetLinePCs(cx, jsdscript->script,
502 startLine, maxLines,
503 count, retLines, &pcs);
505 if (ok) {
506 if (retPCs) {
507 for (i = 0; i < *count; ++i) {
508 (*retPCs)[i] = (*pcs)[i];
509 }
510 }
512 JS_free(cx, pcs);
513 }
515 return ok;
516 }
518 bool
519 jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata)
520 {
521 JSD_LOCK();
522 jsdc->scriptHook = hook;
523 jsdc->scriptHookData = callerdata;
524 JSD_UNLOCK();
525 return true;
526 }
528 bool
529 jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata)
530 {
531 JSD_LOCK();
532 if( hook )
533 *hook = jsdc->scriptHook;
534 if( callerdata )
535 *callerdata = jsdc->scriptHookData;
536 JSD_UNLOCK();
537 return true;
538 }
540 bool
541 jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, bool enable)
542 {
543 bool rv;
544 AutoSafeJSContext cx;
545 JS::RootedScript script(cx, jsdscript->script);
546 JSAutoCompartment ac(cx, script);
547 JSD_LOCK();
548 rv = JS_SetSingleStepMode(cx, script, enable);
549 JSD_UNLOCK();
550 return rv;
551 }
554 /***************************************************************************/
556 void
557 jsd_NewScriptHookProc(
558 JSContext *cx,
559 const char *filename, /* URL this script loads from */
560 unsigned lineno, /* line where this script starts */
561 JSScript *script,
562 JSFunction *fun,
563 void* callerdata )
564 {
565 JSDScript* jsdscript = nullptr;
566 JSDContext* jsdc = (JSDContext*) callerdata;
567 JSD_ScriptHookProc hook;
568 void* hookData;
570 JSD_ASSERT_VALID_CONTEXT(jsdc);
572 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
573 return;
575 JSD_LOCK_SCRIPTS(jsdc);
576 jsdscript = _newJSDScript(jsdc, cx, script);
577 JSD_UNLOCK_SCRIPTS(jsdc);
578 if( ! jsdscript )
579 return;
581 #ifdef JSD_DUMP
582 JSD_LOCK_SCRIPTS(jsdc);
583 _dumpJSDScript(jsdc, jsdscript, "***NEW Script: ");
584 _dumpJSDScriptList( jsdc );
585 JSD_UNLOCK_SCRIPTS(jsdc);
586 #endif /* JSD_DUMP */
588 /* local in case jsdc->scriptHook gets cleared on another thread */
589 JSD_LOCK();
590 hook = jsdc->scriptHook;
591 if( hook )
592 jsdscript->flags = jsdscript->flags | JSD_SCRIPT_CALL_DESTROY_HOOK_BIT;
593 hookData = jsdc->scriptHookData;
594 JSD_UNLOCK();
596 if( hook )
597 hook(jsdc, jsdscript, true, hookData);
598 }
600 void
601 jsd_DestroyScriptHookProc(
602 JSFreeOp *fop,
603 JSScript *script_,
604 void* callerdata )
605 {
606 JSDScript* jsdscript = nullptr;
607 JSDContext* jsdc = (JSDContext*) callerdata;
608 // NB: We're called during GC, so we can't push a cx. Root directly with
609 // the runtime.
610 JS::RootedScript script(jsdc->jsrt, script_);
611 JSD_ScriptHookProc hook;
612 void* hookData;
614 JSD_ASSERT_VALID_CONTEXT(jsdc);
616 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
617 return;
619 JSD_LOCK_SCRIPTS(jsdc);
620 jsdscript = jsd_FindJSDScript(jsdc, script);
621 JSD_UNLOCK_SCRIPTS(jsdc);
623 if( ! jsdscript )
624 return;
626 #ifdef JSD_DUMP
627 JSD_LOCK_SCRIPTS(jsdc);
628 _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: ");
629 JSD_UNLOCK_SCRIPTS(jsdc);
630 #endif /* JSD_DUMP */
632 /* local in case hook gets cleared on another thread */
633 JSD_LOCK();
634 hook = (jsdscript->flags & JSD_SCRIPT_CALL_DESTROY_HOOK_BIT) ? jsdc->scriptHook
635 : nullptr;
636 hookData = jsdc->scriptHookData;
637 JSD_UNLOCK();
639 if( hook )
640 hook(jsdc, jsdscript, false, hookData);
642 JSD_LOCK_SCRIPTS(jsdc);
643 JS_HashTableRemove(jsdc->scriptsTable, (void *)script);
644 JSD_UNLOCK_SCRIPTS(jsdc);
646 #ifdef JSD_DUMP
647 JSD_LOCK_SCRIPTS(jsdc);
648 _dumpJSDScriptList(jsdc);
649 JSD_UNLOCK_SCRIPTS(jsdc);
650 #endif /* JSD_DUMP */
651 }
654 /***************************************************************************/
656 static JSDExecHook*
657 _findHook(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc)
658 {
659 JSDExecHook* jsdhook;
660 JSCList* list = &jsdscript->hooks;
662 for( jsdhook = (JSDExecHook*)list->next;
663 jsdhook != (JSDExecHook*)list;
664 jsdhook = (JSDExecHook*)jsdhook->links.next )
665 {
666 if (jsdhook->pc == pc)
667 return jsdhook;
668 }
669 return nullptr;
670 }
672 static bool
673 _isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook)
674 {
675 JSDExecHook* current;
676 JSCList* list;
677 JSDScript* jsdscript;
679 JSD_LOCK_SCRIPTS(jsdc);
680 jsdscript = jsd_FindJSDScript(jsdc, script);
681 if( ! jsdscript)
682 {
683 JSD_UNLOCK_SCRIPTS(jsdc);
684 return false;
685 }
687 list = &jsdscript->hooks;
689 for( current = (JSDExecHook*)list->next;
690 current != (JSDExecHook*)list;
691 current = (JSDExecHook*)current->links.next )
692 {
693 if(current == jsdhook)
694 {
695 JSD_UNLOCK_SCRIPTS(jsdc);
696 return true;
697 }
698 }
699 JSD_UNLOCK_SCRIPTS(jsdc);
700 return false;
701 }
704 JSTrapStatus
705 jsd_TrapHandler(JSContext *cx, JSScript *script_, jsbytecode *pc, jsval *rval,
706 jsval closure)
707 {
708 JS::RootedScript script(cx, script_);
709 JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure);
710 JSD_ExecutionHookProc hook;
711 void* hookData;
712 JSDContext* jsdc;
714 JSD_LOCK();
716 if( nullptr == (jsdc = jsd_JSDContextForJSContext(cx)) ||
717 ! _isActiveHook(jsdc, script, jsdhook) )
718 {
719 JSD_UNLOCK();
720 return JSTRAP_CONTINUE;
721 }
723 JSD_ASSERT_VALID_EXEC_HOOK(jsdhook);
724 MOZ_ASSERT(!jsdhook->pc || jsdhook->pc == (uintptr_t)pc);
725 MOZ_ASSERT(jsdhook->jsdscript->script == script);
726 MOZ_ASSERT(jsdhook->jsdscript->jsdc == jsdc);
728 hook = jsdhook->hook;
729 hookData = jsdhook->callerdata;
731 /* do not use jsdhook-> after this point */
732 JSD_UNLOCK();
734 if( ! jsdc || ! jsdc->inited )
735 return JSTRAP_CONTINUE;
737 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
738 return JSTRAP_CONTINUE;
740 return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT,
741 hook, hookData, rval);
742 }
746 bool
747 jsd_SetExecutionHook(JSDContext* jsdc,
748 JSDScript* jsdscript,
749 uintptr_t pc,
750 JSD_ExecutionHookProc hook,
751 void* callerdata)
752 {
753 JSDExecHook* jsdhook;
754 bool rv;
756 JSD_LOCK();
757 if( ! hook )
758 {
759 jsd_ClearExecutionHook(jsdc, jsdscript, pc);
760 JSD_UNLOCK();
761 return true;
762 }
764 jsdhook = _findHook(jsdc, jsdscript, pc);
765 if( jsdhook )
766 {
767 jsdhook->hook = hook;
768 jsdhook->callerdata = callerdata;
769 JSD_UNLOCK();
770 return true;
771 }
772 /* else... */
774 jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook));
775 if( ! jsdhook ) {
776 JSD_UNLOCK();
777 return false;
778 }
779 jsdhook->jsdscript = jsdscript;
780 jsdhook->pc = pc;
781 jsdhook->hook = hook;
782 jsdhook->callerdata = callerdata;
784 {
785 AutoSafeJSContext cx;
786 JSAutoCompartment ac(cx, jsdscript->script);
787 JS::RootedScript script(cx, jsdscript->script);
788 JS::RootedValue hookValue(cx, PRIVATE_TO_JSVAL(jsdhook));
789 rv = JS_SetTrap(cx, script, (jsbytecode*)pc, jsd_TrapHandler, hookValue);
790 }
792 if ( ! rv ) {
793 free(jsdhook);
794 JSD_UNLOCK();
795 return false;
796 }
798 JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
799 JSD_UNLOCK();
801 return true;
802 }
804 bool
805 jsd_ClearExecutionHook(JSDContext* jsdc,
806 JSDScript* jsdscript,
807 uintptr_t pc)
808 {
809 JSDExecHook* jsdhook;
811 JSD_LOCK();
813 jsdhook = _findHook(jsdc, jsdscript, pc);
814 if( ! jsdhook )
815 {
816 JSD_UNLOCK();
817 return false;
818 }
820 {
821 AutoSafeJSContext cx;
822 JSAutoCompartment ac(cx, jsdscript->script);
823 JS_ClearTrap(cx, jsdscript->script,
824 (jsbytecode*)pc, nullptr, nullptr);
825 }
827 JS_REMOVE_LINK(&jsdhook->links);
828 free(jsdhook);
830 JSD_UNLOCK();
831 return true;
832 }
834 bool
835 jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript)
836 {
837 JSDExecHook* jsdhook;
838 JSCList* list = &jsdscript->hooks;
839 JSD_LOCK();
841 while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
842 {
843 JS_REMOVE_LINK(&jsdhook->links);
844 free(jsdhook);
845 }
847 JS_ClearScriptTraps(jsdc->jsrt, jsdscript->script);
848 JSD_UNLOCK();
850 return true;
851 }
853 bool
854 jsd_ClearAllExecutionHooks(JSDContext* jsdc)
855 {
856 JSDScript* jsdscript;
857 JSDScript* iterp = nullptr;
859 JSD_LOCK();
860 while( nullptr != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) )
861 jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript);
862 JSD_UNLOCK();
863 return true;
864 }
866 void
867 jsd_ScriptCreated(JSDContext* jsdc,
868 JSContext *cx,
869 const char *filename, /* URL this script loads from */
870 unsigned lineno, /* line where this script starts */
871 JSScript *script,
872 JSFunction *fun)
873 {
874 jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
875 }
877 void
878 jsd_ScriptDestroyed(JSDContext* jsdc,
879 JSFreeOp *fop,
880 JSScript *script)
881 {
882 jsd_DestroyScriptHookProc(fop, script, jsdc);
883 }