1 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
* vim: set ts=8 sw=4 et tw=80: |
3 |
* |
4 |
* ***** BEGIN LICENSE BLOCK ***** |
5 |
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
6 |
* |
7 |
* The contents of this file are subject to the Mozilla Public License Version |
8 |
* 1.1 (the "License"); you may not use this file except in compliance with |
9 |
* the License. You may obtain a copy of the License at |
10 |
* http://www.mozilla.org/MPL/ |
11 |
* |
12 |
* Software distributed under the License is distributed on an "AS IS" basis, |
13 |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
14 |
* for the specific language governing rights and limitations under the |
15 |
* License. |
16 |
* |
17 |
* Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved. |
18 |
* |
19 |
* Contributor(s): |
20 |
* Brendan Eich <brendan@mozilla.org> |
21 |
* |
22 |
* Alternatively, the contents of this file may be used under the terms of |
23 |
* either of the GNU General Public License Version 2 or later (the "GPL"), |
24 |
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
25 |
* in which case the provisions of the GPL or the LGPL are applicable instead |
26 |
* of those above. If you wish to allow use of your version of this file only |
27 |
* under the terms of either the GPL or the LGPL, and not to allow others to |
28 |
* use your version of this file under the terms of the MPL, indicate your |
29 |
* decision by deleting the provisions above and replace them with the notice |
30 |
* and other provisions required by the GPL or the LGPL. If you do not delete |
31 |
* the provisions above, a recipient may use your version of this file under |
32 |
* the terms of any one of the MPL, the GPL or the LGPL. |
33 |
* |
34 |
* ***** END LICENSE BLOCK ***** */ |
35 |
|
36 |
#include "jsapi.h" |
37 |
#include "jsutil.h" |
38 |
#include "jsatom.h" |
39 |
#include "jscntxt.h" |
40 |
#include "jsdbgapi.h" |
41 |
#include "jsfun.h" |
42 |
#include "jsinterp.h" |
43 |
#include "jsobj.h" |
44 |
#include "jsscript.h" |
45 |
#include "jsstr.h" |
46 |
|
47 |
#include "jsdtracef.h" |
48 |
#include <sys/types.h> |
49 |
|
50 |
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v)) |
51 |
|
52 |
static char dempty[] = "<null>"; |
53 |
|
54 |
char * |
55 |
jsdtrace_funcclass_name(JSFunction *fun) |
56 |
{ |
57 |
return (!FUN_INTERPRETED(fun) && |
58 |
!(fun->flags & JSFUN_TRACEABLE) && |
59 |
FUN_CLASP(fun)) |
60 |
? (char *)FUN_CLASP(fun)->name |
61 |
: dempty; |
62 |
} |
63 |
|
64 |
char * |
65 |
jsdtrace_filename(JSStackFrame *fp) |
66 |
{ |
67 |
while (fp && fp->script == NULL) |
68 |
fp = fp->down; |
69 |
return (fp && fp->script && fp->script->filename) |
70 |
? (char *)fp->script->filename |
71 |
: dempty; |
72 |
} |
73 |
|
74 |
int |
75 |
jsdtrace_linenumber(JSContext *cx, JSStackFrame *fp) |
76 |
{ |
77 |
while (fp && fp->script == NULL) |
78 |
fp = fp->down; |
79 |
return (fp && fp->regs) |
80 |
? (int) js_PCToLineNumber(cx, fp->script, fp->regs->pc) |
81 |
: -1; |
82 |
} |
83 |
|
84 |
/* |
85 |
* This function is used to convert function arguments and return value (jsval) |
86 |
* into the following based on each value's type tag: |
87 |
* |
88 |
* jsval returned |
89 |
* ------------------- |
90 |
* STRING -> char * |
91 |
* INT -> int |
92 |
* DOUBLE -> double * |
93 |
* BOOLEAN -> int |
94 |
* OBJECT -> void * |
95 |
* |
96 |
* All are presented as void * for DTrace consumers to use, after shifting or |
97 |
* masking out the JavaScript type bits. This allows D scripts to use ints and |
98 |
* booleans directly and copyinstr() for string arguments, when types are known |
99 |
* beforehand. |
100 |
* |
101 |
* This is used by the function-args and function-rval probes, which also |
102 |
* provide raw (unmasked) jsvals should type info be useful from D scripts. |
103 |
*/ |
104 |
void * |
105 |
jsdtrace_jsvaltovoid(JSContext *cx, jsval argval) |
106 |
{ |
107 |
JSType type = TYPEOF(cx, argval); |
108 |
|
109 |
switch (type) { |
110 |
case JSTYPE_NULL: |
111 |
case JSTYPE_VOID: |
112 |
return (void *)JS_TYPE_STR(type); |
113 |
|
114 |
case JSTYPE_BOOLEAN: |
115 |
return (void *)JSVAL_TO_BOOLEAN(argval); |
116 |
|
117 |
case JSTYPE_STRING: |
118 |
return (void *)js_GetStringBytes(cx, JSVAL_TO_STRING(argval)); |
119 |
|
120 |
case JSTYPE_NUMBER: |
121 |
if (JSVAL_IS_INT(argval)) |
122 |
return (void *)JSVAL_TO_INT(argval); |
123 |
return JSVAL_TO_DOUBLE(argval); |
124 |
|
125 |
default: |
126 |
return JSVAL_TO_GCTHING(argval); |
127 |
} |
128 |
/* NOTREACHED */ |
129 |
} |
130 |
|
131 |
char * |
132 |
jsdtrace_function_name(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
133 |
{ |
134 |
JSAtom *atom; |
135 |
JSFrameRegs *regs; |
136 |
JSScript *script; |
137 |
jsbytecode *pc; |
138 |
char *name; |
139 |
|
140 |
atom = fun->atom; |
141 |
if (!atom) { |
142 |
if (fp->fun != fun || !fp->down) |
143 |
return dempty; |
144 |
|
145 |
regs = fp->down->regs; |
146 |
if (!regs) |
147 |
return dempty; |
148 |
|
149 |
/* |
150 |
* An anonymous function called from an active script or interpreted |
151 |
* function: try to fetch the variable or property name by which the |
152 |
* anonymous function was invoked. |
153 |
*/ |
154 |
pc = regs->pc; |
155 |
script = fp->down->script; |
156 |
switch ((JSOp) *pc) { |
157 |
case JSOP_CALL: |
158 |
case JSOP_EVAL: |
159 |
JS_ASSERT(fp->argv == regs->sp - (int)GET_ARGC(pc)); |
160 |
|
161 |
/* |
162 |
* FIXME bug 422864: update this code to use the pc stack from the |
163 |
* decompiler. |
164 |
*/ |
165 |
break; |
166 |
default: ; |
167 |
} |
168 |
|
169 |
switch ((JSOp) *pc) { |
170 |
case JSOP_CALLNAME: |
171 |
case JSOP_CALLPROP: |
172 |
case JSOP_NAME: |
173 |
case JSOP_SETNAME: |
174 |
case JSOP_GETPROP: |
175 |
case JSOP_SETPROP: |
176 |
GET_ATOM_FROM_BYTECODE(script, pc, 0, atom); |
177 |
break; |
178 |
|
179 |
case JSOP_CALLELEM: |
180 |
case JSOP_GETELEM: |
181 |
case JSOP_SETELEM: |
182 |
case JSOP_CALLGVAR: |
183 |
case JSOP_GETGVAR: |
184 |
case JSOP_SETGVAR: |
185 |
case JSOP_CALLARG: |
186 |
case JSOP_CALLLOCAL: |
187 |
/* FIXME: try to recover a name from these ops. */ |
188 |
/* FALL THROUGH */ |
189 |
|
190 |
default: |
191 |
return dempty; |
192 |
} |
193 |
} |
194 |
|
195 |
name = (char *)js_GetStringBytes(cx, ATOM_TO_STRING(atom)); |
196 |
return name ? name : dempty; |
197 |
} |
198 |
|
199 |
/* |
200 |
* These functions call the DTrace macros for the JavaScript USDT probes. |
201 |
* Originally this code was inlined in the JavaScript code; however since |
202 |
* a number of operations are called, these have been placed into functions |
203 |
* to reduce any negative compiler optimization effect that the addition of |
204 |
* a number of usually unused lines of code would cause. |
205 |
*/ |
206 |
void |
207 |
jsdtrace_function_entry(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
208 |
{ |
209 |
JAVASCRIPT_FUNCTION_ENTRY( |
210 |
jsdtrace_filename(fp), |
211 |
jsdtrace_funcclass_name(fun), |
212 |
jsdtrace_function_name(cx, fp, fun) |
213 |
); |
214 |
} |
215 |
|
216 |
void |
217 |
jsdtrace_function_info(JSContext *cx, JSStackFrame *fp, JSStackFrame *dfp, |
218 |
JSFunction *fun) |
219 |
{ |
220 |
JAVASCRIPT_FUNCTION_INFO( |
221 |
jsdtrace_filename(fp), |
222 |
jsdtrace_funcclass_name(fun), |
223 |
jsdtrace_function_name(cx, fp, fun), |
224 |
fp->script->lineno, |
225 |
jsdtrace_filename(dfp), |
226 |
jsdtrace_linenumber(cx, dfp) |
227 |
); |
228 |
} |
229 |
|
230 |
void |
231 |
jsdtrace_function_args(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
232 |
{ |
233 |
JAVASCRIPT_FUNCTION_ARGS( |
234 |
jsdtrace_filename(fp), |
235 |
jsdtrace_funcclass_name(fun), |
236 |
jsdtrace_function_name(cx, fp, fun), |
237 |
fp->argc, (void *)fp->argv, |
238 |
(fp->argc > 0) ? jsdtrace_jsvaltovoid(cx, fp->argv[0]) : 0, |
239 |
(fp->argc > 1) ? jsdtrace_jsvaltovoid(cx, fp->argv[1]) : 0, |
240 |
(fp->argc > 2) ? jsdtrace_jsvaltovoid(cx, fp->argv[2]) : 0, |
241 |
(fp->argc > 3) ? jsdtrace_jsvaltovoid(cx, fp->argv[3]) : 0, |
242 |
(fp->argc > 4) ? jsdtrace_jsvaltovoid(cx, fp->argv[4]) : 0 |
243 |
); |
244 |
} |
245 |
|
246 |
void |
247 |
jsdtrace_function_rval(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
248 |
{ |
249 |
JAVASCRIPT_FUNCTION_RVAL( |
250 |
jsdtrace_filename(fp), |
251 |
jsdtrace_funcclass_name(fun), |
252 |
jsdtrace_function_name(cx, fp, fun), |
253 |
jsdtrace_linenumber(cx, fp), (void *)fp->rval, |
254 |
jsdtrace_jsvaltovoid(cx, fp->rval) |
255 |
); |
256 |
} |
257 |
|
258 |
void |
259 |
jsdtrace_function_return(JSContext *cx, JSStackFrame *fp, JSFunction *fun) |
260 |
{ |
261 |
JAVASCRIPT_FUNCTION_RETURN( |
262 |
jsdtrace_filename(fp), |
263 |
jsdtrace_funcclass_name(fun), |
264 |
jsdtrace_function_name(cx, fp, fun) |
265 |
); |
266 |
} |
267 |
|
268 |
void |
269 |
jsdtrace_object_create_start(JSStackFrame *fp, JSClass *clasp) |
270 |
{ |
271 |
JAVASCRIPT_OBJECT_CREATE_START(jsdtrace_filename(fp), (char *)clasp->name); |
272 |
} |
273 |
|
274 |
void |
275 |
jsdtrace_object_create_done(JSStackFrame *fp, JSClass *clasp) |
276 |
{ |
277 |
JAVASCRIPT_OBJECT_CREATE_DONE(jsdtrace_filename(fp), (char *)clasp->name); |
278 |
} |
279 |
|
280 |
void |
281 |
jsdtrace_object_create(JSContext *cx, JSClass *clasp, JSObject *obj) |
282 |
{ |
283 |
JAVASCRIPT_OBJECT_CREATE( |
284 |
jsdtrace_filename(cx->fp), |
285 |
(char *)clasp->name, |
286 |
(uintptr_t)obj, |
287 |
jsdtrace_linenumber(cx, cx->fp) |
288 |
); |
289 |
} |
290 |
|
291 |
void |
292 |
jsdtrace_object_finalize(JSObject *obj) |
293 |
{ |
294 |
JSClass *clasp; |
295 |
|
296 |
clasp = LOCKED_OBJ_GET_CLASS(obj); |
297 |
|
298 |
/* the first arg is NULL - reserved for future use (filename?) */ |
299 |
JAVASCRIPT_OBJECT_FINALIZE(NULL, (char *)clasp->name, (uintptr_t)obj); |
300 |
} |
301 |
|
302 |
void |
303 |
jsdtrace_execute_start(JSScript *script) |
304 |
{ |
305 |
JAVASCRIPT_EXECUTE_START( |
306 |
script->filename ? (char *)script->filename : dempty, |
307 |
script->lineno |
308 |
); |
309 |
} |
310 |
|
311 |
void |
312 |
jsdtrace_execute_done(JSScript *script) |
313 |
{ |
314 |
JAVASCRIPT_EXECUTE_DONE( |
315 |
script->filename ? (char *)script->filename : dempty, |
316 |
script->lineno |
317 |
); |
318 |
} |