From 5921158cbe29465ce61285b42c14bfd4433f4b48 Mon Sep 17 00:00:00 2001 From: Dave Pacheco Date: Mon, 7 Oct 2013 13:17:49 -0700 Subject: [PATCH] dtrace, mdb_v8: support more string, frame types This change makes several improvements to the ustack helper and MDB support: - ustack helper and MDB: add support for two-byte strings (necessary to print many filenames in stacktraces in 0.10 and later). - ustack helper: fix position numbers, which were off by a factor of two - ustack helper: fix frames with undefined Scripts (e.g., "RegExp") - ustack helper: add stub frames - MDB: add support for sliced strings - MDB: sync up with changes from the illumos version of the module Fixes #6309 Closes #6318 --- deps/mdb_v8/mdb_v8.c | 183 +++++++++++++++++++++++++++++++++++++++++++-------- deps/mdb_v8/v8dbg.h | 2 + src/v8abbr.h | 12 ++++ src/v8ustack.d | 146 ++++++++++++++++++++++++++++++++-------- 4 files changed, 288 insertions(+), 55 deletions(-) diff --git a/deps/mdb_v8/mdb_v8.c b/deps/mdb_v8/mdb_v8.c index 5ebfb65..998028d 100644 --- a/deps/mdb_v8/mdb_v8.c +++ b/deps/mdb_v8/mdb_v8.c @@ -24,6 +24,14 @@ * makes heavy use of metadata defined in the V8 binary for inspecting in-memory * structures. Canned configurations can be manually loaded for V8 binaries * that predate this metadata. See mdb_v8_cfg.c for details. + * + * NOTE: This dmod implementation (including this file and related headers and C + * files) exist in both the Node and illumos source trees. THESE SHOULD BE KEPT + * IN SYNC. The version in the Node tree is built directly into modern Node + * binaries as part of the build process, and the version in the illumos source + * tree is delivered with the OS for debugging Node binaries that predate + * support for including the dmod directly in the binary. Note too that these + * files have different licenses to match their corresponding repositories. */ /* @@ -119,6 +127,7 @@ static intptr_t V8_AsciiStringTag; static intptr_t V8_StringRepresentationMask; static intptr_t V8_SeqStringTag; static intptr_t V8_ConsStringTag; +static intptr_t V8_SlicedStringTag; static intptr_t V8_ExternalStringTag; static intptr_t V8_FailureTag; static intptr_t V8_FailureTagMask; @@ -180,12 +189,15 @@ static ssize_t V8_OFF_SCRIPT_LINE_ENDS; static ssize_t V8_OFF_SCRIPT_NAME; static ssize_t V8_OFF_SEQASCIISTR_CHARS; static ssize_t V8_OFF_SEQONEBYTESTR_CHARS; +static ssize_t V8_OFF_SEQTWOBYTESTR_CHARS; static ssize_t V8_OFF_SHAREDFUNCTIONINFO_CODE; static ssize_t V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION; static ssize_t V8_OFF_SHAREDFUNCTIONINFO_INFERRED_NAME; static ssize_t V8_OFF_SHAREDFUNCTIONINFO_LENGTH; static ssize_t V8_OFF_SHAREDFUNCTIONINFO_SCRIPT; static ssize_t V8_OFF_SHAREDFUNCTIONINFO_NAME; +static ssize_t V8_OFF_SLICEDSTRING_PARENT; +static ssize_t V8_OFF_SLICEDSTRING_OFFSET; static ssize_t V8_OFF_STRING_LENGTH; #define NODE_OFF_EXTSTR_DATA 0x4 /* see node_string.h */ @@ -233,6 +245,8 @@ static v8_constant_t v8_constants[] = { { &V8_StringRepresentationMask, "v8dbg_StringRepresentationMask" }, { &V8_SeqStringTag, "v8dbg_SeqStringTag" }, { &V8_ConsStringTag, "v8dbg_ConsStringTag" }, + { &V8_SlicedStringTag, "v8dbg_SlicedStringTag", + V8_CONSTANT_FALLBACK(0, 0), 0x3 }, { &V8_ExternalStringTag, "v8dbg_ExternalStringTag" }, { &V8_FailureTag, "v8dbg_FailureTag" }, { &V8_FailureTagMask, "v8dbg_FailureTagMask" }, @@ -284,6 +298,7 @@ typedef struct v8_offset { const char *v8o_class; const char *v8o_member; boolean_t v8o_optional; + intptr_t v8o_fallback; } v8_offset_t; static v8_offset_t v8_offsets[] = { @@ -339,6 +354,8 @@ static v8_offset_t v8_offsets[] = { "SeqAsciiString", "chars", B_TRUE }, { &V8_OFF_SEQONEBYTESTR_CHARS, "SeqOneByteString", "chars", B_TRUE }, + { &V8_OFF_SEQTWOBYTESTR_CHARS, + "SeqTwoByteString", "chars", B_TRUE }, { &V8_OFF_SHAREDFUNCTIONINFO_CODE, "SharedFunctionInfo", "code" }, { &V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION, @@ -351,6 +368,10 @@ static v8_offset_t v8_offsets[] = { "SharedFunctionInfo", "name" }, { &V8_OFF_SHAREDFUNCTIONINFO_SCRIPT, "SharedFunctionInfo", "script" }, + { &V8_OFF_SLICEDSTRING_OFFSET, + "SlicedString", "offset" }, + { &V8_OFF_SLICEDSTRING_PARENT, + "SlicedString", "parent", B_TRUE }, { &V8_OFF_STRING_LENGTH, "String", "length" }, }; @@ -516,6 +537,13 @@ again: if (V8_OFF_SEQONEBYTESTR_CHARS != -1) V8_OFF_SEQASCIISTR_CHARS = V8_OFF_SEQONEBYTESTR_CHARS; + if (V8_OFF_SEQTWOBYTESTR_CHARS == -1) + V8_OFF_SEQTWOBYTESTR_CHARS = V8_OFF_SEQASCIISTR_CHARS; + + if (V8_OFF_SLICEDSTRING_PARENT == -1) + V8_OFF_SLICEDSTRING_PARENT = V8_OFF_SLICEDSTRING_OFFSET - + sizeof (uintptr_t); + return (failed ? -1 : 0); } @@ -795,6 +823,7 @@ conf_class_compute_offsets(v8_class_t *clp) #define JSSTR_NUDE JSSTR_NONE #define JSSTR_VERBOSE 0x1 #define JSSTR_QUOTED 0x2 +#define JSSTR_ISASCII 0x4 static int jsstr_print(uintptr_t, uint_t, char **, size_t *); static boolean_t jsobj_is_undefined(uintptr_t addr); @@ -996,6 +1025,7 @@ read_heap_array(uintptr_t addr, uintptr_t **retp, size_t *lenp, int flags) if (!(flags & UM_GC)) mdb_free(*retp, len * sizeof (uintptr_t)); + *retp = NULL; return (-1); } @@ -1290,11 +1320,13 @@ obj_print_class(uintptr_t addr, v8_class_t *clp) } /* - * Print the ASCII string for the given ASCII JS string, expanding ConsStrings - * and ExternalStrings as needed. + * Print the ASCII string for the given JS string, expanding ConsStrings and + * ExternalStrings as needed. */ -static int jsstr_print_seq(uintptr_t, uint_t, char **, size_t *); +static int jsstr_print_seq(uintptr_t, uint_t, char **, size_t *, size_t, + ssize_t); static int jsstr_print_cons(uintptr_t, uint_t, char **, size_t *); +static int jsstr_print_sliced(uintptr_t, uint_t, char **, size_t *); static int jsstr_print_external(uintptr_t, uint_t, char **, size_t *); static int @@ -1315,11 +1347,6 @@ jsstr_print(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) return (0); } - if (!V8_STRENC_ASCII(typebyte)) { - (void) bsnprintf(bufp, lenp, ""); - return (0); - } - if (verbose) { lbufp = buf; llen = sizeof (buf); @@ -1328,12 +1355,19 @@ jsstr_print(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) (void) mdb_inc_indent(4); } + if (V8_STRENC_ASCII(typebyte)) + flags |= JSSTR_ISASCII; + else + flags &= ~JSSTR_ISASCII; + if (V8_STRREP_SEQ(typebyte)) - err = jsstr_print_seq(addr, flags, bufp, lenp); + err = jsstr_print_seq(addr, flags, bufp, lenp, 0, -1); else if (V8_STRREP_CONS(typebyte)) err = jsstr_print_cons(addr, flags, bufp, lenp); else if (V8_STRREP_EXT(typebyte)) err = jsstr_print_external(addr, flags, bufp, lenp); + else if (V8_STRREP_SLICED(typebyte)) + err = jsstr_print_sliced(addr, flags, bufp, lenp); else { (void) bsnprintf(bufp, lenp, ""); err = -1; @@ -1346,42 +1380,85 @@ jsstr_print(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) } static int -jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) +jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp, + size_t sliceoffset, ssize_t slicelen) { /* * To allow the caller to allocate a very large buffer for strings, * we'll allocate a buffer sized based on our input, making it at * least enough space for our ellipsis and at most 256K. */ - uintptr_t len, rlen, blen = *lenp + sizeof ("[...]") + 1; - char *buf = alloca(MIN(blen, 256 * 1024)); + uintptr_t i, nstrchrs, nreadbytes, nreadoffset, blen, nstrbytes; boolean_t verbose = flags & JSSTR_VERBOSE ? B_TRUE : B_FALSE; boolean_t quoted = flags & JSSTR_QUOTED ? B_TRUE : B_FALSE; + char *buf; + uint16_t chrval; + + blen = MIN(*lenp, 256 * 1024); + buf = alloca(blen); - if (read_heap_smi(&len, addr, V8_OFF_STRING_LENGTH) != 0) + if (read_heap_smi(&nstrchrs, addr, V8_OFF_STRING_LENGTH) != 0) return (-1); - rlen = len <= blen - 1 ? len : blen - sizeof ("[...]"); + if (slicelen != -1) + nstrchrs = slicelen; + if (nstrchrs < 0) + nstrchrs = 0; + + if ((flags & JSSTR_ISASCII) != 0) { + nstrbytes = nstrchrs; + nreadoffset = sliceoffset; + } else { + nstrbytes = 2 * nstrchrs; + nreadoffset = 2 * sliceoffset; + } + + nreadbytes = nstrbytes + sizeof ("\"\"") <= blen ? nstrbytes : + blen - sizeof ("\"\"[...]"); if (verbose) - mdb_printf("length: %d, will read: %d\n", len, rlen); + mdb_printf("length: %d chars (%d bytes), " + "will read %d bytes from offset %d\n", + nstrchrs, nstrbytes, nreadbytes, nreadoffset); + + if (nstrbytes == 0) { + (void) bsnprintf(bufp, lenp, "%s%s", + quoted ? "\"" : "", quoted ? "\"" : ""); + return (0); + } buf[0] = '\0'; - if (rlen > 0 && mdb_readstr(buf, rlen + 1, - addr + V8_OFF_SEQASCIISTR_CHARS) == -1) { - v8_warn("failed to read SeqString data"); - return (-1); - } + if ((flags & JSSTR_ISASCII) != 0) { + if (mdb_readstr(buf, nreadbytes + 1, + addr + V8_OFF_SEQASCIISTR_CHARS + nreadoffset) == -1) { + v8_warn("failed to read SeqString data"); + return (-1); + } - if (rlen != len) - (void) strlcat(buf, "[...]", blen); + if (nreadbytes != nstrbytes) + (void) strlcat(buf, "[...]", blen); - if (verbose) - mdb_printf("value: \"%s\"\n", buf); + (void) bsnprintf(bufp, lenp, "%s%s%s", + quoted ? "\"" : "", buf, quoted ? "\"" : ""); + } else { + if (mdb_readstr(buf, nreadbytes, + addr + V8_OFF_SEQTWOBYTESTR_CHARS + nreadoffset) == -1) { + v8_warn("failed to read SeqTwoByteString data"); + return (-1); + } - (void) bsnprintf(bufp, lenp, "%s%s%s", - quoted ? "\"" : "", buf, quoted ? "\"" : ""); + (void) bsnprintf(bufp, lenp, "%s", quoted ? "\"" : ""); + for (i = 0; i < nreadbytes; i += 2) { + chrval = *((uint16_t *)(buf + i)); + (void) bsnprintf(bufp, lenp, "%c", + (isascii(chrval) || chrval == 0) ? + (char)chrval : '?'); + } + if (nreadbytes != nstrbytes) + (void) bsnprintf(bufp, lenp, "[...]"); + (void) bsnprintf(bufp, lenp, "%s", quoted ? "\"" : ""); + } return (0); } @@ -1418,14 +1495,64 @@ jsstr_print_cons(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) } static int -jsstr_print_external(uintptr_t addr, uint_t flags, char **bufp, - size_t *lenp) +jsstr_print_sliced(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) +{ + uintptr_t parent, offset, length; + uint8_t typebyte; + boolean_t verbose = flags & JSSTR_VERBOSE ? B_TRUE : B_FALSE; + boolean_t quoted = flags & JSSTR_QUOTED ? B_TRUE : B_FALSE; + uint_t newflags; + + if (read_heap_ptr(&parent, addr, V8_OFF_SLICEDSTRING_PARENT) != 0 || + read_heap_smi(&offset, addr, V8_OFF_SLICEDSTRING_OFFSET) != 0 || + read_heap_smi(&length, addr, V8_OFF_STRING_LENGTH) != 0) + return (-1); + + if (verbose) + mdb_printf("parent: %p, offset = %d, length = %d\n", + parent, offset, length); + + if (read_typebyte(&typebyte, parent) != 0) { + v8_warn("SlicedString %s: failed to read parent's type", addr); + (void) bsnprintf(bufp, lenp, ""); + return (0); + } + + if (!V8_STRREP_SEQ(typebyte)) { + v8_warn("SlicedString %s: parent is not a sequential string", + addr); + (void) bsnprintf(bufp, lenp, ""); + return (0); + } + + if (quoted) + (void) bsnprintf(bufp, lenp, "\""); + + newflags = verbose ? JSSTR_VERBOSE : 0; + if (V8_STRENC_ASCII(typebyte)) + newflags |= JSSTR_ISASCII; + if (jsstr_print_seq(parent, newflags, bufp, lenp, offset, length) != 0) + return (-1); + + if (quoted) + (void) bsnprintf(bufp, lenp, "\""); + + return (0); +} + +static int +jsstr_print_external(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp) { uintptr_t ptr1, ptr2; size_t blen = *lenp + 1; char *buf = alloca(blen); boolean_t quoted = flags & JSSTR_QUOTED ? B_TRUE : B_FALSE; + if ((flags & JSSTR_ISASCII) == 0) { + (void) bsnprintf(bufp, lenp, ""); + return (0); + } + if (flags & JSSTR_VERBOSE) mdb_printf("assuming Node.js string\n"); diff --git a/deps/mdb_v8/v8dbg.h b/deps/mdb_v8/v8dbg.h index 6e56e97..a66329e 100644 --- a/deps/mdb_v8/v8dbg.h +++ b/deps/mdb_v8/v8dbg.h @@ -61,6 +61,8 @@ (((type) & V8_StringRepresentationMask) == V8_SeqStringTag) #define V8_STRREP_CONS(type) \ (((type) & V8_StringRepresentationMask) == V8_ConsStringTag) +#define V8_STRREP_SLICED(type) \ + (((type) & V8_StringRepresentationMask) == V8_SlicedStringTag) #define V8_STRREP_EXT(type) \ (((type) & V8_StringRepresentationMask) == V8_ExternalStringTag) diff --git a/src/v8abbr.h b/src/v8abbr.h index 7a5f9e7..6c7a765 100644 --- a/src/v8abbr.h +++ b/src/v8abbr.h @@ -42,6 +42,7 @@ #define V8_FT_INTERNAL V8DBG_FRAMETYPE_INTERNALFRAME #define V8_FT_CONSTRUCT V8DBG_FRAMETYPE_CONSTRUCTFRAME #define V8_FT_ADAPTOR V8DBG_FRAMETYPE_ARGUMENTSADAPTORFRAME +#define V8_FT_STUB V8DBG_FRAMETYPE_STUBFRAME /* Identification masks and tags */ #define V8_SmiTagMask (V8DBG_SMITAGMASK) @@ -65,10 +66,19 @@ /* Instance types */ #define V8_IT_FIXEDARRAY V8DBG_TYPE_FIXEDARRAY__FIXED_ARRAY_TYPE #define V8_IT_CODE V8DBG_TYPE_CODE__CODE_TYPE +#define V8_IT_SCRIPT V8DBG_TYPE_SCRIPT__SCRIPT_TYPE /* Node-specific offsets */ #define NODE_OFF_EXTSTR_DATA sizeof(void*) +/* + * Not all versions of V8 have the offset for the "chars" array in the + * SeqTwoByteString class, but it's the same as the one for SeqOneByteString. + */ +#ifndef V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR +#define V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR V8DBG_CLASS_SEQONEBYTESTRING__CHARS__CHAR +#endif + /* Heap class->field offsets */ #define V8_OFF_HEAP(off) ((off) - 1) @@ -104,5 +114,7 @@ V8_OFF_HEAP(V8DBG_CLASS_HEAPOBJECT__MAP__MAP) #define V8_OFF_MAP_ATTRS \ V8_OFF_HEAP(V8DBG_CLASS_MAP__INSTANCE_ATTRIBUTES__INT) +#define V8_OFF_TWOBYTESTR_CHARS \ + V8_OFF_HEAP(V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR) #endif /* SRC_V8ABBR_H_ */ diff --git a/src/v8ustack.d b/src/v8ustack.d index d643f8f..08d06e2 100644 --- a/src/v8ustack.d +++ b/src/v8ustack.d @@ -31,6 +31,9 @@ #define V8_MAP_PTR(ptr) \ ((ptr & ~V8_HeapObjectTagMask) | V8_HeapObjectTag) +#define V8_TYPE_SCRIPT(type) \ + ((type) == V8_IT_SCRIPT) + /* * Determine the encoding and representation of a V8 string. */ @@ -53,8 +56,11 @@ #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 TWOBYTE_SEQSTR(value) \ + (V8_TYPE_STRING(value) && !V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value)) + +#define IS_CONSSTR(value) \ + (V8_TYPE_STRING(value) && V8_STRREP_CONS(value)) #define ASCII_EXTSTR(value) \ (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_EXT(value)) @@ -123,14 +129,16 @@ * "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: + * encoding and representation. We're only interested in strings + * whose representation is one of: * - * SeqString stored directly as a char array inside the object + * SeqOneByteString stored directly as a char array inside the object * - * ConsString pointer to two strings that should be concatenated + * SeqTwoByteString stored as a UTF-16 char array inside the object * - * ExternalString pointer to a char* outside the V8 heap + * ConsString pointer to two strings that should be concatenated + * + * ExternalString pointer to a char* outside the V8 heap */ /* @@ -141,27 +149,79 @@ this->map = V8_MAP_PTR(COPYIN_PTR(str + V8_OFF_HEAPOBJ_MAP)); \ attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); +#define APPEND_SEQSTR(str, len, attrs) \ + APPEND_SEQONEBYTESTR(str, len, attrs) \ + APPEND_SEQTWOBYTESTR(str, len, attrs) + /* - * Print out the given SeqString, or do nothing if the string is not an ASCII - * SeqString. + * Print out the given SeqOneByteString, or do nothing if the string is not an ASCII + * SeqOneByteString. */ -#define APPEND_SEQSTR(str, len, attrs) \ - dtrace:helper:ustack: \ - /!this->done && len > 0 && ASCII_SEQSTR(attrs)/ \ - { \ +#define APPEND_SEQONEBYTESTR(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; \ } /* + * LOOP_ITER: macro to paste "block" while "ivar" is less than "dynmax" and + * "statmax". The subsequent LOOP_{4,8} macros facilitate pasting the same + * thing 4 and 8 times, respectively. Like much of the rest of the code in this + * file, this is regrettably necessary given the constraints under which we're + * expected to run. + */ +#define LOOP_ITER(ivar, dynmax, statmax, block) \ + ((ivar) < (dynmax)) && ((ivar) < (statmax)) && (block); (ivar)++; + +#define LOOP_4(block) \ + block \ + block \ + block \ + block \ + +#define LOOP_8(block) \ + LOOP_4(block) \ + LOOP_4(block) + +/* + * Print out the given SeqTwoByteString, or do nothing if the string is not an ASCII + * SeqTwoByteString. NOTE: if you bump MAX_TWOBYTESTR_CHARS, you'll also need + * to modify the LOOP_* macro calls below to match. + */ +#define MAX_TWOBYTESTR_CHARS 128 +#define MAX_TWOBYTESTR_BYTES (2 * MAX_TWOBYTESTR_CHARS) +#define TO_ASCII(c) ((c) < 128 ? (c) : '?') + +#define APPEND_SEQTWOBYTESTR(str, len, attrs) \ + dtrace:helper:ustack: \ + /!this->done && len > 0 && TWOBYTE_SEQSTR(attrs)/ \ + { \ + this->i = 0; \ + this->stbuf = (uint16_t *)alloca(MAX_TWOBYTESTR_BYTES + 2); \ + copyinto(str + V8_OFF_TWOBYTESTR_CHARS, \ + MAX_TWOBYTESTR_BYTES, this->stbuf); \ + this->stbuf[MAX_TWOBYTESTR_BYTES - 1] = '\0'; \ + this->stbuf[MAX_TWOBYTESTR_BYTES] = '\0'; \ + \ + LOOP_8(LOOP_8(LOOP_4(LOOP_ITER(this->i, len, \ + MAX_TWOBYTESTR_CHARS, \ + APPEND_CHR(TO_ASCII(this->stbuf[this->i])))))) \ + \ + this->i = 0; \ + this->stbuf = 0; \ + } + +/* * 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_PTR(str + V8_OFF_EXTSTR_RSRC); \ + dtrace:helper:ustack: \ + /!this->done && len > 0 && ASCII_EXTSTR(attrs)/ \ + { \ + this->resource = COPYIN_PTR(str + V8_OFF_EXTSTR_RSRC); \ this->dataptr = COPYIN_PTR(this->resource + NODE_OFF_EXTSTR_DATA); \ copyinto(this->dataptr, len, this->buf + this->off); \ this->off += len; \ @@ -226,7 +286,7 @@ */ #define EXPAND_STR(str, len, attrs, s1s, s1l, s1a, s2s, s2l, s2a) \ dtrace:helper:ustack: \ - /!this->done && len > 0 && ASCII_CONSSTR(attrs)/ \ + /!this->done && len > 0 && IS_CONSSTR(attrs)/ \ { \ len = 0; \ \ @@ -316,6 +376,7 @@ dtrace:helper:ustack: this->funcnamelen = 0; this->funcnameattrs = 0; this->script = (off_t) 0; + this->scriptattrs = 0; this->scriptnamestr = (off_t) 0; this->scriptnamelen = 0; this->scriptnameattrs = 0; @@ -409,6 +470,16 @@ dtrace:helper:ustack: stringof(this->buf); } +dtrace:helper:ustack: +/!this->done && IS_SMI(this->marker) && + SMI_VALUE(this->marker) == V8_FT_STUB/ +{ + this->done = 1; + APPEND_CHR8('<','<',' ','s','t','u','b',' '); + APPEND_CHR4('>','>','\0','\0'); + stringof(this->buf); +} + /* * Now check for internal frames that we can only identify by seeing that * there's a Code object where there would be a JSFunction object for a @@ -477,24 +548,38 @@ dtrace:helper:ustack: APPEND_V8STR(this->funcnamestr, this->funcnamelen, this->funcnameattrs) /* - * Now look for the name of the script where the function was defined. + * Now look for the name of the script where the function was defined. The + * "script" itself may be undefined for special functions like "RegExp". */ dtrace:helper:ustack: /!this->done/ { this->script = COPYIN_PTR(this->shared + V8_OFF_SHARED_SCRIPT); + this->map = V8_MAP_PTR(COPYIN_PTR(this->script + V8_OFF_HEAPOBJ_MAP)); + this->scriptattrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); +} + +dtrace:helper:ustack: +/!this->done && !V8_TYPE_SCRIPT(this->scriptattrs)/ +{ + APPEND_CHR('\0'); + this->done = 1; + stringof(this->buf); +} + + +dtrace:helper:ustack: +/!this->done/ +{ this->scriptnamestr = COPYIN_PTR(this->script + V8_OFF_SCRIPT_NAME); LOAD_STRFIELDS(this->scriptnamestr, this->scriptnamelen, this->scriptnameattrs); - - APPEND_CHR4(' ','a','t',' '); } dtrace:helper:ustack: -/!this->done && this->scriptnamelen == 0/ +/!this->done && this->scriptnamelen != 0/ { - APPEND_CHR8('<','u','n','k','n','o','w','n'); - APPEND_CHR('>'); + APPEND_CHR4(' ','a','t',' '); } APPEND_V8STR(this->scriptnamestr, this->scriptnamelen, this->scriptnameattrs) @@ -512,6 +597,14 @@ dtrace:helper:ustack: } dtrace:helper:ustack: +/!this->done && this->le_attrs != V8_IT_FIXEDARRAY && this->position == 0/ +{ + APPEND_CHR('\0'); + this->done = 1; + stringof(this->buf); +} + +dtrace:helper:ustack: /!this->done && this->le_attrs != V8_IT_FIXEDARRAY/ { /* @@ -519,10 +612,9 @@ dtrace:helper:ustack: * 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_CHR8(' ','p','o','s','i','t','i','o'); - APPEND_CHR('n'); + APPEND_CHR4(' ','p','o','s'); APPEND_CHR(' '); - APPEND_NUM(this->position); + APPEND_NUM(SMI_VALUE(this->position)); APPEND_CHR('\0'); this->done = 1; stringof(this->buf); -- 2.7.4