Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
v8ustack.d
Go to the documentation of this file.
1 /*
2  * V8 DTrace ustack helper for annotating native stack traces with JavaScript
3  * function names. We start with a frame pointer (arg1) and emit a string
4  * describing the current function. We do this by chasing pointers to extract
5  * the function's name (if any) and the filename and line number where the
6  * function is defined.
7  *
8  * To use the helper, run node, then use the jstack() DTrace action to capture
9  * a JavaScript stacktrace. You may need to tune the dtrace_helper_actions_max
10  * kernel variable to 128.
11  */
12 
13 #include <v8constants.h>
14 #include <v8abbr.h>
15 
16 /*
17  * V8 represents small integers (SMI) using the upper 31 bits of a 32/64-bit
18  * value. To extract the actual integer value, we must shift it over.
19  */
20 #define IS_SMI(value) \
21  ((value & V8_SmiTagMask) == V8_SmiTag)
22 #define SMI_VALUE(value) \
23  ((uint32_t) ((value) >> V8_SmiValueShift))
24 
25 /*
26  * Heap objects usually start off with a Map pointer, itself another heap
27  * object. However, during garbage collection, the low order bits of the
28  * pointer (which are normally 01) are used to record GC state. Of course, we
29  * have no idea if we're in GC or not, so we must always normalize the pointer.
30  */
31 #define V8_MAP_PTR(ptr) \
32  ((ptr & ~V8_HeapObjectTagMask) | V8_HeapObjectTag)
33 
34 #define V8_TYPE_SCRIPT(type) \
35  ((type) == V8_IT_SCRIPT)
36 
37 /*
38  * Determine the encoding and representation of a V8 string.
39  */
40 #define V8_TYPE_STRING(type) \
41  (((type) & V8_IsNotStringMask) == V8_StringTag)
42 
43 #define V8_STRENC_ASCII(type) \
44  (((type) & V8_StringEncodingMask) == V8_AsciiStringTag)
45 
46 #define V8_STRREP_SEQ(type) \
47  (((type) & V8_StringRepresentationMask) == V8_SeqStringTag)
48 #define V8_STRREP_CONS(type) \
49  (((type) & V8_StringRepresentationMask) == V8_ConsStringTag)
50 #define V8_STRREP_EXT(type) \
51  (((type) & V8_StringRepresentationMask) == V8_ExternalStringTag)
52 
53 /*
54  * String type predicates
55  */
56 #define ASCII_SEQSTR(value) \
57  (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value))
58 
59 #define TWOBYTE_SEQSTR(value) \
60  (V8_TYPE_STRING(value) && !V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value))
61 
62 #define IS_CONSSTR(value) \
63  (V8_TYPE_STRING(value) && V8_STRREP_CONS(value))
64 
65 #define ASCII_EXTSTR(value) \
66  (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_EXT(value))
67 
68 /*
69  * General helper macros
70  */
71 #define COPYIN_UINT8(addr) (*(uint8_t*) copyin((addr), sizeof(uint8_t)))
72 #define COPYIN_UINT32(addr) (*(uint32_t*) copyin((addr), sizeof(uint32_t)))
73 #define COPYIN_UINT64(addr) (*(uint64_t*) copyin((addr), sizeof(uint64_t)))
74 
75 #if defined(__i386)
76 # define COPYIN_PTR(addr) COPYIN_UINT32(addr)
77 # define off_t uint32_t
78 # define APPEND_PTR(p) APPEND_PTR_32(p)
79 #else
80 # define COPYIN_PTR(addr) COPYIN_UINT64(addr)
81 # define off_t uint64_t
82 # define APPEND_PTR(p) APPEND_PTR_64(p)
83 #endif
84 
85 #define APPEND_CHR(c) (this->buf[this->off++] = (c))
86 #define APPEND_CHR4(s0, s1, s2, s3) \
87  APPEND_CHR(s0); \
88  APPEND_CHR(s1); \
89  APPEND_CHR(s2); \
90  APPEND_CHR(s3);
91 #define APPEND_CHR8(s0, s1, s2, s3, s4, s5, s6, s7) \
92  APPEND_CHR4(s0, s1, s2, s3) \
93  APPEND_CHR4(s4, s5, s6, s7)
94 
95 #define APPEND_DGT(i, d) \
96  (((i) / (d)) ? APPEND_CHR('0' + ((i)/(d) % 10)) : 0)
97 
98 #define APPEND_NUM(i) \
99  APPEND_DGT((i), 100000); \
100  APPEND_DGT((i), 10000); \
101  APPEND_DGT((i), 1000); \
102  APPEND_DGT((i), 100); \
103  APPEND_DGT((i), 10); \
104  APPEND_DGT((i), 1);
105 
106 #define APPEND_HEX(d) \
107  APPEND_CHR((d) < 10 ? '0' + (d) : 'a' - 10 + (d))
108 
109 #define APPEND_PTR_32(p) \
110  APPEND_HEX((p >> 28) & 0xf); \
111  APPEND_HEX((p >> 24) & 0xf); \
112  APPEND_HEX((p >> 20) & 0xf); \
113  APPEND_HEX((p >> 16) & 0xf); \
114  APPEND_HEX((p >> 12) & 0xf); \
115  APPEND_HEX((p >> 8) & 0xf); \
116  APPEND_HEX((p >> 4) & 0xf); \
117  APPEND_HEX((p) & 0xf);
118 
119 #define APPEND_PTR_64(p) \
120  APPEND_PTR_32(p >> 32) \
121  APPEND_PTR_32(p)
122 
123 /*
124  * The following macros are used to output ASCII SeqStrings, ConsStrings, and
125  * Node.js ExternalStrings. To represent each string, we use three fields:
126  *
127  * "str": a pointer to the string itself
128  *
129  * "len": the string length
130  *
131  * "attrs": the type identifier for the string, which indicates the
132  * encoding and representation. We're only interested in strings
133  * whose representation is one of:
134  *
135  * SeqOneByteString stored directly as a char array inside the object
136  *
137  * SeqTwoByteString stored as a UTF-16 char array inside the object
138  *
139  * ConsString pointer to two strings that should be concatenated
140  *
141  * ExternalString pointer to a char* outside the V8 heap
142  */
143 
144 /*
145  * Load "len" and "attrs" for the given "str".
146  */
147 #define LOAD_STRFIELDS(str, len, attrs) \
148  len = SMI_VALUE(COPYIN_PTR(str + V8_OFF_STR_LENGTH)); \
149  this->map = V8_MAP_PTR(COPYIN_PTR(str + V8_OFF_HEAPOBJ_MAP)); \
150  attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS);
151 
152 #define APPEND_SEQSTR(str, len, attrs) \
153  APPEND_SEQONEBYTESTR(str, len, attrs) \
154  APPEND_SEQTWOBYTESTR(str, len, attrs)
155 
156 /*
157  * Print out the given SeqOneByteString, or do nothing if the string is not an ASCII
158  * SeqOneByteString.
159  */
160 #define APPEND_SEQONEBYTESTR(str, len, attrs) \
161  dtrace:helper:ustack: \
162  /!this->done && len > 0 && ASCII_SEQSTR(attrs)/ \
163  { \
164  copyinto(str + V8_OFF_STR_CHARS, len, this->buf + this->off); \
165  this->off += len; \
166  }
167 
168 /*
169  * LOOP_ITER: macro to paste "block" while "ivar" is less than "dynmax" and
170  * "statmax". The subsequent LOOP_{4,8} macros facilitate pasting the same
171  * thing 4 and 8 times, respectively. Like much of the rest of the code in this
172  * file, this is regrettably necessary given the constraints under which we're
173  * expected to run.
174  */
175 #define LOOP_ITER(ivar, dynmax, statmax, block) \
176  ((ivar) < (dynmax)) && ((ivar) < (statmax)) && (block); (ivar)++;
177 
178 #define LOOP_4(block) \
179  block \
180  block \
181  block \
182  block \
183 
184 #define LOOP_8(block) \
185  LOOP_4(block) \
186  LOOP_4(block)
187 
188 /*
189  * Print out the given SeqTwoByteString, or do nothing if the string is not an ASCII
190  * SeqTwoByteString. NOTE: if you bump MAX_TWOBYTESTR_CHARS, you'll also need
191  * to modify the LOOP_* macro calls below to match.
192  */
193 #define MAX_TWOBYTESTR_CHARS 128
194 #define MAX_TWOBYTESTR_BYTES (2 * MAX_TWOBYTESTR_CHARS)
195 #define TO_ASCII(c) ((c) < 128 ? (c) : '?')
196 
197 #define APPEND_SEQTWOBYTESTR(str, len, attrs) \
198  dtrace:helper:ustack: \
199  /!this->done && len > 0 && TWOBYTE_SEQSTR(attrs)/ \
200  { \
201  this->i = 0; \
202  this->stbuf = (uint16_t *)alloca(MAX_TWOBYTESTR_BYTES + 2); \
203  copyinto(str + V8_OFF_TWOBYTESTR_CHARS, \
204  MAX_TWOBYTESTR_BYTES, this->stbuf); \
205  this->stbuf[MAX_TWOBYTESTR_BYTES - 1] = '\0'; \
206  this->stbuf[MAX_TWOBYTESTR_BYTES] = '\0'; \
207  \
208  LOOP_8(LOOP_8(LOOP_4(LOOP_ITER(this->i, len, \
209  MAX_TWOBYTESTR_CHARS, \
210  APPEND_CHR(TO_ASCII(this->stbuf[this->i])))))) \
211  \
212  this->i = 0; \
213  this->stbuf = 0; \
214  }
215 
216 /*
217  * Print out the given Node.js ExternalString, or do nothing if the string is
218  * not an ASCII ExternalString.
219  */
220 #define APPEND_NODESTR(str, len, attrs) \
221  dtrace:helper:ustack: \
222  /!this->done && len > 0 && ASCII_EXTSTR(attrs)/ \
223  { \
224  this->resource = COPYIN_PTR(str + V8_OFF_EXTSTR_RSRC); \
225  this->dataptr = COPYIN_PTR(this->resource + NODE_OFF_EXTSTR_DATA); \
226  copyinto(this->dataptr, len, this->buf + this->off); \
227  this->off += len; \
228  }
229 
230 /*
231  * Recall that each ConsString points to two other strings which are
232  * semantically concatenated. Of course, these strings may themselves by
233  * ConsStrings, but in D we can only expand this recursion to a finite level.
234  * Thankfully, function and script names are generally not more than a few
235  * levels deep, so we unroll the expansion up to three levels. Even this is
236  * pretty hairy: we use strings "s0", ..., "s13", (each with "str", "len", and
237  * "attr" fields -- see above) to store the expanded strings. We expand the
238  * original string into s0 and s7, then s0 into s1 and s4, etc:
239  *
240  *
241  * +---- str ----+
242  * / \ <-- 1st expansion
243  * / \
244  * s0 s7
245  * / \ / \
246  * / \ / \ <-- 2nd expansion
247  * / \ / \
248  * s1 s4 s8 s11
249  * / \ / \ / \ / \ <-- 3rd expansion
250  * s2 s3 s5 s6 s9 s10 s12 s13
251  *
252  * Of course, for a given string, any of these expansions may not be needed.
253  * For example, we may expand str and find that s0 is already a SeqString,
254  * while s7 requires further expansion. So when we expand a ConsString, we
255  * zero the length of the string itself, and then at the end we print out
256  * all non-zero-length strings in order (including both internal nodes and
257  * leafs in the tree above) to get the final output.
258  */
259 #define EXPAND_START() \
260  dtrace:helper:ustack: \
261  /!this->done/ \
262  { \
263  this->s0str = this->s1str = this->s2str = (off_t) 0; \
264  this->s3str = this->s4str = this->s5str = (off_t) 0; \
265  this->s6str = this->s7str = this->s8str = (off_t) 0; \
266  this->s9str = this->s10str = this->s11str = (off_t) 0; \
267  this->s12str = this->s13str = (off_t) 0; \
268  \
269  this->s0len = this->s1len = this->s2len = (off_t) 0; \
270  this->s3len = this->s4len = this->s5len = (off_t) 0; \
271  this->s6len = this->s7len = this->s8len = (off_t) 0; \
272  this->s9len = this->s10len = this->s11len = (off_t) 0; \
273  this->s12len = this->s13len = (off_t) 0; \
274  \
275  this->s0attrs = this->s1attrs = this->s2attrs = 0; \
276  this->s3attrs = this->s4attrs = this->s5attrs = 0; \
277  this->s6attrs = this->s7attrs = this->s8attrs = 0; \
278  this->s9attrs = this->s10attrs = this->s11attrs = 0; \
279  this->s12attrs = this->s13attrs = 0; \
280  }
281 
282 /*
283  * Expand the ConsString "str" (represented by "str", "len", and "attrs") into
284  * strings "s1" (represented by "s1s", "s1l", and "s1a") and "s2" (represented
285  * by "s2s", "s2l", "s2a"). If "str" is not a ConsString, do nothing.
286  */
287 #define EXPAND_STR(str, len, attrs, s1s, s1l, s1a, s2s, s2l, s2a) \
288  dtrace:helper:ustack: \
289  /!this->done && len > 0 && IS_CONSSTR(attrs)/ \
290  { \
291  len = 0; \
292  \
293  s1s = COPYIN_PTR(str + V8_OFF_CONSSTR_CAR); \
294  LOAD_STRFIELDS(s1s, s1l, s1a) \
295  \
296  s2s = COPYIN_PTR(str + V8_OFF_CONSSTR_CDR); \
297  LOAD_STRFIELDS(s2s, s2l, s2a) \
298  }
299 
300 /*
301  * Print out a ConsString by expanding it up to three levels and printing out
302  * the resulting SeqStrings.
303  */
304 #define APPEND_CONSSTR(str, len, attrs) \
305  EXPAND_START() \
306  EXPAND_STR(str, len, attrs, \
307  this->s0str, this->s0len, this->s0attrs, \
308  this->s7str, this->s7len, this->s7attrs) \
309  EXPAND_STR(this->s0str, this->s0len, this->s0attrs, \
310  this->s1str, this->s1len, this->s1attrs, \
311  this->s4str, this->s4len, this->s4attrs) \
312  EXPAND_STR(this->s1str, this->s1len, this->s1attrs, \
313  this->s2str, this->s2len, this->s2attrs, \
314  this->s3str, this->s3len, this->s3attrs) \
315  EXPAND_STR(this->s4str, this->s4len, this->s4attrs, \
316  this->s5str, this->s5len, this->s5attrs, \
317  this->s6str, this->s6len, this->s6attrs) \
318  EXPAND_STR(this->s7str, this->s7len, this->s7attrs, \
319  this->s8str, this->s8len, this->s8attrs, \
320  this->s11str, this->s11len, this->s11attrs) \
321  EXPAND_STR(this->s8str, this->s8len, this->s8attrs, \
322  this->s9str, this->s9len, this->s9attrs, \
323  this->s10str, this->s10len, this->s10attrs) \
324  EXPAND_STR(this->s11str, this->s11len, this->s11attrs, \
325  this->s12str, this->s12len, this->s12attrs, \
326  this->s13str, this->s13len, this->s13attrs) \
327  \
328  APPEND_SEQSTR(str, len, attrs) \
329  APPEND_SEQSTR(this->s0str, this->s0len, this->s0attrs) \
330  APPEND_SEQSTR(this->s1str, this->s1len, this->s1attrs) \
331  APPEND_SEQSTR(this->s2str, this->s2len, this->s2attrs) \
332  APPEND_SEQSTR(this->s3str, this->s3len, this->s3attrs) \
333  APPEND_SEQSTR(this->s4str, this->s4len, this->s4attrs) \
334  APPEND_SEQSTR(this->s5str, this->s5len, this->s5attrs) \
335  APPEND_SEQSTR(this->s6str, this->s6len, this->s6attrs) \
336  APPEND_SEQSTR(this->s7str, this->s7len, this->s7attrs) \
337  APPEND_SEQSTR(this->s8str, this->s8len, this->s8attrs) \
338  APPEND_SEQSTR(this->s9str, this->s9len, this->s9attrs) \
339  APPEND_SEQSTR(this->s10str, this->s10len, this->s10attrs) \
340  APPEND_SEQSTR(this->s11str, this->s11len, this->s11attrs) \
341  APPEND_SEQSTR(this->s12str, this->s12len, this->s12attrs) \
342  APPEND_SEQSTR(this->s13str, this->s13len, this->s13attrs) \
343 
344 
345 /*
346  * Print out the given SeqString, ConsString, or ExternalString.
347  * APPEND_CONSSTR implicitly handles SeqStrings as the degenerate case of an
348  * expanded ConsString.
349  */
350 #define APPEND_V8STR(str, len, attrs) \
351  APPEND_CONSSTR(str, len, attrs) \
352  APPEND_NODESTR(str, len, attrs)
353 
354 /*
355  * In this first clause we initialize all variables. We must explicitly clear
356  * them because they may contain values left over from previous iterations.
357  */
358 dtrace:helper:ustack:
359 {
360  /* input */
361  this->fp = arg1;
362 
363  /* output/flow control */
364  this->buf = (char*) alloca(128);
365  this->off = 0;
366  this->done = 0;
367 
368  /* program state */
369  this->ctx = (off_t) 0;
370  this->marker = (off_t) 0;
371  this->func = (off_t) 0;
372  this->shared = (off_t) 0;
373  this->map = (off_t) 0;
374  this->attrs = 0;
375  this->funcnamestr = (off_t) 0;
376  this->funcnamelen = 0;
377  this->funcnameattrs = 0;
378  this->script = (off_t) 0;
379  this->scriptattrs = 0;
380  this->scriptnamestr = (off_t) 0;
381  this->scriptnamelen = 0;
382  this->scriptnameattrs = 0;
383  this->position = 0;
384  this->line_ends = (off_t) 0;
385  this->le_attrs = 0;
386 
387  /* binary search fields */
388  this->bsearch_min = 0;
389  this->bsearch_max = 0;
390  this->ii = 0;
391 }
392 
393 /*
394  * Like V8, we first check if we've got an ArgumentsAdaptorFrame. We've got
395  * nothing to add for such frames, so we bail out quickly.
396  */
397 dtrace:helper:ustack:
398 {
399  this->ctx = COPYIN_PTR(this->fp + V8_OFF_FP_CONTEXT);
400 }
401 
402 dtrace:helper:ustack:
403 /IS_SMI(this->ctx) && SMI_VALUE(this->ctx) == V8_FT_ADAPTOR/
404 {
405  this->done = 1;
406  APPEND_CHR8('<','<',' ','a','d','a','p','t');
407  APPEND_CHR8('o','r',' ','>','>','\0','\0','\0');
408  stringof(this->buf);
409 }
410 
411 /*
412  * Check for other common frame types for which we also have nothing to add.
413  */
414 dtrace:helper:ustack:
415 /!this->done/
416 {
417  this->marker = COPYIN_PTR(this->fp + V8_OFF_FP_CONTEXT);
418 }
419 
420 dtrace:helper:ustack:
421 /!this->done && IS_SMI(this->marker) &&
422  SMI_VALUE(this->marker) == V8_FT_ENTRY/
423 {
424  this->done = 1;
425  APPEND_CHR8('<','<',' ','e','n','t','r','y');
426  APPEND_CHR4(' ','>','>','\0');
427  stringof(this->buf);
428 }
429 
430 dtrace:helper:ustack:
431 /!this->done && IS_SMI(this->marker) &&
432  SMI_VALUE(this->marker) == V8_FT_ENTRYCONSTRUCT/
433 {
434  this->done = 1;
435  APPEND_CHR8('<','<',' ','e','n','t','r','y');
436  APPEND_CHR8('_','c','o','n','s','t','r','u');
437  APPEND_CHR4('t',' ','>','>');
438  APPEND_CHR('\0');
439  stringof(this->buf);
440 }
441 
442 dtrace:helper:ustack:
443 /!this->done && IS_SMI(this->marker) &&
444  SMI_VALUE(this->marker) == V8_FT_EXIT/
445 {
446  this->done = 1;
447  APPEND_CHR8('<','<',' ','e','x','i','t',' ');
448  APPEND_CHR4('>','>','\0','\0');
449  stringof(this->buf);
450 }
451 
452 dtrace:helper:ustack:
453 /!this->done && IS_SMI(this->marker) &&
454  SMI_VALUE(this->marker) == V8_FT_INTERNAL/
455 {
456  this->done = 1;
457  APPEND_CHR8('<','<',' ','i','n','t','e','r');
458  APPEND_CHR8('n','a','l',' ','>','>','\0','\0');
459  stringof(this->buf);
460 }
461 
462 dtrace:helper:ustack:
463 /!this->done && IS_SMI(this->marker) &&
464  SMI_VALUE(this->marker) == V8_FT_CONSTRUCT/
465 {
466  this->done = 1;
467  APPEND_CHR8('<','<',' ','c','o','n','s','t');
468  APPEND_CHR8('r','u','c','t','o','r',' ','>');
469  APPEND_CHR4('>','\0','\0','\0');
470  stringof(this->buf);
471 }
472 
473 dtrace:helper:ustack:
474 /!this->done && IS_SMI(this->marker) &&
475  SMI_VALUE(this->marker) == V8_FT_STUB/
476 {
477  this->done = 1;
478  APPEND_CHR8('<','<',' ','s','t','u','b',' ');
479  APPEND_CHR4('>','>','\0','\0');
480  stringof(this->buf);
481 }
482 
483 /*
484  * Now check for internal frames that we can only identify by seeing that
485  * there's a Code object where there would be a JSFunction object for a
486  * JavaScriptFrame.
487  */
488 dtrace:helper:ustack:
489 /!this->done/
490 {
491  this->func = COPYIN_PTR(this->fp + V8_OFF_FP_FUNC);
492  this->map = V8_MAP_PTR(COPYIN_PTR(this->func + V8_OFF_HEAPOBJ_MAP));
493  this->attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS);
494 }
495 
496 dtrace:helper:ustack:
497 /!this->done && this->attrs == V8_IT_CODE/
498 {
499  this->done = 1;
500  APPEND_CHR8('<','<',' ','i','n','t','e','r');
501  APPEND_CHR8('n','a','l',' ','c','o','d','e');
502  APPEND_CHR4(' ','>','>','\0');
503  stringof(this->buf);
504 }
505 
506 /*
507  * At this point, we're either looking at a JavaScriptFrame or an
508  * OptimizedFrame. For now, we assume JavaScript and start by grabbing the
509  * function name.
510  */
511 dtrace:helper:ustack:
512 /!this->done/
513 {
514  this->map = 0;
515  this->attrs = 0;
516 
517  this->shared = COPYIN_PTR(this->func + V8_OFF_FUNC_SHARED);
518  this->funcnamestr = COPYIN_PTR(this->shared + V8_OFF_SHARED_NAME);
520  this->funcnameattrs);
521 }
522 
523 dtrace:helper:ustack:
524 /!this->done && this->funcnamelen == 0/
525 {
526  /*
527  * This is an anonymous function, but if it was invoked as a method of
528  * some object then V8 will have computed an inferred name that we can
529  * include in the stack trace.
530  */
531  APPEND_CHR8('(','a','n','o','n',')',' ','a');
532  APPEND_CHR('s');
533  APPEND_CHR(' ');
534 
535  this->funcnamestr = COPYIN_PTR(this->shared + V8_OFF_SHARED_IDENT);
536  LOAD_STRFIELDS(this->funcnamestr, this->funcnamelen,
537  this->funcnameattrs);
538 }
539 
540 dtrace:helper:ustack:
541 /!this->done && this->funcnamelen == 0/
542 {
544  APPEND_CHR4('a','n','o','n');
545  APPEND_CHR(')');
546 }
547 
548 APPEND_V8STR(this->funcnamestr, this->funcnamelen, this->funcnameattrs)
549 
550 /*
551  * Now look for the name of the script where the function was defined. The
552  * "script" itself may be undefined for special functions like "RegExp".
553  */
554 dtrace:helper:ustack:
555 /!this->done/
556 {
557  this->script = COPYIN_PTR(this->shared + V8_OFF_SHARED_SCRIPT);
558  this->map = V8_MAP_PTR(COPYIN_PTR(this->script + V8_OFF_HEAPOBJ_MAP));
559  this->scriptattrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS);
560 }
561 
562 dtrace:helper:ustack:
563 /!this->done && !V8_TYPE_SCRIPT(this->scriptattrs)/
564 {
565  APPEND_CHR('\0');
566  this->done = 1;
567  stringof(this->buf);
568 }
569 
570 
571 dtrace:helper:ustack:
572 /!this->done/
573 {
574  this->scriptnamestr = COPYIN_PTR(this->script + V8_OFF_SCRIPT_NAME);
576  this->scriptnameattrs);
577 }
578 
579 dtrace:helper:ustack:
580 /!this->done && this->scriptnamelen != 0/
581 {
582  APPEND_CHR4(' ','a','t',' ');
583 }
584 
586 
587 /*
588  * Now look for file position and line number information.
589  */
590 dtrace:helper:ustack:
591 /!this->done/
592 {
593  this->position = COPYIN_UINT32(this->shared + V8_OFF_SHARED_FUNTOK);
594  this->line_ends = COPYIN_PTR(this->script + V8_OFF_SCRIPT_LENDS);
595  this->map = V8_MAP_PTR(COPYIN_PTR(this->line_ends + V8_OFF_HEAPOBJ_MAP));
596  this->le_attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS);
597 }
598 
599 dtrace:helper:ustack:
600 /!this->done && this->le_attrs != V8_IT_FIXEDARRAY && this->position == 0/
601 {
602  APPEND_CHR('\0');
603  this->done = 1;
604  stringof(this->buf);
605 }
606 
607 dtrace:helper:ustack:
608 /!this->done && this->le_attrs != V8_IT_FIXEDARRAY/
609 {
610  /*
611  * If the line number array was not a valid FixedArray, it's probably
612  * undefined because V8 has not had to compute it yet. In this case we
613  * just show the raw position and call it a day.
614  */
615  APPEND_CHR4(' ','p','o','s');
616  APPEND_CHR(' ');
617  APPEND_NUM(SMI_VALUE(this->position));
618  APPEND_CHR('\0');
619  this->done = 1;
620  stringof(this->buf);
621 }
622 
623 /*
624  * At this point, we've got both a position in the script and an array
625  * describing where each line of the file ends. We can use this to compute the
626  * line number by binary searching the array. (This is also what V8 does when
627  * computing stack traces.)
628  */
629 dtrace:helper:ustack:
630 /!this->done/
631 {
632  /* initialize binary search */
633  this->bsearch_line = this->position <
634  SMI_VALUE(COPYIN_PTR(this->line_ends + V8_OFF_FA_DATA)) ? 1 : 0;
635  this->bsearch_min = 0;
636  this->bsearch_max = this->bsearch_line != 0 ? 0 :
637  SMI_VALUE(COPYIN_PTR(this->line_ends + V8_OFF_FA_SIZE)) - 1;
638 }
639 
640 /*
641  * Of course, we can't iterate the binary search indefinitely, so we hardcode 15
642  * iterations. That's enough to precisely identify the line number in files up
643  * to 32768 lines of code.
644  */
645 #define BSEARCH_LOOP \
646  dtrace:helper:ustack: \
647  /!this->done && this->bsearch_max >= 1/ \
648  { \
649  this->ii = (this->bsearch_min + this->bsearch_max) >> 1; \
650  } \
651  \
652  dtrace:helper:ustack: \
653  /!this->done && this->bsearch_max >= 1 && \
654  this->position > SMI_VALUE( \
655  COPYIN_PTR(this->line_ends + V8_OFF_FA_DATA + \
656  this->ii * sizeof (uint32_t)))/ \
657  { \
658  this->bsearch_min = this->ii + 1; \
659  } \
660  \
661  dtrace:helper:ustack: \
662  /!this->done && this->bsearch_max >= 1 && \
663  this->position <= SMI_VALUE( \
664  COPYIN_PTR(this->line_ends + V8_OFF_FA_DATA + \
665  (this->ii - 1) * sizeof (uint32_t)))/ \
666  { \
667  this->bsearch_max = this->ii - 1; \
668  }
669 
670 BSEARCH_LOOP
671 BSEARCH_LOOP
672 BSEARCH_LOOP
673 BSEARCH_LOOP
674 BSEARCH_LOOP
675 BSEARCH_LOOP
676 BSEARCH_LOOP
677 BSEARCH_LOOP
678 BSEARCH_LOOP
679 BSEARCH_LOOP
680 BSEARCH_LOOP
681 BSEARCH_LOOP
682 BSEARCH_LOOP
683 BSEARCH_LOOP
684 BSEARCH_LOOP
685 
686 dtrace:helper:ustack:
687 /!this->done && !this->bsearch_line/
688 {
689  this->bsearch_line = this->ii + 1;
690 }
691 
692 dtrace:helper:ustack:
693 /!this->done/
694 {
696  APPEND_CHR4('l','i','n','e');
697  APPEND_CHR(' ');
698  APPEND_NUM(this->bsearch_line);
699  APPEND_CHR('\0');
700  this->done = 1;
701  stringof(this->buf);
702 }
703 
704 /* vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */
this func
Definition: v8ustack.d:371
APPEND_CHR8('<','<',' ', 'a', 'd', 'a', 'p', 't')
#define V8_IT_FIXEDARRAY
Definition: v8abbr.h:67
#define V8_FT_EXIT
Definition: v8abbr.h:39
#define V8_FT_STUB
Definition: v8abbr.h:45
#define V8_OFF_FA_SIZE
Definition: v8abbr.h:110
#define V8_OFF_SHARED_IDENT
Definition: v8abbr.h:90
#define V8_OFF_FA_DATA
Definition: v8abbr.h:112
this buf
Definition: v8ustack.d:364
APPEND_CHR('\0')
LOAD_STRFIELDS(this->funcnamestr, this->funcnamelen, this->funcnameattrs)
#define V8_OFF_SHARED_FUNTOK
Definition: v8abbr.h:94
this script
Definition: v8ustack.d:378
#define V8_FT_ADAPTOR
Definition: v8abbr.h:44
#define V8_OFF_SCRIPT_NAME
Definition: v8abbr.h:96
#define V8_OFF_FP_FUNC
Definition: v8abbr.h:32
this scriptattrs
Definition: v8ustack.d:379
#define V8_OFF_SCRIPT_LENDS
Definition: v8abbr.h:98
this ii
Definition: v8ustack.d:390
this attrs
Definition: v8ustack.d:374
APPEND_V8STR(this->funcnamestr, this->funcnamelen, this->funcnameattrs) dtrace
Definition: v8ustack.d:548
this funcnamestr
Definition: v8ustack.d:375
#define V8_OFF_MAP_ATTRS
Definition: v8abbr.h:116
#define V8_FT_ENTRY
Definition: v8abbr.h:37
#define V8_IT_CODE
Definition: v8abbr.h:68
this scriptnameattrs
Definition: v8ustack.d:382
this scriptnamestr
Definition: v8ustack.d:380
this done
Definition: v8ustack.d:366
this scriptnamelen
Definition: v8ustack.d:381
this bsearch_max
Definition: v8ustack.d:389
this bsearch_min
Definition: v8ustack.d:388
this shared
Definition: v8ustack.d:372
APPEND_CHR4(' ','>','>','\0')
this position
Definition: v8ustack.d:383
#define V8_OFF_FUNC_SHARED
Definition: v8abbr.h:86
APPEND_NUM(SMI_VALUE(this->position))
#define V8_OFF_SHARED_NAME
Definition: v8abbr.h:88
this le_attrs
Definition: v8ustack.d:385
this marker
Definition: v8ustack.d:370
#define V8_OFF_FP_CONTEXT
Definition: v8abbr.h:33
this funcnameattrs
Definition: v8ustack.d:377
this map
Definition: v8ustack.d:373
stringof(this->buf)
#define V8_FT_CONSTRUCT
Definition: v8abbr.h:43
BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP BSEARCH_LOOP dtrace
Definition: v8ustack.d:689
this line_ends
Definition: v8ustack.d:384
#define V8_FT_INTERNAL
Definition: v8abbr.h:42
this funcnamelen
Definition: v8ustack.d:376
#define V8_FT_ENTRYCONSTRUCT
Definition: v8abbr.h:38
this ctx
Definition: v8ustack.d:369
#define V8_OFF_SHARED_SCRIPT
Definition: v8abbr.h:92
#define V8_OFF_HEAPOBJ_MAP
Definition: v8abbr.h:114
this off
Definition: v8ustack.d:365