mdb_v8: update to latest version
authorBryan Cantrill <bryan@joyent.com>
Tue, 11 Mar 2014 01:07:52 +0000 (18:07 -0700)
committerTimothy J Fontaine <tjfontaine@gmail.com>
Tue, 11 Mar 2014 02:12:14 +0000 (19:12 -0700)
 * ::jsstack -v prints function defintion
 * ::jsprint works with objects with only numeric properties
 * update tests to use builtin mdb_v8
 * add more symbols to postmortem script - pending upstream
   inclusion

deps/mdb_v8/mdb_v8.c
deps/v8/tools/gen-postmortem-metadata.py
test/pummel/test-postmortem-findjsobjects.js
test/pummel/test-postmortem-jsstack.js

index a2f5795..5653431 100644 (file)
@@ -100,6 +100,7 @@ static int          v8_next_type;
 static v8_enum_t       v8_frametypes[16];
 static int             v8_next_frametype;
 
+static int             v8_warnings;
 static int             v8_silent;
 
 /*
@@ -159,6 +160,12 @@ static intptr_t V8_TYPE_JSOBJECT = -1;
 static intptr_t V8_TYPE_JSARRAY = -1;
 static intptr_t V8_TYPE_FIXEDARRAY = -1;
 
+static intptr_t V8_ELEMENTS_KIND_SHIFT;
+static intptr_t V8_ELEMENTS_KIND_BITCOUNT;
+static intptr_t V8_ELEMENTS_FAST_ELEMENTS;
+static intptr_t V8_ELEMENTS_FAST_HOLEY_ELEMENTS;
+static intptr_t V8_ELEMENTS_DICTIONARY_ELEMENTS;
+
 /*
  * Although we have this information in v8_classes, the following offsets are
  * defined explicitly because they're used directly in code below.
@@ -182,15 +189,19 @@ static ssize_t V8_OFF_MAP_INOBJECT_PROPERTIES;
 static ssize_t V8_OFF_MAP_INSTANCE_ATTRIBUTES;
 static ssize_t V8_OFF_MAP_INSTANCE_DESCRIPTORS;
 static ssize_t V8_OFF_MAP_INSTANCE_SIZE;
+static ssize_t V8_OFF_MAP_BIT_FIELD;
+static ssize_t V8_OFF_MAP_BIT_FIELD2;
 static ssize_t V8_OFF_MAP_BIT_FIELD3;
 static ssize_t V8_OFF_MAP_TRANSITIONS;
 static ssize_t V8_OFF_ODDBALL_TO_STRING;
 static ssize_t V8_OFF_SCRIPT_LINE_ENDS;
 static ssize_t V8_OFF_SCRIPT_NAME;
+static ssize_t V8_OFF_SCRIPT_SOURCE;
 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_END_POSITION;
 static ssize_t V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION;
 static ssize_t V8_OFF_SHAREDFUNCTIONINFO_INFERRED_NAME;
 static ssize_t V8_OFF_SHAREDFUNCTIONINFO_LENGTH;
@@ -289,6 +300,20 @@ static v8_constant_t v8_constants[] = {
            V8_CONSTANT_FALLBACK(0, 0), 3 },
        { &V8_TRANSITIONS_IDX_DESC,     "v8dbg_transitions_idx_descriptors",
            V8_CONSTANT_OPTIONAL },
+
+       { &V8_ELEMENTS_KIND_SHIFT,      "v8dbg_elements_kind_shift",
+           V8_CONSTANT_FALLBACK(0, 0), 3 },
+       { &V8_ELEMENTS_KIND_BITCOUNT,   "v8dbg_elements_kind_bitcount",
+           V8_CONSTANT_FALLBACK(0, 0), 5 },
+       { &V8_ELEMENTS_FAST_ELEMENTS,
+           "v8dbg_elements_fast_elements",
+           V8_CONSTANT_FALLBACK(0, 0), 2 },
+       { &V8_ELEMENTS_FAST_HOLEY_ELEMENTS,
+           "v8dbg_elements_fast_holey_elements",
+           V8_CONSTANT_FALLBACK(0, 0), 3 },
+       { &V8_ELEMENTS_DICTIONARY_ELEMENTS,
+           "v8dbg_elements_dictionary_elements",
+           V8_CONSTANT_FALLBACK(0, 0), 6 },
 };
 
 static int v8_nconstants = sizeof (v8_constants) / sizeof (v8_constants[0]);
@@ -298,7 +323,6 @@ 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[] = {
@@ -342,6 +366,8 @@ static v8_offset_t v8_offsets[] = {
            "Map", "transitions", B_TRUE },
        { &V8_OFF_MAP_INSTANCE_SIZE,
            "Map", "instance_size" },
+       { &V8_OFF_MAP_BIT_FIELD2,
+           "Map", "bit_field2", B_TRUE },
        { &V8_OFF_MAP_BIT_FIELD3,
            "Map", "bit_field3", B_TRUE },
        { &V8_OFF_ODDBALL_TO_STRING,
@@ -350,6 +376,8 @@ static v8_offset_t v8_offsets[] = {
            "Script", "line_ends" },
        { &V8_OFF_SCRIPT_NAME,
            "Script", "name" },
+       { &V8_OFF_SCRIPT_SOURCE,
+           "Script", "source" },
        { &V8_OFF_SEQASCIISTR_CHARS,
            "SeqAsciiString", "chars", B_TRUE },
        { &V8_OFF_SEQONEBYTESTR_CHARS,
@@ -358,6 +386,8 @@ static v8_offset_t v8_offsets[] = {
            "SeqTwoByteString", "chars", B_TRUE },
        { &V8_OFF_SHAREDFUNCTIONINFO_CODE,
            "SharedFunctionInfo", "code" },
+       { &V8_OFF_SHAREDFUNCTIONINFO_END_POSITION,
+           "SharedFunctionInfo", "end_position" },
        { &V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION,
            "SharedFunctionInfo", "function_token_position" },
        { &V8_OFF_SHAREDFUNCTIONINFO_INFERRED_NAME,
@@ -544,6 +574,16 @@ again:
                V8_OFF_SLICEDSTRING_PARENT = V8_OFF_SLICEDSTRING_OFFSET -
                    sizeof (uintptr_t);
 
+       /*
+        * If we don't have bit_field/bit_field2 for Map, we know that they're
+        * the second and third byte of instance_attributes.
+        */
+       if (V8_OFF_MAP_BIT_FIELD == -1)
+               V8_OFF_MAP_BIT_FIELD = V8_OFF_MAP_INSTANCE_ATTRIBUTES + 2;
+
+       if (V8_OFF_MAP_BIT_FIELD2 == -1)
+               V8_OFF_MAP_BIT_FIELD2 = V8_OFF_MAP_INSTANCE_ATTRIBUTES + 3;
+
        return (failed ? -1 : 0);
 }
 
