1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * JavaScript Debugging support - Call stack support
43 #include "jsfriendapi.h"
46 void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState
* jsdthreadstate
)
48 JS_ASSERT(jsdthreadstate
);
49 JS_ASSERT(jsdthreadstate
->stackDepth
> 0);
52 void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo
* jsdframe
)
55 JS_ASSERT(jsdframe
->jsdthreadstate
);
59 static JSDStackFrameInfo
*
60 _addNewFrame(JSDContext
* jsdc
,
61 JSDThreadState
* jsdthreadstate
,
66 JSDStackFrameInfo
* jsdframe
;
67 JSDScript
* jsdscript
= NULL
;
69 if (JS_IsScriptFrame(jsdthreadstate
->context
, fp
))
71 JSD_LOCK_SCRIPTS(jsdc
);
72 jsdscript
= jsd_FindJSDScript(jsdc
, script
);
73 JSD_UNLOCK_SCRIPTS(jsdc
);
74 if (!jsdscript
|| (jsdc
->flags
& JSD_HIDE_DISABLED_FRAMES
&&
75 !JSD_IS_DEBUG_ENABLED(jsdc
, jsdscript
)))
80 if (!JSD_IS_DEBUG_ENABLED(jsdc
, jsdscript
))
81 jsdthreadstate
->flags
|= TS_HAS_DISABLED_FRAME
;
84 jsdframe
= (JSDStackFrameInfo
*) calloc(1, sizeof(JSDStackFrameInfo
));
88 jsdframe
->jsdthreadstate
= jsdthreadstate
;
89 jsdframe
->jsdscript
= jsdscript
;
93 JS_APPEND_LINK(&jsdframe
->links
, &jsdthreadstate
->stack
);
94 jsdthreadstate
->stackDepth
++;
100 _destroyFrame(JSDStackFrameInfo
* jsdframe
)
102 /* kill any alloc'd objects in frame here... */
109 jsd_NewThreadState(JSDContext
* jsdc
, JSContext
*cx
)
111 JSDThreadState
* jsdthreadstate
;
112 JSStackFrame
* iter
= NULL
;
115 jsdthreadstate
= (JSDThreadState
*)calloc(1, sizeof(JSDThreadState
));
116 if( ! jsdthreadstate
)
119 jsdthreadstate
->context
= cx
;
120 jsdthreadstate
->thread
= JSD_CURRENT_THREAD();
121 JS_INIT_CLIST(&jsdthreadstate
->stack
);
122 jsdthreadstate
->stackDepth
= 0;
124 JS_BeginRequest(jsdthreadstate
->context
);
125 while( NULL
!= (fp
= JS_FrameIterator(cx
, &iter
)) )
127 JSScript
* script
= JS_GetFrameScript(cx
, fp
);
128 jsuword pc
= (jsuword
) JS_GetFramePC(cx
, fp
);
132 * don't construct a JSDStackFrame for dummy frames (those without a
133 * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
136 if (JS_GetFrameThis(cx
, fp
, &dummyThis
) &&
137 ((jsdc
->flags
& JSD_INCLUDE_NATIVE_FRAMES
) ||
138 JS_IsScriptFrame(cx
, fp
)))
140 JSDStackFrameInfo
*frame
;
142 frame
= _addNewFrame( jsdc
, jsdthreadstate
, script
, pc
, fp
);
144 if ((jsdthreadstate
->stackDepth
== 0 && !frame
) ||
145 (jsdthreadstate
->stackDepth
== 1 && frame
&&
146 frame
->jsdscript
&& !JSD_IS_DEBUG_ENABLED(jsdc
, frame
->jsdscript
)))
149 * if we failed to create the first frame, or the top frame
150 * is not enabled for debugging, fail the entire thread state.
152 JS_INIT_CLIST(&jsdthreadstate
->links
);
153 JS_EndRequest(jsdthreadstate
->context
);
154 jsd_DestroyThreadState(jsdc
, jsdthreadstate
);
159 JS_EndRequest(jsdthreadstate
->context
);
161 if (jsdthreadstate
->stackDepth
== 0)
163 free(jsdthreadstate
);
167 JSD_LOCK_THREADSTATES(jsdc
);
168 JS_APPEND_LINK(&jsdthreadstate
->links
, &jsdc
->threadsStates
);
169 JSD_UNLOCK_THREADSTATES(jsdc
);
171 return jsdthreadstate
;
175 jsd_DestroyThreadState(JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
)
177 JSDStackFrameInfo
* jsdframe
;
180 JS_ASSERT(jsdthreadstate
);
181 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate
->thread
);
183 JSD_LOCK_THREADSTATES(jsdc
);
184 JS_REMOVE_LINK(&jsdthreadstate
->links
);
185 JSD_UNLOCK_THREADSTATES(jsdc
);
187 list
= &jsdthreadstate
->stack
;
188 while( (JSDStackFrameInfo
*)list
!= (jsdframe
= (JSDStackFrameInfo
*)list
->next
) )
190 JS_REMOVE_LINK(&jsdframe
->links
);
191 _destroyFrame(jsdframe
);
193 free(jsdthreadstate
);
197 jsd_GetCountOfStackFrames(JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
)
201 JSD_LOCK_THREADSTATES(jsdc
);
203 if( jsd_IsValidThreadState(jsdc
, jsdthreadstate
) )
204 count
= jsdthreadstate
->stackDepth
;
206 JSD_UNLOCK_THREADSTATES(jsdc
);
212 jsd_GetStackFrame(JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
)
214 JSDStackFrameInfo
* jsdframe
= NULL
;
216 JSD_LOCK_THREADSTATES(jsdc
);
218 if( jsd_IsValidThreadState(jsdc
, jsdthreadstate
) )
219 jsdframe
= (JSDStackFrameInfo
*) JS_LIST_HEAD(&jsdthreadstate
->stack
);
220 JSD_UNLOCK_THREADSTATES(jsdc
);
226 jsd_GetJSContext (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
)
228 JSContext
* cx
= NULL
;
230 JSD_LOCK_THREADSTATES(jsdc
);
231 if( jsd_IsValidThreadState(jsdc
, jsdthreadstate
) )
232 cx
= jsdthreadstate
->context
;
233 JSD_UNLOCK_THREADSTATES(jsdc
);
239 jsd_GetCallingStackFrame(JSDContext
* jsdc
,
240 JSDThreadState
* jsdthreadstate
,
241 JSDStackFrameInfo
* jsdframe
)
243 JSDStackFrameInfo
* nextjsdframe
= NULL
;
245 JSD_LOCK_THREADSTATES(jsdc
);
247 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
248 if( JS_LIST_HEAD(&jsdframe
->links
) != &jsdframe
->jsdthreadstate
->stack
)
249 nextjsdframe
= (JSDStackFrameInfo
*) JS_LIST_HEAD(&jsdframe
->links
);
251 JSD_UNLOCK_THREADSTATES(jsdc
);
257 jsd_GetScriptForStackFrame(JSDContext
* jsdc
,
258 JSDThreadState
* jsdthreadstate
,
259 JSDStackFrameInfo
* jsdframe
)
261 JSDScript
* jsdscript
= NULL
;
263 JSD_LOCK_THREADSTATES(jsdc
);
265 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
266 jsdscript
= jsdframe
->jsdscript
;
268 JSD_UNLOCK_THREADSTATES(jsdc
);
274 jsd_GetPCForStackFrame(JSDContext
* jsdc
,
275 JSDThreadState
* jsdthreadstate
,
276 JSDStackFrameInfo
* jsdframe
)
280 JSD_LOCK_THREADSTATES(jsdc
);
282 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
285 JSD_UNLOCK_THREADSTATES(jsdc
);
291 jsd_GetCallObjectForStackFrame(JSDContext
* jsdc
,
292 JSDThreadState
* jsdthreadstate
,
293 JSDStackFrameInfo
* jsdframe
)
296 JSDValue
* jsdval
= NULL
;
298 JSD_LOCK_THREADSTATES(jsdc
);
300 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
302 obj
= JS_GetFrameCallObject(jsdthreadstate
->context
, jsdframe
->fp
);
304 jsdval
= JSD_NewValue(jsdc
, OBJECT_TO_JSVAL(obj
));
307 JSD_UNLOCK_THREADSTATES(jsdc
);
313 jsd_GetScopeChainForStackFrame(JSDContext
* jsdc
,
314 JSDThreadState
* jsdthreadstate
,
315 JSDStackFrameInfo
* jsdframe
)
318 JSDValue
* jsdval
= NULL
;
320 JSD_LOCK_THREADSTATES(jsdc
);
322 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
324 JS_BeginRequest(jsdthreadstate
->context
);
325 obj
= JS_GetFrameScopeChain(jsdthreadstate
->context
, jsdframe
->fp
);
326 JS_EndRequest(jsdthreadstate
->context
);
328 jsdval
= JSD_NewValue(jsdc
, OBJECT_TO_JSVAL(obj
));
331 JSD_UNLOCK_THREADSTATES(jsdc
);
337 jsd_GetThisForStackFrame(JSDContext
* jsdc
,
338 JSDThreadState
* jsdthreadstate
,
339 JSDStackFrameInfo
* jsdframe
)
342 JSDValue
* jsdval
= NULL
;
343 JSD_LOCK_THREADSTATES(jsdc
);
345 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
349 JS_BeginRequest(jsdthreadstate
->context
);
350 ok
= JS_GetFrameThis(jsdthreadstate
->context
, jsdframe
->fp
, &thisval
);
351 JS_EndRequest(jsdthreadstate
->context
);
353 jsdval
= JSD_NewValue(jsdc
, thisval
);
356 JSD_UNLOCK_THREADSTATES(jsdc
);
361 jsd_GetNameForStackFrame(JSDContext
* jsdc
,
362 JSDThreadState
* jsdthreadstate
,
363 JSDStackFrameInfo
* jsdframe
)
367 JSD_LOCK_THREADSTATES(jsdc
);
369 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
371 JSFunction
*fun
= JS_GetFrameFunction (jsdthreadstate
->context
,
375 rv
= JS_GetFunctionId (fun
);
378 * For compatibility we return "anonymous", not an empty string
382 rv
= JS_GetAnonymousString(jsdc
->jsrt
);
386 JSD_UNLOCK_THREADSTATES(jsdc
);
391 jsd_IsStackFrameDebugger(JSDContext
* jsdc
,
392 JSDThreadState
* jsdthreadstate
,
393 JSDStackFrameInfo
* jsdframe
)
396 JSD_LOCK_THREADSTATES(jsdc
);
398 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
400 rv
= JS_IsDebuggerFrame(jsdthreadstate
->context
, jsdframe
->fp
);
403 JSD_UNLOCK_THREADSTATES(jsdc
);
408 jsd_IsStackFrameConstructing(JSDContext
* jsdc
,
409 JSDThreadState
* jsdthreadstate
,
410 JSDStackFrameInfo
* jsdframe
)
413 JSD_LOCK_THREADSTATES(jsdc
);
415 if( jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
) )
417 rv
= JS_IsConstructorFrame(jsdthreadstate
->context
, jsdframe
->fp
);
420 JSD_UNLOCK_THREADSTATES(jsdc
);
425 jsd_EvaluateUCScriptInStackFrame(JSDContext
* jsdc
,
426 JSDThreadState
* jsdthreadstate
,
427 JSDStackFrameInfo
* jsdframe
,
428 const jschar
*bytes
, uintN length
,
429 const char *filename
, uintN lineno
,
430 JSBool eatExceptions
, jsval
*rval
)
434 JSExceptionState
* exceptionState
= NULL
;
437 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate
->thread
);
439 JSD_LOCK_THREADSTATES(jsdc
);
440 valid
= jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
);
441 JSD_UNLOCK_THREADSTATES(jsdc
);
446 cx
= jsdthreadstate
->context
;
450 exceptionState
= JS_SaveExceptionState(cx
);
451 JS_ClearPendingException(cx
);
452 jsd_StartingEvalUsingFilename(jsdc
, filename
);
453 retval
= JS_EvaluateUCInStackFrame(cx
, jsdframe
->fp
, bytes
, length
,
454 filename
, lineno
, rval
);
455 jsd_FinishedEvalUsingFilename(jsdc
, filename
);
457 JS_RestoreExceptionState(cx
, exceptionState
);
463 jsd_EvaluateScriptInStackFrame(JSDContext
* jsdc
,
464 JSDThreadState
* jsdthreadstate
,
465 JSDStackFrameInfo
* jsdframe
,
466 const char *bytes
, uintN length
,
467 const char *filename
, uintN lineno
,
468 JSBool eatExceptions
, jsval
*rval
)
472 JSExceptionState
* exceptionState
= NULL
;
475 JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate
->thread
);
477 JSD_LOCK_THREADSTATES(jsdc
);
478 valid
= jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
);
479 JSD_UNLOCK_THREADSTATES(jsdc
);
484 cx
= jsdthreadstate
->context
;
488 exceptionState
= JS_SaveExceptionState(cx
);
489 JS_ClearPendingException(cx
);
490 jsd_StartingEvalUsingFilename(jsdc
, filename
);
491 retval
= JS_EvaluateInStackFrame(cx
, jsdframe
->fp
, bytes
, length
,
492 filename
, lineno
, rval
);
493 jsd_FinishedEvalUsingFilename(jsdc
, filename
);
495 JS_RestoreExceptionState(cx
, exceptionState
);
501 jsd_ValToStringInStackFrame(JSDContext
* jsdc
,
502 JSDThreadState
* jsdthreadstate
,
503 JSDStackFrameInfo
* jsdframe
,
508 JSExceptionState
* exceptionState
;
511 JSD_LOCK_THREADSTATES(jsdc
);
512 valid
= jsd_IsValidFrameInThreadState(jsdc
, jsdthreadstate
, jsdframe
);
513 JSD_UNLOCK_THREADSTATES(jsdc
);
518 cx
= jsdthreadstate
->context
;
521 exceptionState
= JS_SaveExceptionState(cx
);
522 retval
= JS_ValueToString(cx
, val
);
523 JS_RestoreExceptionState(cx
, exceptionState
);
529 jsd_IsValidThreadState(JSDContext
* jsdc
,
530 JSDThreadState
* jsdthreadstate
)
534 JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc
) );
536 for( cur
= (JSDThreadState
*)jsdc
->threadsStates
.next
;
537 cur
!= (JSDThreadState
*)&jsdc
->threadsStates
;
538 cur
= (JSDThreadState
*)cur
->links
.next
)
540 if( cur
== jsdthreadstate
)
547 jsd_IsValidFrameInThreadState(JSDContext
* jsdc
,
548 JSDThreadState
* jsdthreadstate
,
549 JSDStackFrameInfo
* jsdframe
)
551 JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc
));
553 if( ! jsd_IsValidThreadState(jsdc
, jsdthreadstate
) )
555 if( jsdframe
->jsdthreadstate
!= jsdthreadstate
)
558 JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate
);
559 JSD_ASSERT_VALID_STACK_FRAME(jsdframe
);
565 _getContextForThreadState(JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
)
568 JSD_LOCK_THREADSTATES(jsdc
);
569 valid
= jsd_IsValidThreadState(jsdc
, jsdthreadstate
);
570 JSD_UNLOCK_THREADSTATES(jsdc
);
572 return jsdthreadstate
->context
;
577 jsd_GetException(JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
)
582 if(!(cx
= _getContextForThreadState(jsdc
, jsdthreadstate
)))
585 if(JS_GetPendingException(cx
, &val
))
586 return jsd_NewValue(jsdc
, val
);
591 jsd_SetException(JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
596 if(!(cx
= _getContextForThreadState(jsdc
, jsdthreadstate
)))
600 JS_SetPendingException(cx
, JSD_GetValueWrappedJSVal(jsdc
, jsdval
));
602 JS_ClearPendingException(cx
);