mirror of https://github.com/lukechilds/node.git
Dave Pacheco
13 years ago
committed by
Ryan Dahl
3 changed files with 737 additions and 4 deletions
@ -0,0 +1,83 @@ |
|||||
|
/*
|
||||
|
* The following offsets are derived from the V8 3.6.6.14 source. A future |
||||
|
* version of this helper will automatically generate this file based on the |
||||
|
* debug metadata included in libv8. See v8ustack.d for details on how these |
||||
|
* values are used. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef V8_CONSTANTS_H |
||||
|
#define V8_CONSTANTS_H |
||||
|
|
||||
|
#if defined(__i386) |
||||
|
|
||||
|
/*
|
||||
|
* Frame pointer offsets |
||||
|
*/ |
||||
|
#define V8_OFF_FP_FUNC (-0x8) |
||||
|
#define V8_OFF_FP_CONTEXT (-0x4) |
||||
|
#define V8_OFF_FP_MARKER (-0x8) |
||||
|
|
||||
|
/*
|
||||
|
* Heap class->field offsets |
||||
|
*/ |
||||
|
#define V8_OFF_HEAP(off) ((off) - 1) |
||||
|
|
||||
|
#define V8_OFF_FUNC_SHARED V8_OFF_HEAP(0x14) |
||||
|
#define V8_OFF_SHARED_NAME V8_OFF_HEAP(0x4) |
||||
|
#define V8_OFF_SHARED_INFERRED V8_OFF_HEAP(0x24) |
||||
|
#define V8_OFF_SHARED_SCRIPT V8_OFF_HEAP(0x1c) |
||||
|
#define V8_OFF_SHARED_FUNTOK V8_OFF_HEAP(0x4c) |
||||
|
#define V8_OFF_SCRIPT_NAME V8_OFF_HEAP(0x8) |
||||
|
#define V8_OFF_SCRIPT_LENDS V8_OFF_HEAP(0x28) |
||||
|
#define V8_OFF_STR_LENGTH V8_OFF_HEAP(0x4) |
||||
|
#define V8_OFF_STR_CHARS V8_OFF_HEAP(0xc) |
||||
|
#define V8_OFF_CONSSTR_CAR V8_OFF_HEAP(0xc) |
||||
|
#define V8_OFF_CONSSTR_CDR V8_OFF_HEAP(0x10) |
||||
|
#define V8_OFF_EXTSTR_RSRC V8_OFF_HEAP(0xc) |
||||
|
#define V8_OFF_FA_SIZE V8_OFF_HEAP(0x4) |
||||
|
#define V8_OFF_FA_DATA V8_OFF_HEAP(0x8) |
||||
|
#define V8_OFF_HEAPOBJ_MAP V8_OFF_HEAP(0x0) |
||||
|
#define V8_OFF_MAP_ATTRS V8_OFF_HEAP(0x8) |
||||
|
|
||||
|
#define NODE_OFF_EXTSTR_DATA 0x4 |
||||
|
|
||||
|
/*
|
||||
|
* Stack frame types |
||||
|
*/ |
||||
|
#define V8_FT_ENTRY 0x1 |
||||
|
#define V8_FT_ENTRYCONSTRUCT 0x2 |
||||
|
#define V8_FT_EXIT 0x3 |
||||
|
#define V8_FT_JAVASCRIPT 0x4 |
||||
|
#define V8_FT_OPTIMIZED 0x5 |
||||
|
#define V8_FT_INTERNAL 0x6 |
||||
|
#define V8_FT_CONSTRUCT 0x7 |
||||
|
#define V8_FT_ADAPTOR 0x8 |
||||
|
|
||||
|
/*
|
||||
|
* Instance types |
||||
|
*/ |
||||
|
#define V8_IT_FIXEDARRAY 0x9f |
||||
|
|
||||
|
/*
|
||||
|
* Identification masks and tags |
||||
|
*/ |
||||
|
#define V8_SmiTagMask 0x1 |
||||
|
#define V8_SmiTag 0x0 |
||||
|
#define V8_SmiValueShift V8_SmiTagMask |
||||
|
|
||||
|
#define V8_IsNotStringMask 0x80 |
||||
|
#define V8_StringTag 0x0 |
||||
|
|
||||
|
#define V8_StringEncodingMask 0x4 |
||||
|
#define V8_AsciiStringTag 0x4 |
||||
|
|
||||
|
#define V8_StringRepresentationMask 0x3 |
||||
|
#define V8_SeqStringTag 0x0 |
||||
|
#define V8_ConsStringTag 0x1 |
||||
|
#define V8_ExternalStringTag 0x2 |
||||
|
|
||||
|
#else |
||||
|
#error "only i386 is supported for DTrace ustack helper" |
||||
|
#endif |
||||
|
|
||||
|
#endif /* V8_CONSTANTS_H */ |
@ -0,0 +1,626 @@ |
|||||
|
/* |
||||
|
* V8 DTrace ustack helper for annotating native stack traces with JavaScript |
||||
|
* function names. We start with a frame pointer (arg1) and emit a string |
||||
|
* describing the current function. We do this by chasing pointers to extract |
||||
|
* the function's name (if any) and the filename and line number where the |
||||
|
* function is defined. |
||||
|
* |
||||
|
* To use the helper, run node, then use the jstack() DTrace action to capture |
||||
|
* a JavaScript stacktrace. You may need to tune the dtrace_helper_actions_max |
||||
|
* kernel variable to 128. |
||||
|
*/ |
||||
|
|
||||
|
#include <v8constants.h> |
||||
|
|
||||
|
/* |
||||
|
* V8 represents small integers (SMI) using the upper 31 bits of a 32-bit |
||||
|
* value. To extract the actual integer value, we must shift it over. |
||||
|
*/ |
||||
|
#define IS_SMI(value) ((value & V8_SmiTagMask) == V8_SmiTag) |
||||
|
#define SMI_VALUE(value) ((int32_t)(value) >> V8_SmiValueShift) |
||||
|
|
||||
|
/* |
||||
|
* Determine the encoding and representation of a V8 string. |
||||
|
*/ |
||||
|
#define V8_TYPE_STRING(type) (((type) & V8_IsNotStringMask) == V8_StringTag) |
||||
|
|
||||
|
#define V8_STRENC_ASCII(type) \ |
||||
|
(((type) & V8_StringEncodingMask) == V8_AsciiStringTag) |
||||
|
|
||||
|
#define V8_STRREP_SEQ(type) \ |
||||
|
(((type) & V8_StringRepresentationMask) == V8_SeqStringTag) |
||||
|
#define V8_STRREP_CONS(type) \ |
||||
|
(((type) & V8_StringRepresentationMask) == V8_ConsStringTag) |
||||
|
#define V8_STRREP_EXT(type) \ |
||||
|
(((type) & V8_StringRepresentationMask) == V8_ExternalStringTag) |
||||
|
|
||||
|
/* |
||||
|
* String type predicates |
||||
|
*/ |
||||
|
#define ASCII_SEQSTR(value) \ |
||||
|
(V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value)) |
||||
|
|
||||
|
#define ASCII_CONSSTR(value) \ |
||||
|
(V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_CONS(value)) |
||||
|
|
||||
|
#define ASCII_EXTSTR(value) \ |
||||
|
(V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_EXT(value)) |
||||
|
|
||||
|
/* |
||||
|
* General helper macros |
||||
|
*/ |
||||
|
#define COPYIN_UINT8(addr) (*(uint8_t *)copyin((addr), sizeof (uint8_t))) |
||||
|
#define COPYIN_UINT32(addr) (*(uint32_t *)copyin((addr), sizeof (uint32_t))) |
||||
|
|
||||
|
#define APPEND_CHR(c) (this->buf[this->off++] = (c)) |
||||
|
|
||||
|
#define APPEND_DGT(i, d) \ |
||||
|
(((i) / (d)) ? APPEND_CHR('0' + ((i)/(d) % 10)) : 0) |
||||
|
|
||||
|
#define APPEND_NUM(i) \ |
||||
|
APPEND_DGT((i), 10000); \ |
||||
|
APPEND_DGT((i), 1000); \ |
||||
|
APPEND_DGT((i), 100); \ |
||||
|
APPEND_DGT((i), 10); \ |
||||
|
APPEND_DGT((i), 1); |
||||
|
|
||||
|
/* |
||||
|
* The following macros are used to output ASCII SeqStrings, ConsStrings, and |
||||
|
* Node.js ExternalStrings. To represent each string, we use three fields: |
||||
|
* |
||||
|
* "str": a pointer to the string itself |
||||
|
* |
||||
|
* "len": the string length |
||||
|
* |
||||
|
* "attrs": the type identifier for the string, which indicates the |
||||
|
* encoding and representation. We're only interested in ASCII |
||||
|
* encoded strings whose representation is one of: |
||||
|
* |
||||
|
* SeqString stored directly as a char array inside the object |
||||
|
* |
||||
|
* ConsString pointer to two strings that should be concatenated |
||||
|
* |
||||
|
* ExternalString pointer to a char* outside the V8 heap |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
* Load "len" and "attrs" for the given "str". |
||||
|
*/ |
||||
|
#define LOAD_STRFIELDS(str, len, attrs) \ |
||||
|
len = SMI_VALUE(COPYIN_UINT32(str + V8_OFF_STR_LENGTH)); \ |
||||
|
this->map = COPYIN_UINT32(str + V8_OFF_HEAPOBJ_MAP); \ |
||||
|
attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); |
||||
|
|
||||
|
/* |
||||
|
* Print out the given SeqString, or do nothing if the string is not an ASCII |
||||
|
* SeqString. |
||||
|
*/ |
||||
|
#define APPEND_SEQSTR(str, len, attrs) \ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done && len > 0 && ASCII_SEQSTR(attrs)/ \ |
||||
|
{ \ |
||||
|
copyinto(str + V8_OFF_STR_CHARS, len, this->buf + this->off); \ |
||||
|
this->off += len; \ |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Print out the given Node.js ExternalString, or do nothing if the string is |
||||
|
* not an ASCII ExternalString. |
||||
|
*/ |
||||
|
#define APPEND_NODESTR(str, len, attrs) \ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done && len > 0 && ASCII_EXTSTR(attrs)/ \ |
||||
|
{ \ |
||||
|
this->resource = COPYIN_UINT32(str + V8_OFF_EXTSTR_RSRC); \ |
||||
|
this->dataptr = COPYIN_UINT32(this->resource + NODE_OFF_EXTSTR_DATA); \ |
||||
|
copyinto(this->dataptr, len, this->buf + this->off); \ |
||||
|
this->off += len; \ |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Recall that each ConsString points to two other strings which are |
||||
|
* semantically concatenated. Of course, these strings may themselves by |
||||
|
* ConsStrings, but in D we can only expand this recursion to a finite level. |
||||
|
* Thankfully, function and script names are generally not more than a few |
||||
|
* levels deep, so we unroll the expansion up to three levels. Even this is |
||||
|
* pretty hairy: we use strings "s0", ..., "s13", (each with "str", "len", and |
||||
|
* "attr" fields -- see above) to store the expanded strings. We expand the |
||||
|
* original string into s0 and s7, then s0 into s1 and s4, etc: |
||||
|
* |
||||
|
* |
||||
|
* +---- str ----+ |
||||
|
* / \ <-- 1st expansion |
||||
|
* / \ |
||||
|
* s0 s7 |
||||
|
* / \ / \ |
||||
|
* / \ / \ <-- 2nd expansion |
||||
|
* / \ / \ |
||||
|
* s1 s4 s8 s11 |
||||
|
* / \ / \ / \ / \ <-- 3rd expansion |
||||
|
* s2 s3 s5 s6 s9 s10 s12 s13 |
||||
|
* |
||||
|
* Of course, for a given string, any of these expansions may not be needed. |
||||
|
* For example, we may expand str and find that s0 is already a SeqString, |
||||
|
* while s7 requires further expansion. So when we expand a ConsString, we |
||||
|
* zero the length of the string itself, and then at the end we print out |
||||
|
* all non-zero-length strings in order (including both internal nodes and |
||||
|
* leafs in the tree above) to get the final output. |
||||
|
*/ |
||||
|
#define EXPAND_START() \ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done/ \ |
||||
|
{ \ |
||||
|
this->s0str = this->s1str = this->s2str = 0; \ |
||||
|
this->s3str = this->s4str = this->s5str = 0; \ |
||||
|
this->s6str = this->s7str = this->s8str = 0; \ |
||||
|
this->s9str = this->s10str = this->s11str = 0; \ |
||||
|
this->s12str = this->s13str = 0; \ |
||||
|
\ |
||||
|
this->s0len = this->s1len = this->s2len = 0; \ |
||||
|
this->s3len = this->s4len = this->s5len = 0; \ |
||||
|
this->s6len = this->s7len = this->s8len = 0; \ |
||||
|
this->s9len = this->s10len = this->s11len = 0; \ |
||||
|
this->s12len = this->s13len = 0; \ |
||||
|
\ |
||||
|
this->s0attrs = this->s1attrs = this->s2attrs = 0; \ |
||||
|
this->s3attrs = this->s4attrs = this->s5attrs = 0; \ |
||||
|
this->s6attrs = this->s7attrs = this->s8attrs = 0; \ |
||||
|
this->s9attrs = this->s10attrs = this->s11attrs = 0; \ |
||||
|
this->s12attrs = this->s13attrs = 0; \ |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Expand the ConsString "str" (represensted by "str", "len", and "attrs") into |
||||
|
* strings "s1" (represented by "s1s", "s1l", and "s1a") and "s2" (represented |
||||
|
* by "s2s", "s2l", "s2a"). If "str" is not a ConsString, do nothing. |
||||
|
*/ |
||||
|
#define EXPAND_STR(str, len, attrs, s1s, s1l, s1a, s2s, s2l, s2a) \ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done && len > 0 && ASCII_CONSSTR(attrs)/ \ |
||||
|
{ \ |
||||
|
len = 0; \ |
||||
|
\ |
||||
|
s1s = COPYIN_UINT32(str + V8_OFF_CONSSTR_CAR); \ |
||||
|
LOAD_STRFIELDS(s1s, s1l, s1a) \ |
||||
|
\ |
||||
|
s2s = COPYIN_UINT32(str + V8_OFF_CONSSTR_CDR); \ |
||||
|
LOAD_STRFIELDS(s2s, s2l, s2a) \ |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Print out a ConsString by expanding it up to three levels and printing out |
||||
|
* the resulting SeqStrings. |
||||
|
*/ |
||||
|
#define APPEND_CONSSTR(str, len, attrs) \ |
||||
|
EXPAND_START() \ |
||||
|
EXPAND_STR(str, len, attrs, \ |
||||
|
this->s0str, this->s0len, this->s0attrs, \ |
||||
|
this->s7str, this->s7len, this->s7attrs) \ |
||||
|
EXPAND_STR(this->s0str, this->s0len, this->s0attrs, \ |
||||
|
this->s1str, this->s1len, this->s1attrs, \ |
||||
|
this->s4str, this->s4len, this->s4attrs) \ |
||||
|
EXPAND_STR(this->s1str, this->s1len, this->s1attrs, \ |
||||
|
this->s2str, this->s2len, this->s2attrs, \ |
||||
|
this->s3str, this->s3len, this->s3attrs) \ |
||||
|
EXPAND_STR(this->s4str, this->s4len, this->s4attrs, \ |
||||
|
this->s5str, this->s5len, this->s5attrs, \ |
||||
|
this->s6str, this->s6len, this->s6attrs) \ |
||||
|
EXPAND_STR(this->s7str, this->s7len, this->s7attrs, \ |
||||
|
this->s8str, this->s8len, this->s8attrs, \ |
||||
|
this->s11str, this->s11len, this->s11attrs) \ |
||||
|
EXPAND_STR(this->s8str, this->s8len, this->s8attrs, \ |
||||
|
this->s9str, this->s9len, this->s9attrs, \ |
||||
|
this->s10str, this->s10len, this->s10attrs) \ |
||||
|
EXPAND_STR(this->s11str, this->s11len, this->s11attrs, \ |
||||
|
this->s12str, this->s12len, this->s12attrs, \ |
||||
|
this->s13str, this->s13len, this->s13attrs) \ |
||||
|
\ |
||||
|
APPEND_SEQSTR(str, len, attrs) \ |
||||
|
APPEND_SEQSTR(this->s0str, this->s0len, this->s0attrs) \ |
||||
|
APPEND_SEQSTR(this->s1str, this->s1len, this->s1attrs) \ |
||||
|
APPEND_SEQSTR(this->s2str, this->s2len, this->s2attrs) \ |
||||
|
APPEND_SEQSTR(this->s3str, this->s3len, this->s3attrs) \ |
||||
|
APPEND_SEQSTR(this->s4str, this->s4len, this->s4attrs) \ |
||||
|
APPEND_SEQSTR(this->s5str, this->s5len, this->s5attrs) \ |
||||
|
APPEND_SEQSTR(this->s6str, this->s6len, this->s6attrs) \ |
||||
|
APPEND_SEQSTR(this->s7str, this->s7len, this->s7attrs) \ |
||||
|
APPEND_SEQSTR(this->s8str, this->s8len, this->s8attrs) \ |
||||
|
APPEND_SEQSTR(this->s9str, this->s9len, this->s9attrs) \ |
||||
|
APPEND_SEQSTR(this->s10str, this->s10len, this->s10attrs) \ |
||||
|
APPEND_SEQSTR(this->s11str, this->s11len, this->s11attrs) \ |
||||
|
APPEND_SEQSTR(this->s12str, this->s12len, this->s12attrs) \ |
||||
|
APPEND_SEQSTR(this->s13str, this->s13len, this->s13attrs) \ |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Print out the given SeqString, ConsString, or ExternalString. |
||||
|
* APPEND_CONSSTR implicitly handles SeqStrings as the degenerate case of an |
||||
|
* expanded ConsString. |
||||
|
*/ |
||||
|
#define APPEND_V8STR(str, len, attrs) \ |
||||
|
APPEND_CONSSTR(str, len, attrs) \ |
||||
|
APPEND_NODESTR(str, len, attrs) |
||||
|
|
||||
|
/* |
||||
|
* In this first clause we initialize all variables. We must explicitly clear |
||||
|
* them because they may contain values left over from previous iterations. |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
{ |
||||
|
/* input */ |
||||
|
this->fp = arg1; |
||||
|
|
||||
|
/* output/flow control */ |
||||
|
this->buf = (char *)alloca(128); |
||||
|
this->off = 0; |
||||
|
this->done = 0; |
||||
|
|
||||
|
/* program state */ |
||||
|
this->ctx = 0; |
||||
|
this->marker = 0; |
||||
|
this->func = 0; |
||||
|
this->shared = 0; |
||||
|
this->map = 0; |
||||
|
this->funcnamestr = 0; |
||||
|
this->funcnamelen = 0; |
||||
|
this->funcnameattrs = 0; |
||||
|
this->script = 0; |
||||
|
this->scriptnamestr = 0; |
||||
|
this->scriptnamelen = 0; |
||||
|
this->scriptnameattrs = 0; |
||||
|
this->position = 0; |
||||
|
this->line_ends = 0; |
||||
|
this->le_attrs = 0; |
||||
|
|
||||
|
/* binary search fields */ |
||||
|
this->bsearch_min = 0; |
||||
|
this->bsearch_max = 0; |
||||
|
this->ii = 0; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Like V8, we first check if we've got an ArgumentsAdaptorFrame. We've got |
||||
|
* nothing to add for such frames, so we bail out quickly. |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
{ |
||||
|
this->ctx = COPYIN_UINT32(this->fp + V8_OFF_FP_CONTEXT); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/IS_SMI(this->ctx) && SMI_VALUE(this->ctx) == V8_FT_ADAPTOR/ |
||||
|
{ |
||||
|
this->done = 1; |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('d'); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('p'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('\0'); |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Check for other common frame types for which we also have nothing to add. |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done/ |
||||
|
{ |
||||
|
this->marker = COPYIN_UINT32(this->fp + V8_OFF_FP_MARKER); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && IS_SMI(this->marker) && |
||||
|
SMI_VALUE(this->marker) == V8_FT_ENTRY/ |
||||
|
{ |
||||
|
this->done = 1; |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('e'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR('y'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('\0'); |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && IS_SMI(this->marker) && |
||||
|
SMI_VALUE(this->marker) == V8_FT_ENTRYCONSTRUCT/ |
||||
|
{ |
||||
|
this->done = 1; |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('e'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR('y'); |
||||
|
APPEND_CHR('_'); |
||||
|
APPEND_CHR('c'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('s'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR('u'); |
||||
|
APPEND_CHR('c'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('\0'); |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && IS_SMI(this->marker) && |
||||
|
SMI_VALUE(this->marker) == V8_FT_EXIT/ |
||||
|
{ |
||||
|
this->done = 1; |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('e'); |
||||
|
APPEND_CHR('x'); |
||||
|
APPEND_CHR('i'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('\0'); |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && IS_SMI(this->marker) && |
||||
|
SMI_VALUE(this->marker) == V8_FT_INTERNAL/ |
||||
|
{ |
||||
|
this->done = 1; |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('i'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('e'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('l'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('\0'); |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && IS_SMI(this->marker) && |
||||
|
SMI_VALUE(this->marker) == V8_FT_CONSTRUCT/ |
||||
|
{ |
||||
|
this->done = 1; |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR('<'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('c'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('s'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR('u'); |
||||
|
APPEND_CHR('c'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('r'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('>'); |
||||
|
APPEND_CHR('\0'); |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* At this point, we're either looking at a JavaScriptFrame or an |
||||
|
* OptimizedFrame. For now, we assume JavaScript and start by grabbing the |
||||
|
* function name. |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done/ |
||||
|
{ |
||||
|
this->func = COPYIN_UINT32(this->fp + V8_OFF_FP_FUNC); |
||||
|
this->shared = COPYIN_UINT32(this->func + V8_OFF_FUNC_SHARED); |
||||
|
this->funcnamestr = COPYIN_UINT32(this->shared + V8_OFF_SHARED_NAME); |
||||
|
LOAD_STRFIELDS(this->funcnamestr, this->funcnamelen, |
||||
|
this->funcnameattrs); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && this->funcnamelen == 0/ |
||||
|
{ |
||||
|
/* |
||||
|
* This is an anonymous function, but if it was invoked as a method of |
||||
|
* some object then V8 will have computed an inferred name that we can |
||||
|
* include in the stack trace. |
||||
|
*/ |
||||
|
APPEND_CHR('('); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR(')'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('s'); |
||||
|
APPEND_CHR(' '); |
||||
|
|
||||
|
this->funcnamestr = COPYIN_UINT32(this->shared + V8_OFF_SHARED_INFERRED); |
||||
|
LOAD_STRFIELDS(this->funcnamestr, this->funcnamelen, |
||||
|
this->funcnameattrs); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && this->funcnamelen == 0/ |
||||
|
{ |
||||
|
APPEND_CHR('('); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR(')'); |
||||
|
} |
||||
|
|
||||
|
APPEND_V8STR(this->funcnamestr, this->funcnamelen, this->funcnameattrs) |
||||
|
|
||||
|
/* |
||||
|
* Now look for the name of the script where the function was defined. |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done/ |
||||
|
{ |
||||
|
this->script = COPYIN_UINT32(this->shared + V8_OFF_SHARED_SCRIPT); |
||||
|
this->scriptnamestr = COPYIN_UINT32(this->script + |
||||
|
V8_OFF_SCRIPT_NAME); |
||||
|
LOAD_STRFIELDS(this->scriptnamestr, this->scriptnamelen, |
||||
|
this->scriptnameattrs); |
||||
|
|
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('a'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR(' '); |
||||
|
} |
||||
|
|
||||
|
APPEND_V8STR(this->scriptnamestr, this->scriptnamelen, this->scriptnameattrs) |
||||
|
|
||||
|
/* |
||||
|
* Now look for file position and line number information. |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done/ |
||||
|
{ |
||||
|
this->position = COPYIN_UINT32(this->shared + V8_OFF_SHARED_FUNTOK); |
||||
|
this->line_ends = COPYIN_UINT32(this->script + V8_OFF_SCRIPT_LENDS); |
||||
|
this->map = COPYIN_UINT32(this->line_ends + V8_OFF_HEAPOBJ_MAP); |
||||
|
this->le_attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done && this->le_attrs != V8_IT_FIXEDARRAY/ |
||||
|
{ |
||||
|
/* |
||||
|
* If the line number array was not a valid FixedArray, it's probably |
||||
|
* undefined because V8 has not had to compute it yet. In this case we |
||||
|
* just show the raw position and call it a day. |
||||
|
*/ |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('p'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('s'); |
||||
|
APPEND_CHR('i'); |
||||
|
APPEND_CHR('t'); |
||||
|
APPEND_CHR('i'); |
||||
|
APPEND_CHR('o'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_NUM(this->position); |
||||
|
APPEND_CHR('\0'); |
||||
|
this->done = 1; |
||||
|
stringof(this->buf); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* At this point, we've got both a position in the script and an array |
||||
|
* describing where each line of the file ends. We can use this to compute the |
||||
|
* line number by binary searching the array. (This is also what V8 does when |
||||
|
* computing stack traces.) |
||||
|
*/ |
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done/ |
||||
|
{ |
||||
|
/* initialize binary search */ |
||||
|
this->bsearch_line = this->position < COPYIN_UINT32( |
||||
|
this->line_ends + V8_OFF_FA_DATA) ? 1 : 0; |
||||
|
this->bsearch_min = 0; |
||||
|
this->bsearch_max = this->bsearch_line != 0 ? 0 : |
||||
|
SMI_VALUE(COPYIN_UINT32(this->line_ends + V8_OFF_FA_SIZE)) - 1; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Of course, we can't iterate the binary search indefinitely, so we hardcode 15 |
||||
|
* iterations. That's enough to precisely identify the line number in files up |
||||
|
* to 32768 lines of code. |
||||
|
*/ |
||||
|
#define BSEARCH_LOOP \ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done && this->bsearch_max >= 1/ \ |
||||
|
{ \ |
||||
|
this->ii = (this->bsearch_min + this->bsearch_max) >> 1; \ |
||||
|
} \ |
||||
|
\ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done && this->bsearch_max >= 1 && \ |
||||
|
this->position > COPYIN_UINT32(this->line_ends + V8_OFF_FA_DATA + \ |
||||
|
this->ii * sizeof (uint32_t))/ \ |
||||
|
{ \ |
||||
|
this->bsearch_min = this->ii + 1; \ |
||||
|
} \ |
||||
|
\ |
||||
|
dtrace:helper:ustack: \ |
||||
|
/!this->done && this->bsearch_max >= 1 && \ |
||||
|
this->position <= COPYIN_UINT32(this->line_ends + V8_OFF_FA_DATA + \ |
||||
|
(this->ii - 1) * sizeof (uint32_t))/ \ |
||||
|
{ \ |
||||
|
this->bsearch_max = this->ii - 1; \ |
||||
|
} |
||||
|
|
||||
|
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:helper:ustack: |
||||
|
/!this->done && !this->bsearch_line/ |
||||
|
{ |
||||
|
this->bsearch_line = this->ii + 1; |
||||
|
} |
||||
|
|
||||
|
dtrace:helper:ustack: |
||||
|
/!this->done/ |
||||
|
{ |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_CHR('l'); |
||||
|
APPEND_CHR('i'); |
||||
|
APPEND_CHR('n'); |
||||
|
APPEND_CHR('e'); |
||||
|
APPEND_CHR(' '); |
||||
|
APPEND_NUM(this->bsearch_line); |
||||
|
APPEND_CHR('\0'); |
||||
|
this->done = 1; |
||||
|
stringof(this->buf); |
||||
|
} |
Loading…
Reference in new issue