@@ -821,12 +861,19 @@ conf_class_compute_offsets(v8_class_t *clp)
  */
 #define        JSSTR_NONE              0
 #define        JSSTR_NUDE              JSSTR_NONE
-#define        JSSTR_VERBOSE           0x1
-#define        JSSTR_QUOTED            0x2
-#define        JSSTR_ISASCII           0x4
+
+#define        JSSTR_FLAGSHIFT         16
+#define        JSSTR_VERBOSE           (0x1 << JSSTR_FLAGSHIFT)
+#define        JSSTR_QUOTED            (0x2 << JSSTR_FLAGSHIFT)
+#define        JSSTR_ISASCII           (0x4 << JSSTR_FLAGSHIFT)
+
+#define        JSSTR_MAXDEPTH          512
+#define        JSSTR_DEPTH(f)          ((f) & ((1 << JSSTR_FLAGSHIFT) - 1))
+#define        JSSTR_BUMPDEPTH(f)      ((f) + 1)
 
 static int jsstr_print(uintptr_t, uint_t, char **, size_t *);
 static boolean_t jsobj_is_undefined(uintptr_t addr);
+static boolean_t jsobj_is_hole(uintptr_t addr);
 
 static const char *
 enum_lookup_str(v8_enum_t *enums, int val, const char *dflt)
@@ -893,7 +940,7 @@ v8_warn(const char *format, ...)
        va_list alist;
        int len;
 
-       if (v8_silent)
+       if (!v8_warnings || v8_silent)
                return;
 
        va_start(alist, format);
