diff options
author | Bryan Cantrill <bryan@joyent.com> | 2013-02-04 08:22:58 +0000 |
---|---|---|
committer | Bryan Cantrill <bryan@joyent.com> | 2013-02-04 08:22:58 +0000 |
commit | 600bd902c554b22fe96b6fb340df43c817828eef (patch) | |
tree | 707b10f3362d36603a51e5578bce2b81effaf4da /usr/src | |
parent | c312f0a7563f40ced48ca5883039bcbce242c8c8 (diff) | |
download | illumos-joyent-600bd902c554b22fe96b6fb340df43c817828eef.tar.gz |
OS-1854 mdb_v8's ::jsprint should take an optional member
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/mdb/common/modules/v8/mdb_v8.c | 150 |
1 files changed, 145 insertions, 5 deletions
diff --git a/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c b/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c index cddda96e4e..9d34a7d68f 100644 --- a/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c +++ b/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c @@ -1772,6 +1772,8 @@ typedef struct jsobj_print { uint64_t jsop_depth; boolean_t jsop_printaddr; int jsop_nprops; + const char *jsop_member; + boolean_t jsop_found; } jsobj_print_t; static int jsobj_print_number(uintptr_t, jsobj_print_t *); @@ -1802,7 +1804,7 @@ jsobj_print(uintptr_t addr, jsobj_print_t *jsop) { NULL } }, *ent; - if (jsop->jsop_printaddr) + if (jsop->jsop_printaddr && jsop->jsop_member == NULL) (void) bsnprintf(bufp, lenp, "%p: ", addr); if (V8_IS_SMI(addr)) { @@ -1890,11 +1892,50 @@ jsobj_print_prop(const char *desc, uintptr_t val, void *arg) } static int +jsobj_print_prop_member(const char *desc, uintptr_t val, void *arg) +{ + jsobj_print_t *jsop = arg, descend; + const char *member = jsop->jsop_member, *next = member; + int rv; + + for (; *next != '\0' && *next != '.' && *next != '['; next++) + continue; + + if (*member == '[') { + mdb_warn("cannot use array indexing on an object\n"); + return (-1); + } + + if (strncmp(member, desc, next - member) != 0) + return (0); + + /* + * This property matches the desired member; descend. + */ + descend = *jsop; + + if (*next == '\0') { + descend.jsop_member = NULL; + descend.jsop_found = B_TRUE; + } else { + descend.jsop_member = *next == '.' ? next + 1 : next; + } + + rv = jsobj_print(val, &descend); + jsop->jsop_found = descend.jsop_found; + + return (rv); +} + +static int jsobj_print_jsobject(uintptr_t addr, jsobj_print_t *jsop) { char **bufp = jsop->jsop_bufp; size_t *lenp = jsop->jsop_lenp; + if (jsop->jsop_member != NULL) + return (jsobj_properties(addr, jsobj_print_prop_member, jsop)); + if (jsop->jsop_depth == 0) { (void) bsnprintf(bufp, lenp, "[...]"); return (0); @@ -1919,6 +1960,82 @@ jsobj_print_jsobject(uintptr_t addr, jsobj_print_t *jsop) } static int +jsobj_print_jsarray_member(uintptr_t addr, jsobj_print_t *jsop) +{ + uintptr_t *elts; + jsobj_print_t descend; + uintptr_t ptr; + const char *member = jsop->jsop_member, *end, *p; + size_t elt = 0, place = 1, len, rv; + + if (read_heap_ptr(&ptr, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0 || + read_heap_array(ptr, &elts, &len, UM_GC) != 0) + return (-1); + + if (*member != '[') { + mdb_warn("expected bracketed array index; " + "found '%s'\n", member); + return (-1); + } + + if ((end = strchr(member, ']')) == NULL) { + mdb_warn("missing array index terminator\n"); + return (-1); + } + + /* + * We know where our array index ends; convert it to an integer + * by stepping through it from least significant digit to most. + */ + for (p = end - 1; p > member; p--) { + if (*p < '0' || *p > '9') { + mdb_warn("illegal array index at '%c'\n", *p); + return (-1); + } + + elt += (*p - '0') * place; + place *= 10; + } + + if (place == 1) { + mdb_warn("missing array index\n"); + return (-1); + } + + if (elt >= len) { + mdb_warn("array index %d exceeds size of %d\n", elt, len); + return (-1); + } + + descend = *jsop; + + switch (*(++end)) { + case '\0': + descend.jsop_member = NULL; + descend.jsop_found = B_TRUE; + break; + + case '.': + descend.jsop_member = end + 1; + break; + + case '[': + descend.jsop_member = end; + break; + + default: + mdb_warn("illegal character '%c' following " + "array index terminator\n", *end); + return (-1); + } + + rv = jsobj_print(elts[elt], &descend); + jsop->jsop_found = descend.jsop_found; + + return (rv); +} + +static int jsobj_print_jsarray(uintptr_t addr, jsobj_print_t *jsop) { char **bufp = jsop->jsop_bufp; @@ -1929,6 +2046,9 @@ jsobj_print_jsarray(uintptr_t addr, jsobj_print_t *jsop) uintptr_t *elts; size_t ii, len; + if (jsop->jsop_member != NULL) + return (jsobj_print_jsarray_member(addr, jsop)); + if (jsop->jsop_depth == 0) { (void) bsnprintf(bufp, lenp, "[...]"); return (0); @@ -3031,17 +3151,28 @@ dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) char *buf, *bufp; size_t bufsz = 262144, len = bufsz; jsobj_print_t jsop; - int rv; + int rv, i; bzero(&jsop, sizeof (jsop)); jsop.jsop_depth = 2; jsop.jsop_printaddr = B_FALSE; - if (mdb_getopts(argc, argv, + i = mdb_getopts(argc, argv, 'a', MDB_OPT_SETBITS, B_TRUE, &jsop.jsop_printaddr, - 'd', MDB_OPT_UINT64, &jsop.jsop_depth, NULL) != argc) + 'd', MDB_OPT_UINT64, &jsop.jsop_depth, NULL); + + if (i < argc - 1) return (DCMD_USAGE); + if (i != argc) { + const mdb_arg_t *member = &argv[argc - 1]; + + if (member->a_type != MDB_TYPE_STRING) + return (DCMD_USAGE); + + jsop.jsop_member = member->a_un.a_str; + } + for (;;) { if ((buf = bufp = mdb_zalloc(bufsz, UM_NOSLEEP)) == NULL) return (DCMD_ERR); @@ -3059,6 +3190,15 @@ dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) len = bufsz; } + if (jsop.jsop_member && !jsop.jsop_found) { + if (rv != 0) + return (DCMD_ERR); + + mdb_warn("'%s' not found in %p\n", jsop.jsop_member, addr); + mdb_free(buf, bufsz); + return (DCMD_ERR); + } + (void) mdb_printf("%s\n", buf); mdb_free(buf, bufsz); @@ -3307,7 +3447,7 @@ static const mdb_dcmd_t v8_mdb_dcmds[] = { */ { "jsframe", ":[-v]", "summarize a JavaScript stack frame", dcmd_jsframe }, - { "jsprint", ":[-a] [-d depth]", "print a JavaScript object", + { "jsprint", ":[-a] [-d depth] [member]", "print a JavaScript object", dcmd_jsprint }, { "jsstack", "[-v]", "print a JavaScript stacktrace", dcmd_jsstack }, |