@@ -1110,7 +1157,6 @@ read_heap_dict(uintptr_t addr,
        char *bufp;
        int rval = -1;
        uintptr_t *dict, ndict, i;
-       const char *typename;
 
        if (read_heap_array(addr, &dict, &ndict, UM_SLEEP) != 0)
                return (-1);
@@ -1130,28 +1176,31 @@ read_heap_dict(uintptr_t addr,
                if (jsobj_is_undefined(dict[i]))
                        continue;
 
-               if (read_typebyte(&type, dict[i]) != 0)
-                       goto out;
+               if (V8_IS_SMI(dict[i])) {
+                       intptr_t val = V8_SMI_VALUE(dict[i]);
 
-               typename = enum_lookup_str(v8_types, type, NULL);
+                       (void) snprintf(buf, sizeof (buf), "%ld", val);
+               } else {
+                       if (jsobj_is_hole(dict[i])) {
+                               /*
+                                * In some cases, the key can (apparently) be a
+                                * hole, in which case we skip over it.
+                                */
+                               continue;
+                       }
 
-               if (typename != NULL && strcmp(typename, "Oddball") == 0) {
-                       /*
-                        * In some cases, the key can (apparently) be a hole;
-                        * assume that any Oddball in the key field falls into
-                        * this case and skip over it.
-                        */
-                       continue;
-               }
+                       if (read_typebyte(&type, dict[i]) != 0)
+                               goto out;
 
-               if (!V8_TYPE_STRING(type))
-                       goto out;
+                       if (!V8_TYPE_STRING(type))
+                               goto out;
 
-               bufp = buf;
-               len = sizeof (buf);
+                       bufp = buf;
+                       len = sizeof (buf);
 
-               if (jsstr_print(dict[i], JSSTR_NUDE, &bufp, &len) != 0)
-                       goto out;
+                       if (jsstr_print(dict[i], JSSTR_NUDE, &bufp, &len) != 0)
+                               goto out;
+               }
 
                if (func(buf, dict[i + 1], arg) == -1)
                        goto out;
@@ -1339,12 +1388,14 @@ jsstr_print(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp)
        char buf[64];
        boolean_t verbose = flags & JSSTR_VERBOSE ? B_TRUE : B_FALSE;
 
-       if (read_typebyte(&typebyte, addr) != 0)
-               return (0);
+       if (read_typebyte(&typebyte, addr) != 0) {
+               (void) bsnprintf(bufp, lenp, "<could not read type>");
+               return (-1);
+       }
 
        if (!V8_TYPE_STRING(typebyte)) {
                (void) bsnprintf(bufp, lenp, "<not a string>");
-               return (0);
+               return (-1);
        }
 
        if (verbose) {
@@ -1355,11 +1406,18 @@ jsstr_print(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp)
                (void) mdb_inc_indent(4);
        }
 
+       if (JSSTR_DEPTH(flags) > JSSTR_MAXDEPTH) {
+               (void) bsnprintf(bufp, lenp, "<maximum depth exceeded>");
+               return (-1);
+       }
+
        if (V8_STRENC_ASCII(typebyte))
                flags |= JSSTR_ISASCII;
        else
                flags &= ~JSSTR_ISASCII;
 
+       flags = JSSTR_BUMPDEPTH(flags);
+
        if (V8_STRREP_SEQ(typebyte))
                err = jsstr_print_seq(addr, flags, bufp, lenp, 0, -1);
        else if (V8_STRREP_CONS(typebyte))
@@ -1388,17 +1446,23 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
         * 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 i, nstrchrs, nreadbytes, nreadoffset, blen, nstrbytes;
+       uintptr_t i, nreadoffset, blen, nstrbytes, nstrchrs;
+       ssize_t nreadbytes;
        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);
+       if ((blen = MIN(*lenp, 256 * 1024)) == 0)
+               return (0);
+
        buf = alloca(blen);
 
-       if (read_heap_smi(&nstrchrs, addr, V8_OFF_STRING_LENGTH) != 0)
+       if (read_heap_smi(&nstrchrs, addr, V8_OFF_STRING_LENGTH) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<string (failed to read length)>");
                return (-1);
+       }
 
        if (slicelen != -1)
                nstrchrs = slicelen;
@@ -1414,6 +1478,16 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
        nreadbytes = nstrbytes + sizeof ("\"\"") <= blen ? nstrbytes :
            blen - sizeof ("\"\"[...]");
 
+       if (nreadbytes < 0) {
+               /*
+                * We don't even have the room to store the ellipsis; zero
+                * the buffer out and set the length to zero.
+                */
+               *bufp = '\0';
+               *lenp = 0;
+               return (0);
+       }
+
        if (verbose)
                mdb_printf("length: %d chars (%d bytes), "
                    "will read %d bytes from offset %d\n",
@@ -1448,6 +1522,7 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
 
                (void) bsnprintf(bufp, lenp, "%s", quoted ? "\"" : "");
                for (i = 0; i < nreadbytes; i += 2) {
+                       /*LINTED*/
                        chrval = *((uint16_t *)(buf + i));
                        (void) bsnprintf(bufp, lenp, "%c",
                            (isascii(chrval) || chrval == 0) ?
@@ -1468,9 +1543,17 @@ jsstr_print_cons(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp)
        boolean_t quoted = flags & JSSTR_QUOTED ? B_TRUE : B_FALSE;
        uintptr_t ptr1, ptr2;
 
-       if (read_heap_ptr(&ptr1, addr, V8_OFF_CONSSTRING_FIRST) != 0 ||
-           read_heap_ptr(&ptr2, addr, V8_OFF_CONSSTRING_SECOND) != 0)
+       if (read_heap_ptr(&ptr1, addr, V8_OFF_CONSSTRING_FIRST) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<cons string (failed to read first)>");
                return (-1);
+       }
+
+       if (read_heap_ptr(&ptr2, addr, V8_OFF_CONSSTRING_SECOND) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<cons string (failed to read second)>");
+               return (-1);
+       }
 
        if (verbose) {
                mdb_printf("ptr1: %p\n", ptr1);
@@ -1480,10 +1563,12 @@ jsstr_print_cons(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp)
        if (quoted)
                (void) bsnprintf(bufp, lenp, "\"");
 
-       if (jsstr_print(ptr1, verbose, bufp, lenp) != 0)
+       flags = JSSTR_BUMPDEPTH(flags) & ~JSSTR_QUOTED;
+
+       if (jsstr_print(ptr1, flags, bufp, lenp) != 0)
                return (-1);
 
-       if (jsstr_print(ptr2, verbose, bufp, lenp) != 0)
+       if (jsstr_print(ptr2, flags, bufp, lenp) != 0)
                return (-1);
 
        if (quoted)
@@ -1499,37 +1584,50 @@ jsstr_print_sliced(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp)
        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)
+       if (read_heap_ptr(&parent, addr, V8_OFF_SLICEDSTRING_PARENT) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<sliced string (failed to read parent)>");
+               return (-1);
+       }
+
+       if (read_heap_smi(&offset, addr, V8_OFF_SLICEDSTRING_OFFSET) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<sliced string (failed to read offset)>");
                return (-1);
+       }
+
+       if (read_heap_smi(&length, addr, V8_OFF_STRING_LENGTH) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<sliced string (failed to read length)>");
+               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, "<sliced string>");
+               (void) bsnprintf(bufp, lenp,
+                   "<sliced string (failed to read parent type)>");
                return (0);
        }
 
        if (!V8_STRREP_SEQ(typebyte)) {
-               v8_warn("SlicedString %s: parent is not a sequential string",
-                   addr);
-               (void) bsnprintf(bufp, lenp, "<sliced string>");
+               (void) bsnprintf(bufp, lenp,
+                   "<sliced string (parent is not a sequential string)>");
                return (0);
        }
 
        if (quoted)
                (void) bsnprintf(bufp, lenp, "\"");
 
-       newflags = verbose ? JSSTR_VERBOSE : 0;
+       flags = JSSTR_BUMPDEPTH(flags) & ~JSSTR_QUOTED;
+
        if (V8_STRENC_ASCII(typebyte))
-               newflags |= JSSTR_ISASCII;
-       if (jsstr_print_seq(parent, newflags, bufp, lenp, offset, length) != 0)
+               flags |= JSSTR_ISASCII;
+
+       if (jsstr_print_seq(parent, flags, bufp, lenp, offset, length) != 0)
                return (-1);
 
        if (quoted)
@@ -1543,8 +1641,9 @@ 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);
+       char *buf;
        boolean_t quoted = flags & JSSTR_QUOTED ? B_TRUE : B_FALSE;
+       int rval = -1;
 
        if ((flags & JSSTR_ISASCII) == 0) {
                (void) bsnprintf(bufp, lenp, "<external two-byte string>");
@@ -1554,38 +1653,51 @@ jsstr_print_external(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp)
        if (flags & JSSTR_VERBOSE)
                mdb_printf("assuming Node.js string\n");
 
-       if (read_heap_ptr(&ptr1, addr, V8_OFF_EXTERNALSTRING_RESOURCE) != 0)
+       if (read_heap_ptr(&ptr1, addr, V8_OFF_EXTERNALSTRING_RESOURCE) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<external string (failed to read resource)>");
                return (-1);
+       }
 
        if (mdb_vread(&ptr2, sizeof (ptr2),
            ptr1 + NODE_OFF_EXTSTR_DATA) == -1) {
-               v8_warn("failed to read node external pointer: %p",
+               (void) bsnprintf(bufp, lenp, "<external string (failed to "
+                   "read node external pointer %p)>",
                    ptr1 + NODE_OFF_EXTSTR_DATA);
                return (-1);
        }
 
+       buf = mdb_alloc(blen, UM_SLEEP);
+
        if (mdb_readstr(buf, blen, ptr2) == -1) {
-               v8_warn("failed to read ExternalString data");
-               return (-1);
+               (void) bsnprintf(bufp, lenp, "<external string "
+                   "(failed to read ExternalString data)>");
+               goto out;
        }
 
        if (buf[0] != '\0' && !isascii(buf[0])) {
-               v8_warn("failed to read ExternalString ascii data\n");
-               return (-1);
+               (void) bsnprintf(bufp, lenp, "<external string "
+                   "(failed to read ExternalString ascii data)>");
+               goto out;
        }
 
        (void) bsnprintf(bufp, lenp, "%s%s%s",
            quoted ? "\"" : "", buf, quoted ? "\"" : "");
 
-       return (0);
+       rval = 0;
+out:
+       mdb_free(buf, blen);
+
+       return (rval);
 }
 
 /*
- * Returns true if the given address refers to the "undefined" object.  Returns
- * false on failure (since we shouldn't fail on the actual "undefined" value).
+ * Returns true if the given address refers to the named oddball object (e.g.
+ * "undefined").  Returns false on failure (since we shouldn't fail on the
+ * actual "undefined" value).
  */
 static boolean_t
-jsobj_is_undefined(uintptr_t addr)
+jsobj_is_oddball(uintptr_t addr, char *oddball)
 {
        uint8_t type;
        uintptr_t strptr;
@@ -1602,7 +1714,6 @@ jsobj_is_undefined(uintptr_t addr)
        }
 
        v8_silent--;
-
        typename = enum_lookup_str(v8_types, type, "<unknown>");
        if (strcmp(typename, "Oddball") != 0)
                return (B_FALSE);
@@ -1613,16 +1724,28 @@ jsobj_is_undefined(uintptr_t addr)
        if (jsstr_print(strptr, JSSTR_NUDE, &bufp, &len) != 0)
                return (B_FALSE);
 
-       return (strcmp(buf, "undefined") == 0);
+       return (strcmp(buf, oddball) == 0);
+}
+
+static boolean_t
+jsobj_is_undefined(uintptr_t addr)
+{
+       return (jsobj_is_oddball(addr, "undefined"));
+}
+
+static boolean_t
+jsobj_is_hole(uintptr_t addr)
+{
+       return (jsobj_is_oddball(addr, "hole"));
 }
 
 static int
 jsobj_properties(uintptr_t addr,
     int (*func)(const char *, uintptr_t, void *), void *arg)
 {
-       uintptr_t ptr, map;
-       uintptr_t *props = NULL, *descs = NULL, *content = NULL, *trans;
-       size_t size, nprops, ndescs, ncontent, ntrans;
+       uintptr_t ptr, map, elements;
+       uintptr_t *props = NULL, *descs = NULL, *content = NULL, *trans, *elts;
+       size_t size, nprops, ndescs, ncontent, ntrans, len;
        ssize_t ii, rndescs;
        uint8_t type, ninprops;
        int rval = -1;
@@ -1661,6 +1784,51 @@ jsobj_properties(uintptr_t addr,
        if (mdb_vread(&map, ps, addr + V8_OFF_HEAPOBJECT_MAP) == -1)
                goto err;
 
+       /*
+        * Check to see if our elements member is an array and non-zero; if
+        * so, it contains numerically-named properties.
+        */
+       if (V8_ELEMENTS_KIND_SHIFT != -1 &&
+           read_heap_ptr(&elements, addr, V8_OFF_JSOBJECT_ELEMENTS) == 0 &&
+           read_heap_array(elements, &elts, &len, UM_SLEEP) == 0 && len != 0) {
+               uint8_t bit_field2, kind;
+               size_t sz = len * sizeof (uintptr_t);
+
+               if (mdb_vread(&bit_field2, sizeof (bit_field2),
+                   map + V8_OFF_MAP_BIT_FIELD2) == -1) {
+                       mdb_free(elts, sz);
+                       goto err;
+               }
+
+               kind = bit_field2 >> V8_ELEMENTS_KIND_SHIFT;
+               kind &= (1 << V8_ELEMENTS_KIND_BITCOUNT) - 1;
+
+               if (kind == V8_ELEMENTS_FAST_ELEMENTS ||
+                   kind == V8_ELEMENTS_FAST_HOLEY_ELEMENTS) {
+                       for (ii = 0; ii < len; ii++) {
+                               char name[10];
+
+                               if (kind == V8_ELEMENTS_FAST_HOLEY_ELEMENTS &&
+                                   jsobj_is_hole(elts[ii]))
+                                       continue;
+
+                               snprintf(name, sizeof (name), "%d", ii);
+
+                               if (func(name, elts[ii], arg) != 0) {
+                                       mdb_free(elts, sz);
+                                       goto err;
+                               }
+                       }
+               } else if (kind == V8_ELEMENTS_DICTIONARY_ELEMENTS) {
+                       if (read_heap_dict(elements, func, arg) != 0) {
+                               mdb_free(elts, sz);
+                               goto err;
+                       }
+               }
+
+               mdb_free(elts, sz);
+       }
+
        if (V8_DICT_SHIFT != -1) {
                uintptr_t bit_field3;
 
@@ -1804,18 +1972,27 @@ jsobj_properties(uintptr_t addr,
                        /* property is stored directly in the object */
                        if (mdb_vread(&ptr, sizeof (ptr), addr + V8_OFF_HEAP(
                            size + val * sizeof (uintptr_t))) == -1) {
-                               v8_warn("failed to read in-object "
-                                   "property at %p\n", addr + V8_OFF_HEAP(
-                                   size + val * sizeof (uintptr_t)));
+                               v8_warn("object %p: failed to read in-object "
+                                   "property at %p\n", addr, addr +
+                                   V8_OFF_HEAP(size + val *
+                                   sizeof (uintptr_t)));
                                continue;
                        }
                } else {
                        /* property should be in "props" array */
                        if (val >= nprops) {
-                               v8_warn("property descriptor %d: value index "
-                                   "value (%d) out of bounds (%d)\n", ii, val,
-                                   nprops);
-                               continue;
+                               /*
+                                * This can happen when properties are deleted.
+                                * If this value isn't obviously corrupt, we'll
+                                * just silently ignore it.
+                                */
+                               if (val < rndescs)
+                                       continue;
+
+                               v8_warn("object %p: property descriptor %d: "
+                                   "value index value (%d) out of bounds "
+                                   "(%d)\n", addr, ii, val, nprops);
+                               goto err;
                        }
 
                        ptr = props[val];
@@ -1845,11 +2022,15 @@ err:
  * undefined, prints the token position instead.
  */
 static int
-jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos, char *buf, size_t buflen)
+jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos,
+    char *buf, size_t buflen, int *lineno)
 {
        uintptr_t size, bufsz, lower, upper, ii = 0;
        uintptr_t *data;
 
+       if (lineno != NULL)
+               *lineno = -1;
+
        if (jsobj_is_undefined(lendsp)) {
                /*
                 * The token position is an SMI, but it comes in as its raw
@@ -1858,6 +2039,10 @@ jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos, char *buf, size_t buflen)
                 * we must convert it here.
                 */
                mdb_snprintf(buf, buflen, "position %d", V8_SMI_VALUE(tokpos));
+
+               if (lineno != NULL)
+                       *lineno = 0;
+
                return (0);
        }
 
@@ -1883,12 +2068,20 @@ jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos, char *buf, size_t buflen)
        if (tokpos > data[upper]) {
                (void) strlcpy(buf, "position out of range", buflen);
                mdb_free(data, bufsz);
+
+               if (lineno != NULL)
+                       *lineno = 0;
+
                return (0);
        }
 
        if (tokpos <= data[0]) {
                (void) strlcpy(buf, "line 1", buflen);
                mdb_free(data, bufsz);
+
+               if (lineno != NULL)
+                       *lineno = 1;
+
                return (0);
        }
 
@@ -1902,12 +2095,118 @@ jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos, char *buf, size_t buflen)
                        break;
        }
 
+       if (lineno != NULL)
+               *lineno = ii + 1;
+
        (void) mdb_snprintf(buf, buflen, "line %d", ii + 1);
        mdb_free(data, bufsz);
        return (0);
 }
 
 /*
+ * Given a Script object, prints nlines on either side of lineno, with each
+ * line prefixed by prefix (if non-NULL).
+ */
+static void
+jsfunc_lines(uintptr_t scriptp,
+    uintptr_t start, uintptr_t end, int nlines, char *prefix)
+{
+       uintptr_t src;
+       char *buf, *bufp;
+       size_t bufsz = 1024, len;
+       int i, line, slop = 10;
+       boolean_t newline = B_TRUE;
+       int startline = -1, endline = -1;
+
+       if (read_heap_ptr(&src, scriptp, V8_OFF_SCRIPT_SOURCE) != 0)
+               return;
+
+       for (;;) {
+               if ((buf = mdb_zalloc(bufsz, UM_NOSLEEP)) == NULL) {
+                       mdb_warn("failed to allocate source code "
+                           "buffer of size %d", bufsz);
+                       return;
+               }
+
+               bufp = buf;
+               len = bufsz;
+
+               if (jsstr_print(src, JSSTR_NUDE, &bufp, &len) != 0) {
+                       mdb_free(buf, bufsz);
+                       return;
+               }
+
+               if (len > slop)
+                       break;
+
+               mdb_free(buf, bufsz);
+               bufsz <<= 1;
+       }
+
+       if (end >= bufsz)
+               return;
+
+       /*
+        * First, take a pass to determine where our lines actually start.
+        */
+       for (i = 0, line = 1; buf[i] != '\0'; i++) {
+               if (buf[i] == '\n')
+                       line++;
+
+               if (i == start)
+                       startline = line;
+
+               if (i == end) {
+                       endline = line;
+                       break;
+               }
+       }
+
+       if (startline == -1 || endline == -1) {
+               mdb_warn("for script %p, could not determine startline/endline"
+                   " (start %ld, end %ld, nlines %d)",
+                   scriptp, start, end, nlines);
+               mdb_free(buf, bufsz);
+               return;
+       }
+
+       for (i = 0, line = 1; buf[i] != '\0'; i++) {
+               if (buf[i] == '\n') {
+                       line++;
+                       newline = B_TRUE;
+               }
+
+               if (line < startline - nlines)
+                       continue;
+
+               if (line > endline + nlines)
+                       break;
+
+               mdb_printf("%c", buf[i]);
+
+               if (newline) {
+                       if (line >= startline && line <= endline)
+                               mdb_printf("%<b>");
+
+                       if (prefix != NULL)
+                               mdb_printf(prefix, line);
+
+                       if (line >= startline && line <= endline)
+                               mdb_printf("%</b>");
+
+                       newline = B_FALSE;
+               }
+       }
+
+       mdb_printf("\n");
+
+       if (line == endline)
+               mdb_printf("%</b>");
+
+       mdb_free(buf, bufsz);
+}
+
+/*
  * Given a SharedFunctionInfo object, prints into bufp a name of the function
  * suitable for printing.  This function attempts to infer a name for anonymous
  * functions.
@@ -1919,8 +2218,13 @@ jsfunc_name(uintptr_t funcinfop, char **bufp, size_t *lenp)
        char *bufs = *bufp;
 
        if (read_heap_ptr(&ptrp, funcinfop,
-           V8_OFF_SHAREDFUNCTIONINFO_NAME) != 0 ||
-           jsstr_print(ptrp, JSSTR_NUDE, bufp, lenp) != 0)
+           V8_OFF_SHAREDFUNCTIONINFO_NAME) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<function (failed to read SharedFunctionInfo)>");
+               return (-1);
+       }
+
+       if (jsstr_print(ptrp, JSSTR_NUDE, bufp, lenp) != 0)
                return (-1);
 
        if (*bufp != bufs)
@@ -1959,6 +2263,7 @@ typedef struct jsobj_print {
        int jsop_nprops;
        const char *jsop_member;
        boolean_t jsop_found;
+       boolean_t jsop_descended;
 } jsobj_print_t;
 
 static int jsobj_print_number(uintptr_t, jsobj_print_t *);
@@ -2001,12 +2306,14 @@ jsobj_print(uintptr_t addr, jsobj_print_t *jsop)
        }
 
        if (!V8_IS_HEAPOBJECT(addr)) {
-               v8_warn("not a heap object: %p\n", addr);
+               (void) bsnprintf(bufp, lenp, "<not a heap object>");
                return (-1);
        }
 
-       if (read_typebyte(&type, addr) != 0)
+       if (read_typebyte(&type, addr) != 0) {
+               (void) bsnprintf(bufp, lenp, "<couldn't read type>");
                return (-1);
+       }
 
        if (V8_TYPE_STRING(type)) {
                if (jsstr_print(addr, JSSTR_QUOTED, bufp, lenp) == -1)
@@ -2018,11 +2325,14 @@ jsobj_print(uintptr_t addr, jsobj_print_t *jsop)
        klass = enum_lookup_str(v8_types, type, "<unknown>");
 
        for (ent = &table[0]; ent->name != NULL; ent++) {
-               if (strcmp(klass, ent->name) == 0)
+               if (strcmp(klass, ent->name) == 0) {
+                       jsop->jsop_descended = B_TRUE;
                        return (ent->func(addr, jsop));
+               }
        }
 
-       v8_warn("%p: unknown JavaScript object type \"%s\"\n", addr, klass);
+       (void) bsnprintf(bufp, lenp,
+           "<unknown JavaScript object type \"%s\">", klass);
        return (-1);
 }
 
@@ -2158,10 +2468,20 @@ jsobj_print_jsarray_member(uintptr_t addr, jsobj_print_t *jsop)
        uintptr_t ptr;
        const char *member = jsop->jsop_member, *end, *p;
        size_t elt = 0, place = 1, len, rv;
+       char **bufp = jsop->jsop_bufp;
+       size_t *lenp = jsop->jsop_lenp;
 
-       if (read_heap_ptr(&ptr, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0 ||
-           read_heap_array(ptr, &elts, &len, UM_SLEEP | UM_GC) != 0)
+       if (read_heap_ptr(&ptr, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<array member (failed to read elements)>");
                return (-1);
+       }
+
+       if (read_heap_array(ptr, &elts, &len, UM_SLEEP | UM_GC) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<array member (failed to read array)>");
+               return (-1);
+       }
 
        if (*member != '[') {
                mdb_warn("expected bracketed array index; "
@@ -2245,9 +2565,16 @@ jsobj_print_jsarray(uintptr_t addr, jsobj_print_t *jsop)
                return (0);
        }
 
-       if (read_heap_ptr(&ptr, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0 ||
-           read_heap_array(ptr, &elts, &len, UM_SLEEP | UM_GC) != 0)
+       if (read_heap_ptr(&ptr, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0) {
+               (void) bsnprintf(bufp, lenp,
+                   "<array (failed to read elements)>");
                return (-1);
+       }
+
+       if (read_heap_array(ptr, &elts, &len, UM_SLEEP | UM_GC) != 0) {
+               (void) bsnprintf(bufp, lenp, "<array (failed to read array)>");
+               return (-1);
+       }
 
        if (len == 0) {
                (void) bsnprintf(bufp, lenp, "[]");
@@ -2267,7 +2594,7 @@ jsobj_print_jsarray(uintptr_t addr, jsobj_print_t *jsop)
 
        (void) bsnprintf(bufp, lenp, "[\n");
 
-       for (ii = 0; ii < len; ii++) {
+       for (ii = 0; ii < len && *lenp > 0; ii++) {
                (void) bsnprintf(bufp, lenp, "%*s", indent + 4, "");
                (void) jsobj_print(elts[ii], &descend);
                (void) bsnprintf(bufp, lenp, ",\n");
@@ -2308,17 +2635,23 @@ jsobj_print_jsdate(uintptr_t addr, jsobj_print_t *jsop)
                return (0);
        }
 
-       if (read_heap_ptr(&value, addr, V8_OFF_JSDATE_VALUE) != 0)
+       if (read_heap_ptr(&value, addr, V8_OFF_JSDATE_VALUE) != 0) {
+               (void) bsnprintf(bufp, lenp, "<JSDate (failed to read value)>");
                return (-1);
+       }
 
-       if (read_typebyte(&type, value) != 0)
+       if (read_typebyte(&type, value) != 0) {
+               (void) bsnprintf(bufp, lenp, "<JSDate (failed to read type)>");
                return (-1);
+       }
 
        if (strcmp(enum_lookup_str(v8_types, type, ""), "HeapNumber") != 0)
                return (-1);
 
-       if (read_heap_double(&numval, value, V8_OFF_HEAPNUMBER_VALUE) == -1)
+       if (read_heap_double(&numval, value, V8_OFF_HEAPNUMBER_VALUE) == -1) {
+               (void) bsnprintf(bufp, lenp, "<JSDate (failed to read num)>");
                return (-1);
+       }
 
        mdb_snprintf(buf, sizeof (buf), "%Y",
            (time_t)((long long)numval / MILLISEC));
@@ -2413,12 +2746,14 @@ dcmd_v8function(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
            NULL) != argc)
                return (DCMD_USAGE);
 
+       v8_warnings++;
+
        if (read_typebyte(&type, addr) != 0)
-               return (DCMD_ERR);
+               goto err;
 
        if (strcmp(enum_lookup_str(v8_types, type, ""), "JSFunction") != 0) {
                v8_warn("%p is not an instance of JSFunction\n", addr);
-               return (DCMD_ERR);
+               goto err;
        }
 
        if (read_heap_ptr(&funcinfop, addr, V8_OFF_JSFUNCTION_SHARED) != 0 ||
@@ -2428,12 +2763,12 @@ dcmd_v8function(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
            V8_OFF_SHAREDFUNCTIONINFO_SCRIPT) != 0 ||
            read_heap_ptr(&namep, scriptp, V8_OFF_SCRIPT_NAME) != 0 ||
            read_heap_ptr(&lendsp, scriptp, V8_OFF_SCRIPT_LINE_ENDS) != 0)
-               return (DCMD_ERR);
+               goto err;
 
        bufp = buf;
        len = sizeof (buf);
        if (jsfunc_name(funcinfop, &bufp, &len) != 0)
-               return (DCMD_ERR);
+               goto err;
 
        mdb_printf("%p: JSFunction: %s\n", addr, buf);
 
@@ -2444,16 +2779,22 @@ dcmd_v8function(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
        if (jsstr_print(namep, JSSTR_NUDE, &bufp, &len) == 0)
                mdb_printf("%s ", buf);
 
-       if (jsfunc_lineno(lendsp, tokpos, buf, sizeof (buf)) == 0)
+       if (jsfunc_lineno(lendsp, tokpos, buf, sizeof (buf), NULL) == 0)
                mdb_printf("%s", buf);
 
        mdb_printf("\n");
 
        if (read_heap_ptr(&codep,
            funcinfop, V8_OFF_SHAREDFUNCTIONINFO_CODE) != 0)
-               return (DCMD_ERR);
+               goto err;
+
+       v8_warnings--;
 
        return (do_v8code(codep, opt_d));
+
+err:
+       v8_warnings--;
+       return (DCMD_ERR);
 }
 
 /* ARGSUSED */
@@ -2636,15 +2977,16 @@ do_jsframe_special(uintptr_t fptr, uintptr_t raddr, char *prop)
 
 static int
 do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
-    char *func, char *prop)
+    char *func, char *prop, uintptr_t nlines)
 {
-       uintptr_t funcp, funcinfop, tokpos, scriptp, lendsp, ptrp;
+       uintptr_t funcp, funcinfop, tokpos, endpos, scriptp, lendsp, ptrp;
        uintptr_t ii, nargs;
        const char *typename;
        char *bufp;
        size_t len;
        uint8_t type;
        char buf[256];
+       int lineno;
 
        /*
         * Check for non-JavaScript frames first.
@@ -2667,12 +3009,8 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
         * Check if this thing is really a JSFunction at all. For some frames,
         * it's a Code object, presumably indicating some internal frame.
         */
-       v8_silent++;
-
        if (read_typebyte(&type, funcp) != 0 ||
            (typename = enum_lookup_str(v8_types, type, NULL)) == NULL) {
-               v8_silent--;
-
                if (func != NULL || prop != NULL)
                        return (DCMD_OK);
 
@@ -2680,8 +3018,6 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
                return (DCMD_OK);
        }
 
-       v8_silent--;
-
        if (strcmp("Code", typename) == 0) {
                if (func != NULL || prop != NULL)
                        return (DCMD_OK);
@@ -2748,16 +3084,6 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
        if (read_heap_ptr(&lendsp, scriptp, V8_OFF_SCRIPT_LINE_ENDS) != 0)
                return (DCMD_ERR);
 
-       (void) jsfunc_lineno(lendsp, tokpos, buf, sizeof (buf));
-
-       if (prop != NULL && strcmp(prop, "posn") == 0) {
-               mdb_printf("%s\n", buf);
-               return (DCMD_OK);
-       }
-
-       if (prop == NULL)
-               mdb_printf("posn: %s\n", buf);
-
        if (read_heap_smi(&nargs, funcinfop,
            V8_OFF_SHAREDFUNCTIONINFO_LENGTH) == 0) {
                for (ii = 0; ii < nargs; ii++) {
@@ -2787,11 +3113,27 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
                }
        }
 
+       (void) jsfunc_lineno(lendsp, tokpos, buf, sizeof (buf), &lineno);
+
        if (prop != NULL) {
+               if (strcmp(prop, "posn") == 0) {
+                       mdb_printf("%s\n", buf);
+                       return (DCMD_OK);
+               }
+
                mdb_warn("unknown frame property '%s'\n", prop);
                return (DCMD_ERR);
        }
 
+       mdb_printf("posn: %s", buf);
+
+       if (nlines != 0 && read_heap_smi(&endpos, funcinfop,
+           V8_OFF_SHAREDFUNCTIONINFO_END_POSITION) == 0) {
+               jsfunc_lines(scriptp,
+                   V8_SMI_VALUE(tokpos), endpos, nlines, "%5d ");
+       }
+
+       mdb_printf("\n");
        (void) mdb_dec_indent(4);
 
        return (DCMD_OK);
@@ -3681,11 +4023,13 @@ dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
        uintptr_t fptr, raddr;
        boolean_t opt_v = B_FALSE, opt_i = B_FALSE;
        char *opt_f = NULL, *opt_p = NULL;
+       uintptr_t opt_n = 5;
 
        if (mdb_getopts(argc, argv,
            'v', MDB_OPT_SETBITS, B_TRUE, &opt_v,
            'i', MDB_OPT_SETBITS, B_TRUE, &opt_i,
            'f', MDB_OPT_STR, &opt_f,
+           'n', MDB_OPT_UINTPTR, &opt_n,
            'p', MDB_OPT_STR, &opt_p, NULL) != argc)
                return (DCMD_USAGE);
 
@@ -3697,7 +4041,7 @@ dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
         * overridden with the "-i" option (for "immediate").
         */
        if (opt_i)
-               return (do_jsframe(addr, 0, opt_v, opt_f, opt_p));
+               return (do_jsframe(addr, 0, opt_v, opt_f, opt_p, opt_n));
 
        if (mdb_vread(&raddr, sizeof (raddr),
            addr + sizeof (uintptr_t)) == -1) {
@@ -3714,7 +4058,7 @@ dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
        if (fptr == NULL)
                return (DCMD_OK);
 
-       return (do_jsframe(fptr, raddr, opt_v, opt_f, opt_p));
+       return (do_jsframe(fptr, raddr, opt_v, opt_f, opt_p, opt_n));
 }
 
 /* ARGSUSED */
@@ -3767,8 +4111,12 @@ dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
                        len = bufsz;
                }
 
-               if (jsop.jsop_member == NULL && rv != 0)
+               if (jsop.jsop_member == NULL && rv != 0) {
+                       if (!jsop.jsop_descended)
+                               mdb_warn("%s\n", buf);
+
                        return (DCMD_ERR);
+               }
 
                if (jsop.jsop_member && !jsop.jsop_found) {
                        if (jsop.jsop_baseaddr)
@@ -3883,13 +4231,14 @@ dcmd_v8array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 static int
 dcmd_jsstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
-       uintptr_t raddr;
-       boolean_t opt_v;
+       uintptr_t raddr, opt_n = 5;
+       boolean_t opt_v = B_FALSE;
        char *opt_f = NULL, *opt_p = NULL;
 
        if (mdb_getopts(argc, argv,
            'v', MDB_OPT_SETBITS, B_TRUE, &opt_v,
            'f', MDB_OPT_STR, &opt_f,
+           'n', MDB_OPT_UINTPTR, &opt_n,
            'p', MDB_OPT_STR, &opt_p,
            NULL) != argc)
                return (DCMD_USAGE);
@@ -3901,7 +4250,7 @@ dcmd_jsstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
         */
        if (!(flags & DCMD_ADDRSPEC)) {
                if (load_current_context(&addr, &raddr) != 0 ||
-                   do_jsframe(addr, raddr, opt_v, opt_f, opt_p) != 0)
+                   do_jsframe(addr, raddr, opt_v, opt_f, opt_p, opt_n) != 0)
                        return (DCMD_ERR);
        }
 
@@ -3993,6 +4342,16 @@ dcmd_v8load(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
        return (DCMD_OK);
 }
 
+/* ARGSUSED */
+static int
+dcmd_v8warnings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+       v8_warnings ^= 1;
+       mdb_printf("v8 warnings are now %s\n", v8_warnings ? "on" : "off");
+
+       return (DCMD_OK);
+}
+
 static int
 walk_jsframes_init(mdb_walk_state_t *wsp)
 {
@@ -4116,11 +4475,11 @@ static const mdb_dcmd_t v8_mdb_dcmds[] = {
        /*
         * Commands to inspect JavaScript-level state
         */
-       { "jsframe", ":[-iv] [-f function] [-p property]",
+       { "jsframe", ":[-iv] [-f function] [-p property] [-n numlines]",
                "summarize a JavaScript stack frame", dcmd_jsframe },
        { "jsprint", ":[-ab] [-d depth] [member]", "print a JavaScript object",
                dcmd_jsprint },
-       { "jsstack", "[-v] [-f function] [-p property]",
+       { "jsstack", "[-v] [-f function] [-p property] [-n numlines]",
                "print a JavaScript stacktrace", dcmd_jsstack },
        { "findjsobjects", "?[-vb] [-r | -c cons | -p prop]", "find JavaScript "
                "objects", dcmd_findjsobjects, dcmd_findjsobjects_help },
@@ -4150,6 +4509,8 @@ static const mdb_dcmd_t v8_mdb_dcmds[] = {
                dcmd_v8type },
        { "v8types", NULL, "list known V8 heap object types",
                dcmd_v8types },
+       { "v8warnings", NULL, "toggle V8 warnings",
+               dcmd_v8warnings },
 
        { NULL }
 };
index 2837727..1a4f221 100644 (file)
@@ -106,6 +106,14 @@ consts_misc = [
         'value': 'JavaScriptFrameConstants::kFunctionOffset' },
     { 'name': 'off_fp_args',
         'value': 'JavaScriptFrameConstants::kLastParameterOffset' },
+
+    { 'name': 'elements_kind_shift',
+        'value': 'Map::kElementsKindShift' },
+    { 'name': 'elements_kind_bitcount',
+        'value': 'Map::kElementsKindBitCount' },
+    { 'name': 'elements_fast_elements', 'value': 'FAST_ELEMENTS' },
+    { 'name': 'elements_fast_holey_elements', 'value': 'FAST_HOLEY_ELEMENTS' },
+    { 'name': 'elements_dictionary_elements', 'value': 'DICTIONARY_ELEMENTS' },
 ];
 
 #
index 292b060..65214a0 100644 (file)
@@ -22,6 +22,7 @@
 var common = require('../common');
 var assert = require('assert');
 var os = require('os');
+var path = require('path');
 var util = require('util');
 
 if (os.type() != 'SunOS') {
@@ -89,7 +90,14 @@ gcore.on('exit', function (code) {
     console.log('mdb stderr: ' + data);
   });
 
-  mdb.stdin.write('::load v8.so\n');
+  var mod = util.format('::load %s\n',
+                        path.join(__dirname,
+                                  '..',
+                                  '..',
+                                  'out',
+                                  'Release',
+                                  'mdb_v8.so'));
+  mdb.stdin.write(mod);
   mdb.stdin.write('::findjsobjects -c LanguageH | ');
   mdb.stdin.write('::findjsobjects | ::jsprint\n');
   mdb.stdin.write('::findjsobjects -p OBEY | ');
index 735e39e..04b3352 100644 (file)
@@ -90,6 +90,14 @@ dtrace.on('exit', function (code) {
    */
   var mdb = spawn('mdb', args, { stdio: 'pipe' });
 
+  var mod = util.format('::load %s\n',
+                        path.join(__dirname,
+                                  '..',
+                                  '..',
+                                  'out',
+                                  'Release',
+                                  'mdb_v8.so'));
+
   mdb.on('exit', function (code) {
     var retained = '; core retained as ' + corefile;
 
@@ -157,7 +165,7 @@ dtrace.on('exit', function (code) {
       console.log('mdb (second) stderr: ' + data);
     });
 
-    mdb.stdin.write('::load v8.so\n');
+    mdb.stdin.write(mod);
     mdb.stdin.write(straddr + '::v8str\n');
     mdb.stdin.end();
   });
@@ -170,7 +178,7 @@ dtrace.on('exit', function (code) {
     console.log('mdb stderr: ' + data);
   });
 
-  mdb.stdin.write('::load v8.so\n');
+  mdb.stdin.write(mod);
   mdb.stdin.write('::jsstack -v\n');
   mdb.stdin.end();
 });