diff options
author | John Sonnenschein <johns@joyent.com> | 2011-12-20 22:02:19 +0000 |
---|---|---|
committer | John Sonnenschein <johns@joyent.com> | 2011-12-20 22:02:19 +0000 |
commit | 1636e739ebc2ac80c49a1e69f71fda812db48850 (patch) | |
tree | fc50ff3fb0191895828671198e8ee7cb93cb5859 /usr/src | |
parent | 84c9e00cfac0317d1e164e792a2386a9440b833a (diff) | |
parent | e7c3f416aa65d7864d1198dcfead49a8d7583a58 (diff) | |
download | illumos-joyent-1636e739ebc2ac80c49a1e69f71fda812db48850.tar.gz |
Merge branch 'master' into gcc4
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/mdb/Makefile.common | 3 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/v8/mdb_v8.c | 1939 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/v8/mdb_v8_cfg.c | 715 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/v8/v8cfg.h | 53 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/v8/v8dbg.h | 81 | ||||
-rw-r--r-- | usr/src/cmd/mdb/intel/ia32/v8/Makefile | 42 | ||||
-rw-r--r-- | usr/src/pkg/manifests/developer-build-onbld.mf | 8 | ||||
-rw-r--r-- | usr/src/tools/scripts/Makefile | 24 | ||||
-rw-r--r-- | usr/src/tools/scripts/flg.flp.sh | 8 | ||||
-rw-r--r-- | usr/src/tools/scripts/git-pbchk.1 | 94 | ||||
-rwxr-xr-x | usr/src/tools/scripts/git-pbchk.py | 285 | ||||
-rw-r--r-- | usr/src/tools/scripts/nightly.sh | 4 | ||||
-rw-r--r-- | usr/src/tools/scripts/webrev.1 | 20 | ||||
-rw-r--r-- | usr/src/tools/scripts/webrev.sh | 258 | ||||
-rw-r--r-- | usr/src/tools/scripts/which_scm.1 | 2 | ||||
-rw-r--r-- | usr/src/tools/scripts/ws.sh | 16 | ||||
-rw-r--r-- | usr/src/uts/common/dtrace/dtrace.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/dbuf.c | 3 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev_raidz.c | 2 |
19 files changed, 3428 insertions, 131 deletions
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common index 4e282bf001..3bbca8d4e0 100644 --- a/usr/src/cmd/mdb/Makefile.common +++ b/usr/src/cmd/mdb/Makefile.common @@ -45,7 +45,8 @@ COMMON_MODULES_PROC = \ # COMMON_MODULES_PROC_32BIT = \ svc.configd \ - svc.startd + svc.startd \ + v8 # # MDB modules used for debugging kernels. diff --git a/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c b/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c new file mode 100644 index 0000000000..7f4d2e7110 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c @@ -0,0 +1,1939 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2011, Joyent, Inc. All rights reserved. + */ + +/* + * mdb(1M) module for debugging the V8 JavaScript engine. This implementation + * 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. + */ + +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include <sys/mdb_modapi.h> + +#include "v8dbg.h" +#include "v8cfg.h" + +/* + * The "v8_class" and "v8_field" structures describe the C++ classes used to + * represent V8 heap objects. + */ +typedef struct v8_class { + struct v8_class *v8c_next; /* list linkage */ + struct v8_class *v8c_parent; /* parent class (inheritance) */ + struct v8_field *v8c_fields; /* array of class fields */ + size_t v8c_start; /* offset of first class field */ + size_t v8c_end; /* offset of first subclass field */ + char v8c_name[64]; /* heap object class name */ +} v8_class_t; + +typedef struct v8_field { + struct v8_field *v8f_next; /* list linkage */ + ssize_t v8f_offset; /* field offset */ + char v8f_name[64]; /* field name */ + boolean_t v8f_isbyte; /* 1-byte int field */ +} v8_field_t; + +/* + * Similarly, the "v8_enum" structure describes an enum from V8. + */ +typedef struct { + char v8e_name[64]; + uint_t v8e_value; +} v8_enum_t; + +/* + * During configuration, the dmod updates these globals with the actual set of + * classes, types, and frame types based on the debug metadata. + */ +static v8_class_t *v8_classes; + +static v8_enum_t v8_types[128]; +static int v8_next_type; + +static v8_enum_t v8_frametypes[16]; +static int v8_next_frametype; + +/* + * The following constants describe offsets from the frame pointer that are used + * to inspect each stack frame. They're initialized from the debug metadata. + */ +static ssize_t V8_OFF_FP_CONTEXT; +static ssize_t V8_OFF_FP_MARKER; +static ssize_t V8_OFF_FP_FUNCTION; +static ssize_t V8_OFF_FP_ARGS; + +/* + * The following constants are used by macros defined in heap-dbg-common.h to + * examine the types of various V8 heap objects. In general, the macros should + * be preferred to using the constants directly. The values of these constants + * are initialized from the debug metadata. + */ +static intptr_t V8_FirstNonstringType; +static intptr_t V8_IsNotStringMask; +static intptr_t V8_StringTag; +static intptr_t V8_NotStringTag; +static intptr_t V8_StringEncodingMask; +static intptr_t V8_TwoByteStringTag; +static intptr_t V8_AsciiStringTag; +static intptr_t V8_StringRepresentationMask; +static intptr_t V8_SeqStringTag; +static intptr_t V8_ConsStringTag; +static intptr_t V8_ExternalStringTag; +static intptr_t V8_FailureTag; +static intptr_t V8_FailureTagMask; +static intptr_t V8_HeapObjectTag; +static intptr_t V8_HeapObjectTagMask; +static intptr_t V8_SmiTag; +static intptr_t V8_SmiTagMask; +static intptr_t V8_SmiValueShift; +static intptr_t V8_PointerSizeLog2; + +static intptr_t V8_PROP_IDX_CONTENT; +static intptr_t V8_PROP_IDX_FIRST; +static intptr_t V8_PROP_TYPE_FIELD; +static intptr_t V8_PROP_FIRST_PHANTOM; +static intptr_t V8_PROP_TYPE_MASK; + +/* + * Although we have this information in v8_classes, the following offsets are + * defined explicitly because they're used directly in code below. + */ +static ssize_t V8_OFF_FIXEDARRAY_DATA; +static ssize_t V8_OFF_SEQASCIISTR_CHARS; + +static const char *V8_FIXEDARRAY_BASE; + +#define NODE_OFF_EXTSTR_DATA 0x4 /* see node_string.h */ + +/* + * Table of constants used directly by this file. + */ +typedef struct v8_constant { + intptr_t *v8c_valp; + const char *v8c_symbol; +} v8_constant_t; + +static v8_constant_t v8_constants[] = { + { &V8_OFF_FP_CONTEXT, "v8dbg_off_fp_context" }, + { &V8_OFF_FP_FUNCTION, "v8dbg_off_fp_function" }, + { &V8_OFF_FP_MARKER, "v8dbg_off_fp_marker" }, + { &V8_OFF_FP_ARGS, "v8dbg_off_fp_args" }, + + { &V8_FirstNonstringType, "v8dbg_FirstNonstringType" }, + { &V8_IsNotStringMask, "v8dbg_IsNotStringMask" }, + { &V8_StringTag, "v8dbg_StringTag" }, + { &V8_NotStringTag, "v8dbg_NotStringTag" }, + { &V8_StringEncodingMask, "v8dbg_StringEncodingMask" }, + { &V8_TwoByteStringTag, "v8dbg_TwoByteStringTag" }, + { &V8_AsciiStringTag, "v8dbg_AsciiStringTag" }, + { &V8_StringRepresentationMask, "v8dbg_StringRepresentationMask" }, + { &V8_SeqStringTag, "v8dbg_SeqStringTag" }, + { &V8_ConsStringTag, "v8dbg_ConsStringTag" }, + { &V8_ExternalStringTag, "v8dbg_ExternalStringTag" }, + { &V8_FailureTag, "v8dbg_FailureTag" }, + { &V8_FailureTagMask, "v8dbg_FailureTagMask" }, + { &V8_HeapObjectTag, "v8dbg_HeapObjectTag" }, + { &V8_HeapObjectTagMask, "v8dbg_HeapObjectTagMask" }, + { &V8_SmiTag, "v8dbg_SmiTag" }, + { &V8_SmiTagMask, "v8dbg_SmiTagMask" }, + { &V8_SmiValueShift, "v8dbg_SmiValueShift" }, + { &V8_PointerSizeLog2, "v8dbg_PointerSizeLog2" }, + + { &V8_PROP_IDX_CONTENT, "v8dbg_prop_idx_content" }, + { &V8_PROP_IDX_FIRST, "v8dbg_prop_idx_first" }, + { &V8_PROP_TYPE_FIELD, "v8dbg_prop_type_field" }, + { &V8_PROP_FIRST_PHANTOM, "v8dbg_prop_type_first_phantom" }, + { &V8_PROP_TYPE_MASK, "v8dbg_prop_type_mask" }, +}; + +static int v8_nconstants = sizeof (v8_constants) / sizeof (v8_constants[0]); + +static int autoconf_iter_symbol(mdb_symbol_t *, void *); +static v8_class_t *conf_class_findcreate(const char *); +static v8_field_t *conf_field_create(v8_class_t *, const char *, size_t); +static char *conf_next_part(char *, char *); +static int conf_update_parent(const char *); +static int conf_update_field(v8_cfg_t *, const char *); +static int conf_update_enum(v8_cfg_t *, const char *, const char *, + v8_enum_t *); +static int conf_update_type(v8_cfg_t *, const char *); +static int conf_update_frametype(v8_cfg_t *, const char *); +static void conf_class_compute_offsets(v8_class_t *); + +static int heap_offset(const char *, const char *, ssize_t *, boolean_t); + +/* + * Invoked when this dmod is initially loaded to load the set of classes, enums, + * and other constants from the metadata in the target binary. + */ +static int +autoconfigure(v8_cfg_t *cfgp) +{ + v8_class_t *clp; + struct v8_constant *cnp; + ssize_t unused; + int ii; + + assert(v8_classes == NULL); + + /* + * Iterate all global symbols looking for metadata. + */ + if (cfgp->v8cfg_iter(cfgp, autoconf_iter_symbol, cfgp) != 0) { + mdb_warn("failed to autoconfigure V8 support\n"); + return (-1); + } + + /* + * By now we've configured all of the classes so we can update the + * "start" and "end" fields in each class with information from its + * parent class. + */ + for (clp = v8_classes; clp != NULL; clp = clp->v8c_next) { + if (clp->v8c_end != (size_t)-1) + continue; + + conf_class_compute_offsets(clp); + }; + + /* + * Finally, load various constants used directly in the module. + */ + for (ii = 0; ii < v8_nconstants; ii++) { + cnp = &v8_constants[ii]; + + if (cfgp->v8cfg_readsym(cfgp, cnp->v8c_symbol, + cnp->v8c_valp) == -1) { + mdb_warn("failed to read \"%s\"", cnp->v8c_symbol); + return (-1); + } + } + + if (heap_offset("SeqAsciiString", "chars", &V8_OFF_SEQASCIISTR_CHARS, + B_FALSE) != 0 || heap_offset("FixedArray", "data", + &V8_OFF_FIXEDARRAY_DATA, B_FALSE) != 0) + return (-1); + + /* + * The V8 included in node v0.6 uses a FixedArrayBase class to contain + * the "length" field, while the one in v0.4 has no such base class and + * stores the field directly in FixedArray. We handle both cases here. + */ + V8_FIXEDARRAY_BASE = heap_offset("FixedArray", "length", &unused, + B_TRUE) == 0 ? "FixedArray" : "FixedArrayBase"; + + return (0); +} + +/* ARGSUSED */ +static int +autoconf_iter_symbol(mdb_symbol_t *symp, void *arg) +{ + v8_cfg_t *cfgp = arg; + + if (strncmp(symp->sym_name, "v8dbg_parent_", + sizeof ("v8dbg_parent_") - 1) == 0) + return (conf_update_parent(symp->sym_name)); + + if (strncmp(symp->sym_name, "v8dbg_class_", + sizeof ("v8dbg_class_") - 1) == 0) + return (conf_update_field(cfgp, symp->sym_name)); + + if (strncmp(symp->sym_name, "v8dbg_type_", + sizeof ("v8dbg_type_") - 1) == 0) + return (conf_update_type(cfgp, symp->sym_name)); + + if (strncmp(symp->sym_name, "v8dbg_frametype_", + sizeof ("v8dbg_frametype_") - 1) == 0) + return (conf_update_frametype(cfgp, symp->sym_name)); + + return (0); +} + +/* + * Extracts the next field of a string whose fields are separated by "__" (as + * the V8 metadata symbols are). + */ +static char * +conf_next_part(char *buf, char *start) +{ + char *pp; + + if ((pp = strstr(start, "__")) == NULL) { + mdb_warn("malformed symbol name: %s\n", buf); + return (NULL); + } + + *pp = '\0'; + return (pp + sizeof ("__") - 1); +} + +static v8_class_t * +conf_class_findcreate(const char *name) +{ + v8_class_t *clp, *iclp, **ptr; + int cmp; + + if (v8_classes == NULL || strcmp(v8_classes->v8c_name, name) > 0) { + ptr = &v8_classes; + } else { + for (iclp = v8_classes; iclp->v8c_next != NULL; + iclp = iclp->v8c_next) { + cmp = strcmp(iclp->v8c_next->v8c_name, name); + + if (cmp == 0) + return (iclp->v8c_next); + + if (cmp > 0) + break; + } + + ptr = &iclp->v8c_next; + } + + if ((clp = mdb_zalloc(sizeof (*clp), UM_NOSLEEP)) == NULL) + return (NULL); + + (void) strlcpy(clp->v8c_name, name, sizeof (clp->v8c_name)); + clp->v8c_end = (size_t)-1; + + clp->v8c_next = *ptr; + *ptr = clp; + return (clp); +} + +static v8_field_t * +conf_field_create(v8_class_t *clp, const char *name, size_t offset) +{ + v8_field_t *flp, *iflp; + + if ((flp = mdb_zalloc(sizeof (*flp), UM_NOSLEEP)) == NULL) + return (NULL); + + (void) strlcpy(flp->v8f_name, name, sizeof (flp->v8f_name)); + flp->v8f_offset = offset; + + if (clp->v8c_fields == NULL || clp->v8c_fields->v8f_offset > offset) { + flp->v8f_next = clp->v8c_fields; + clp->v8c_fields = flp; + return (flp); + } + + for (iflp = clp->v8c_fields; iflp->v8f_next != NULL; + iflp = iflp->v8f_next) { + if (iflp->v8f_next->v8f_offset > offset) + break; + } + + flp->v8f_next = iflp->v8f_next; + iflp->v8f_next = flp; + return (flp); +} + +/* + * Given a "v8dbg_parent_X__Y", symbol, update the parent of class X to class Y. + * Note that neither class necessarily exists already. + */ +static int +conf_update_parent(const char *symbol) +{ + char *pp, *qq; + char buf[128]; + v8_class_t *clp, *pclp; + + (void) strlcpy(buf, symbol, sizeof (buf)); + pp = buf + sizeof ("v8dbg_parent_") - 1; + qq = conf_next_part(buf, pp); + + if (qq == NULL) + return (-1); + + clp = conf_class_findcreate(pp); + pclp = conf_class_findcreate(qq); + + if (clp == NULL || pclp == NULL) { + mdb_warn("mdb_v8: out of memory\n"); + return (-1); + } + + clp->v8c_parent = pclp; + return (0); +} + +/* + * Given a "v8dbg_class_CLASS__FIELD__TYPE", symbol, save field "FIELD" into + * class CLASS with the offset described by the symbol. Note that CLASS does + * not necessarily exist already. + */ +static int +conf_update_field(v8_cfg_t *cfgp, const char *symbol) +{ + v8_class_t *clp; + v8_field_t *flp; + intptr_t offset; + char *pp, *qq, *tt; + char buf[128]; + + (void) strlcpy(buf, symbol, sizeof (buf)); + + pp = buf + sizeof ("v8dbg_class_") - 1; + qq = conf_next_part(buf, pp); + + if (qq == NULL || (tt = conf_next_part(buf, qq)) == NULL) + return (-1); + + if (cfgp->v8cfg_readsym(cfgp, symbol, &offset) == -1) { + mdb_warn("failed to read symbol \"%s\"", symbol); + return (-1); + } + + if ((clp = conf_class_findcreate(pp)) == NULL || + (flp = conf_field_create(clp, qq, (size_t)offset)) == NULL) + return (-1); + + if (strcmp(tt, "int") == 0) + flp->v8f_isbyte = B_TRUE; + + return (0); +} + +static int +conf_update_enum(v8_cfg_t *cfgp, const char *symbol, const char *name, + v8_enum_t *enp) +{ + intptr_t value; + + if (cfgp->v8cfg_readsym(cfgp, symbol, &value) == -1) { + mdb_warn("failed to read symbol \"%s\"", symbol); + return (-1); + } + + enp->v8e_value = (int)value; + (void) strlcpy(enp->v8e_name, name, sizeof (enp->v8e_name)); + return (0); +} + +/* + * Given a "v8dbg_type_TYPENAME" constant, save the type name in v8_types. Note + * that this enum has multiple integer values with the same string label. + */ +static int +conf_update_type(v8_cfg_t *cfgp, const char *symbol) +{ + char *klass; + v8_enum_t *enp; + char buf[128]; + + if (v8_next_type > sizeof (v8_types) / sizeof (v8_types[0])) { + mdb_warn("too many V8 types\n"); + return (-1); + } + + (void) strlcpy(buf, symbol, sizeof (buf)); + + klass = buf + sizeof ("v8dbg_type_") - 1; + if (conf_next_part(buf, klass) == NULL) + return (-1); + + enp = &v8_types[v8_next_type++]; + return (conf_update_enum(cfgp, symbol, klass, enp)); +} + +/* + * Given a "v8dbg_frametype_TYPENAME" constant, save the frame type in + * v8_frametypes. + */ +static int +conf_update_frametype(v8_cfg_t *cfgp, const char *symbol) +{ + const char *frametype; + v8_enum_t *enp; + + if (v8_next_frametype > + sizeof (v8_frametypes) / sizeof (v8_frametypes[0])) { + mdb_warn("too many V8 frame types\n"); + return (-1); + } + + enp = &v8_frametypes[v8_next_frametype++]; + frametype = symbol + sizeof ("v8dbg_frametype_") - 1; + return (conf_update_enum(cfgp, symbol, frametype, enp)); +} + +/* + * Now that all classes have been loaded, update the "start" and "end" fields of + * each class based on the values of its parent class. + */ +static void +conf_class_compute_offsets(v8_class_t *clp) +{ + v8_field_t *flp; + + assert(clp->v8c_start == 0); + assert(clp->v8c_end == (size_t)-1); + + if (clp->v8c_parent != NULL) { + if (clp->v8c_parent->v8c_end == (size_t)-1) + conf_class_compute_offsets(clp->v8c_parent); + + clp->v8c_start = clp->v8c_parent->v8c_end; + } + + if (clp->v8c_fields == NULL) { + clp->v8c_end = clp->v8c_start; + return; + } + + for (flp = clp->v8c_fields; flp->v8f_next != NULL; flp = flp->v8f_next) + ; + + if (flp == NULL) + clp->v8c_end = clp->v8c_start; + else + clp->v8c_end = flp->v8f_offset + sizeof (uintptr_t); +} + +/* + * Utility functions + */ +static int jsstr_print(uintptr_t, boolean_t, char **, size_t *); + +static const char * +enum_lookup_str(v8_enum_t *enums, int val, const char *dflt) +{ + v8_enum_t *ep; + + for (ep = enums; ep->v8e_name[0] != '\0'; ep++) { + if (ep->v8e_value == val) + return (ep->v8e_name); + } + + return (dflt); +} + +static void +enum_print(v8_enum_t *enums) +{ + v8_enum_t *itp; + + for (itp = enums; itp->v8e_name[0] != '\0'; itp++) + mdb_printf("%-30s = 0x%02x\n", itp->v8e_name, itp->v8e_value); +} + +/* + * b[v]snprintf behave like [v]snprintf(3c), except that they update the buffer + * and length arguments based on how much buffer space is used by the operation. + * This makes it much easier to combine multiple calls in sequence without + * worrying about buffer overflow. + */ +static size_t +bvsnprintf(char **bufp, size_t *buflenp, const char *format, va_list alist) +{ + size_t rv, len; + + if (*buflenp == 0) + return (vsnprintf(NULL, 0, format, alist)); + + rv = vsnprintf(*bufp, *buflenp, format, alist); + + len = MIN(rv, *buflenp); + *buflenp -= len; + *bufp += len; + + return (len); +} + +static size_t +bsnprintf(char **bufp, size_t *buflenp, const char *format, ...) +{ + va_list alist; + size_t rv; + + va_start(alist, format); + rv = bvsnprintf(bufp, buflenp, format, alist); + va_end(alist); + + return (rv); +} + +/* + * Returns in "offp" the offset of field "field" in C++ class "klass". + */ +static int +heap_offset(const char *klass, const char *field, ssize_t *offp, + boolean_t silent) +{ + v8_class_t *clp; + v8_field_t *flp; + + for (clp = v8_classes; clp != NULL; clp = clp->v8c_next) { + if (strcmp(klass, clp->v8c_name) == 0) + break; + } + + if (clp == NULL) { + if (!silent) + mdb_warn("couldn't find class \"%s\"\n", klass); + return (-1); + } + + for (flp = clp->v8c_fields; flp != NULL; flp = flp->v8f_next) { + if (strcmp(field, flp->v8f_name) == 0) + break; + } + + if (flp == NULL) { + if (!silent) + mdb_warn("couldn't find class \"%s\" field \"%s\"\n", + klass, field); + return (-1); + } + + *offp = V8_OFF_HEAP(flp->v8f_offset); + return (0); +} + +/* + * Assuming "addr" is an instance of the C++ heap class "klass", read into *valp + * the pointer-sized value of field "field". + */ +static int +read_heap_ptr(uintptr_t *valp, uintptr_t addr, const char *klass, + const char *field) +{ + ssize_t off; + + if (heap_offset(klass, field, &off, B_FALSE) != 0) + return (-1); + + if (mdb_vread(valp, sizeof (*valp), addr + off) == -1) { + mdb_warn("failed to read heap value at %p", addr + off); + return (-1); + } + + return (0); +} + +/* + * Like read_heap_ptr, but assume the field is an SMI and store the actual value + * into *valp rather than the encoded representation. + */ +static int +read_heap_smi(uintptr_t *valp, uintptr_t addr, const char *klass, + const char *field) +{ + if (read_heap_ptr(valp, addr, klass, field) != 0) + return (-1); + + if (!V8_IS_SMI(*valp)) { + mdb_warn("expected SMI, got %p\n", *valp); + return (-1); + } + + *valp = V8_SMI_VALUE(*valp); + + return (0); +} + +static int +read_heap_double(double *valp, uintptr_t addr, const char *klass, + const char *field) +{ + ssize_t off; + + if (heap_offset(klass, field, &off, B_FALSE) != 0) + return (-1); + + if (mdb_vread(valp, sizeof (*valp), addr + off) == -1) { + mdb_warn("failed to read heap value at %p", addr + off); + return (-1); + } + + return (0); +} + +/* + * Assuming "addr" refers to a FixedArray, return a newly-allocated array + * representing its contents. + */ +static int +read_heap_array(uintptr_t addr, uintptr_t **retp, size_t *lenp) +{ + uintptr_t len; + + if (read_heap_smi(&len, addr, V8_FIXEDARRAY_BASE, "length") != 0) + return (-1); + + *lenp = len; + + if (len == 0) { + *retp = NULL; + return (0); + } + + if ((*retp = mdb_zalloc(len * sizeof (uintptr_t), UM_GC)) == NULL) + return (-1); + + if (mdb_vread(*retp, len * sizeof (uintptr_t), + addr + V8_OFF_FIXEDARRAY_DATA) == -1) + return (-1); + + return (0); +} + +static int +read_heap_byte(uint8_t *valp, uintptr_t addr, const char *klass, + const char *field) +{ + ssize_t off; + + if (heap_offset(klass, field, &off, B_FALSE) != 0) + return (-1); + + if (mdb_vread(valp, sizeof (*valp), addr + off) == -1) { + mdb_warn("failed to read heap value at %p", addr + off); + return (-1); + } + + return (0); +} + +/* + * Given a heap object, returns in *valp the byte describing the type of the + * object. This is shorthand for first retrieving the Map at the start of the + * heap object and then retrieving the type byte from the Map object. + */ +static int +read_typebyte(uint8_t *valp, uintptr_t addr) +{ + uintptr_t mapaddr; + + if (read_heap_ptr(&mapaddr, addr, "HeapObject", "map") != 0) + return (-1); + + if (!V8_IS_HEAPOBJECT(mapaddr)) { + mdb_warn("heap object map is not itself a heap object\n"); + return (-1); + } + + if (read_heap_byte(valp, mapaddr, "Map", "instance_attributes") == -1) + return (-1); + + return (0); +} + +/* + * Given a heap object, returns in *valp the size of the object. For + * variable-size objects, returns an undefined value. + */ +static int +read_size(size_t *valp, uintptr_t addr) +{ + uintptr_t mapaddr; + uint8_t size; + + if (read_heap_ptr(&mapaddr, addr, "HeapObject", "map") != 0) + return (-1); + + if (!V8_IS_HEAPOBJECT(mapaddr)) { + mdb_warn("heap object map is not itself a heap object\n"); + return (-1); + } + + if (read_heap_byte(&size, mapaddr, "Map", "instance_size") != 0) + return (-1); + + *valp = size << V8_PointerSizeLog2; + return (0); +} + +/* + * Returns in "buf" a description of the type of "addr" suitable for printing. + */ +static int +obj_jstype(uintptr_t addr, char **bufp, size_t *lenp, uint8_t *typep) +{ + uint8_t typebyte; + uintptr_t strptr; + const char *typename; + + if (V8_IS_FAILURE(addr)) { + if (typep) + *typep = 0; + (void) bsnprintf(bufp, lenp, "'Failure' object"); + return (0); + } + + if (V8_IS_SMI(addr)) { + if (typep) + *typep = 0; + (void) bsnprintf(bufp, lenp, "SMI: value = %d", + V8_SMI_VALUE(addr)); + return (0); + } + + if (read_typebyte(&typebyte, addr) != 0) + return (-1); + + if (typep) + *typep = typebyte; + + typename = enum_lookup_str(v8_types, typebyte, "<unknown>"); + (void) bsnprintf(bufp, lenp, typename); + + if (strcmp(typename, "Oddball") == 0) { + if (read_heap_ptr(&strptr, addr, "Oddball", + "to_string") != -1) { + (void) bsnprintf(bufp, lenp, ": \""); + (void) jsstr_print(strptr, B_FALSE, bufp, lenp); + (void) bsnprintf(bufp, lenp, "\""); + } + } + + return (0); +} + +/* + * Print out the fields of the given object that come from the given class. + */ +static int +obj_print_fields(uintptr_t baddr, v8_class_t *clp) +{ + v8_field_t *flp; + uintptr_t addr, value; + int rv; + char *bufp; + size_t len; + uint8_t type; + char buf[256]; + + for (flp = clp->v8c_fields; flp != NULL; flp = flp->v8f_next) { + bufp = buf; + len = sizeof (buf); + + addr = baddr + V8_OFF_HEAP(flp->v8f_offset); + + if (flp->v8f_isbyte) { + uint8_t sv; + if (mdb_vread(&sv, sizeof (sv), addr) == -1) { + mdb_printf("%p %s (unreadable)\n", + addr, flp->v8f_name); + continue; + } + + mdb_printf("%p %s = 0x%x\n", addr, flp->v8f_name, sv); + continue; + } + + rv = mdb_vread((void *)&value, sizeof (value), addr); + + if (rv != sizeof (value) || + obj_jstype(value, &bufp, &len, &type) != 0) { + mdb_printf("%p %s (unreadable)\n", addr, flp->v8f_name); + continue; + } + + if (type != 0 && V8_TYPE_STRING(type)) { + (void) bsnprintf(&bufp, &len, ": \""); + (void) jsstr_print(value, B_FALSE, &bufp, &len); + (void) bsnprintf(&bufp, &len, "\""); + } + + mdb_printf("%p %s = %p (%s)\n", addr, flp->v8f_name, value, + buf); + } + + return (DCMD_OK); +} + +/* + * Print out all fields of the given object, starting with the root of the class + * hierarchy and working down the most specific type. + */ +static int +obj_print_class(uintptr_t addr, v8_class_t *clp) +{ + int rv = 0; + + /* + * If we have no fields, we just print a simple inheritance hierarchy. + * If we have fields but our parent doesn't, our header includes the + * inheritance hierarchy. + */ + if (clp->v8c_end == 0) { + mdb_printf("%s ", clp->v8c_name); + + if (clp->v8c_parent != NULL) { + mdb_printf("< "); + (void) obj_print_class(addr, clp->v8c_parent); + } + + return (0); + } + + mdb_printf("%p %s", addr, clp->v8c_name); + + if (clp->v8c_start == 0 && clp->v8c_parent != NULL) { + mdb_printf(" < "); + (void) obj_print_class(addr, clp->v8c_parent); + } + + mdb_printf(" {\n"); + (void) mdb_inc_indent(4); + + if (clp->v8c_start > 0 && clp->v8c_parent != NULL) + rv = obj_print_class(addr, clp->v8c_parent); + + rv |= obj_print_fields(addr, clp); + (void) mdb_dec_indent(4); + mdb_printf("}\n"); + + return (rv); +} + +/* + * Print the ASCII string for the given ASCII JS string, expanding ConsStrings + * and ExternalStrings as needed. + */ +static int jsstr_print_seq(uintptr_t, boolean_t, char **, size_t *); +static int jsstr_print_cons(uintptr_t, boolean_t, char **, size_t *); +static int jsstr_print_external(uintptr_t, boolean_t, char **, size_t *); + +static int +jsstr_print(uintptr_t addr, boolean_t verbose, char **bufp, size_t *lenp) +{ + uint8_t typebyte; + int err = 0; + char *lbufp; + size_t llen; + char buf[64]; + + if (read_typebyte(&typebyte, addr) != 0) + return (0); + + if (!V8_TYPE_STRING(typebyte)) { + (void) bsnprintf(bufp, lenp, "<not a string>"); + return (0); + } + + if (!V8_STRENC_ASCII(typebyte)) { + (void) bsnprintf(bufp, lenp, "<two-byte string>"); + return (0); + } + + if (verbose) { + lbufp = buf; + llen = sizeof (buf); + (void) obj_jstype(addr, &lbufp, &llen, NULL); + mdb_printf("%s\n", buf); + (void) mdb_inc_indent(4); + } + + if (V8_STRREP_SEQ(typebyte)) + err = jsstr_print_seq(addr, verbose, bufp, lenp); + else if (V8_STRREP_CONS(typebyte)) + err = jsstr_print_cons(addr, verbose, bufp, lenp); + else if (V8_STRREP_EXT(typebyte)) + err = jsstr_print_external(addr, verbose, bufp, lenp); + else { + (void) bsnprintf(bufp, lenp, "<unknown string type>"); + err = -1; + } + + if (verbose) + (void) mdb_dec_indent(4); + + return (err); +} + +static int +jsstr_print_seq(uintptr_t addr, boolean_t verbose, char **bufp, size_t *lenp) +{ + uintptr_t len, rlen; + char buf[256]; + + if (read_heap_smi(&len, addr, "String", "length") != 0) + return (-1); + + rlen = len <= sizeof (buf) - 1 ? len : sizeof (buf) - sizeof ("[...]"); + + if (verbose) + mdb_printf("length: %d, will read: %d\n", len, rlen); + + buf[0] = '\0'; + + if (rlen > 0 && mdb_readstr(buf, rlen + 1, + addr + V8_OFF_SEQASCIISTR_CHARS) == -1) { + mdb_warn("failed to read SeqString data"); + return (-1); + } + + if (rlen != len) + (void) strlcat(buf, "[...]", sizeof (buf)); + + if (verbose) + mdb_printf("value: \"%s\"\n", buf); + + (void) bsnprintf(bufp, lenp, "%s", buf); + return (0); +} + +static int +jsstr_print_cons(uintptr_t addr, boolean_t verbose, char **bufp, size_t *lenp) +{ + uintptr_t ptr1, ptr2; + + if (read_heap_ptr(&ptr1, addr, "ConsString", "first") != 0 || + read_heap_ptr(&ptr2, addr, "ConsString", "second") != 0) + return (-1); + + if (verbose) { + mdb_printf("ptr1: %p\n", ptr1); + mdb_printf("ptr2: %p\n", ptr2); + } + + if (jsstr_print(ptr1, verbose, bufp, lenp) != 0) + return (-1); + + return (jsstr_print(ptr2, verbose, bufp, lenp)); +} + +static int +jsstr_print_external(uintptr_t addr, boolean_t verbose, char **bufp, + size_t *lenp) +{ + uintptr_t ptr1, ptr2; + char buf[256]; + + if (verbose) + mdb_printf("assuming Node.js string\n"); + + if (read_heap_ptr(&ptr1, addr, "ExternalString", "resource") != 0) + return (-1); + + if (mdb_vread(&ptr2, sizeof (ptr2), + ptr1 + NODE_OFF_EXTSTR_DATA) == -1) { + mdb_warn("failed to read node external pointer: %p", + ptr1 + NODE_OFF_EXTSTR_DATA); + return (-1); + } + + if (mdb_readstr(buf, sizeof (buf), ptr2) == -1) { + mdb_warn("failed to read ExternalString data"); + return (-1); + } + + if (buf[0] != '\0' && !isascii(buf[0])) { + mdb_warn("failed to read ExternalString ascii data\n"); + return (-1); + } + + (void) bsnprintf(bufp, lenp, "%s", buf); + return (0); +} + +/* + * 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). + */ +static boolean_t +jsobj_is_undefined(uintptr_t addr) +{ + uint8_t type; + uintptr_t strptr; + const char *typename; + char buf[16]; + char *bufp = buf; + size_t len = sizeof (buf); + + if (read_typebyte(&type, addr) != 0) + return (B_FALSE); + + typename = enum_lookup_str(v8_types, type, "<unknown>"); + if (strcmp(typename, "Oddball") != 0) + return (B_FALSE); + + if (read_heap_ptr(&strptr, addr, "Oddball", "to_string") == -1) + return (B_FALSE); + + if (jsstr_print(strptr, B_FALSE, &bufp, &len) != 0) + return (B_FALSE); + + return (strcmp(buf, "undefined") == 0); +} + +/* + * Given the line endings table in "lendsp", computes the line number for the + * given token position and print the result into "buf". If "lendsp" is + * undefined, prints the token position instead. + */ +static int +jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos, char *buf, size_t buflen) +{ + uintptr_t size, bufsz, lower, upper, ii; + uintptr_t *data; + + if (jsobj_is_undefined(lendsp)) { + mdb_snprintf(buf, buflen, "position %d", tokpos); + return (0); + } + + if (read_heap_smi(&size, lendsp, V8_FIXEDARRAY_BASE, "length") != 0) + return (-1); + + bufsz = size * sizeof (data[0]); + + if ((data = mdb_alloc(bufsz, UM_NOSLEEP)) == NULL) { + mdb_warn("failed to alloc %d bytes for FixedArray data", bufsz); + return (-1); + } + + if (mdb_vread(data, bufsz, lendsp + V8_OFF_FIXEDARRAY_DATA) != bufsz) { + mdb_warn("failed to read FixedArray data"); + mdb_free(data, bufsz); + return (-1); + } + + lower = 0; + upper = size - 1; + + if (tokpos > data[upper]) { + (void) strlcpy(buf, "position out of range", buflen); + mdb_free(data, bufsz); + return (0); + } + + if (tokpos <= data[0]) { + (void) strlcpy(buf, "line 1", buflen); + mdb_free(data, bufsz); + return (0); + } + + while (upper >= 1) { + ii = (lower + upper) >> 1; + if (tokpos > data[ii]) + lower = ii + 1; + else if (tokpos <= data[ii - 1]) + upper = ii - 1; + else + break; + } + + (void) mdb_snprintf(buf, buflen, "line %d", ii + 1); + mdb_free(data, bufsz); + return (0); +} + +/* + * 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. + */ +static int +jsfunc_name(uintptr_t funcinfop, char **bufp, size_t *lenp) +{ + uintptr_t ptrp; + char *bufs = *bufp; + + if (read_heap_ptr(&ptrp, funcinfop, "SharedFunctionInfo", + "name") != 0 || jsstr_print(ptrp, B_FALSE, bufp, lenp) != 0) + return (-1); + + if (*bufp != bufs) + return (0); + + if (read_heap_ptr(&ptrp, funcinfop, "SharedFunctionInfo", + "inferred_name") != 0) { + (void) bsnprintf(bufp, lenp, "<anonymous>"); + return (0); + } + + (void) bsnprintf(bufp, lenp, "<anonymous> (as "); + bufs = *bufp; + + if (jsstr_print(ptrp, B_FALSE, bufp, lenp) != 0) + return (-1); + + if (*bufp == bufs) + (void) bsnprintf(bufp, lenp, "<anon>"); + + (void) bsnprintf(bufp, lenp, ")"); + + return (0); +} + +/* + * JavaScript-level object printing + */ +static int jsobj_print_number(uintptr_t, char **, size_t *); +static int jsobj_print_oddball(uintptr_t, char **, size_t *); +static int jsobj_print_jsobject(uintptr_t, boolean_t, int, int, char **, + size_t *); +static int jsobj_print_jsarray(uintptr_t, boolean_t, int, int, char **, + size_t *); +static int jsobj_print_jsfunction(uintptr_t, char **, size_t *); + +static int +jsobj_print(uintptr_t addr, boolean_t printaddr, int indent, int depth, + char **bufp, size_t *lenp) +{ + uint8_t type; + const char *klass; + + if (printaddr) + (void) bsnprintf(bufp, lenp, "%p: ", addr); + + if (V8_IS_SMI(addr)) { + (void) bsnprintf(bufp, lenp, "%d", V8_SMI_VALUE(addr)); + return (0); + } + + if (!V8_IS_HEAPOBJECT(addr)) { + mdb_warn("not a heap object: %p\n", addr); + return (-1); + } + + if (read_typebyte(&type, addr) != 0) + return (-1); + + if (V8_TYPE_STRING(type)) + return (jsstr_print(addr, B_FALSE, bufp, lenp)); + + klass = enum_lookup_str(v8_types, type, "<unknown>"); + if (strcmp(klass, "HeapNumber") == 0) + return (jsobj_print_number(addr, bufp, lenp)); + if (strcmp(klass, "Oddball") == 0) + return (jsobj_print_oddball(addr, bufp, lenp)); + if (strcmp(klass, "JSObject") == 0) + return (jsobj_print_jsobject(addr, printaddr, indent, depth, + bufp, lenp)); + if (strcmp(klass, "JSArray") == 0) + return (jsobj_print_jsarray(addr, printaddr, indent, depth, + bufp, lenp)); + if (strcmp(klass, "JSFunction") == 0) + return (jsobj_print_jsfunction(addr, bufp, lenp)); + + mdb_warn("unknown JavaScript object type \"%s\"\n", klass); + return (-1); +} + +static int +jsobj_print_number(uintptr_t addr, char **bufp, size_t *lenp) +{ + double numval; + + if (read_heap_double(&numval, addr, "HeapNumber", "value") == -1) + return (-1); + + if (numval == (long long)numval) + (void) bsnprintf(bufp, lenp, "%lld", (long long)numval); + else + (void) bsnprintf(bufp, lenp, "%e", numval); + + return (0); +} + +static int +jsobj_print_oddball(uintptr_t addr, char **bufp, size_t *lenp) +{ + uintptr_t strptr; + + if (read_heap_ptr(&strptr, addr, "Oddball", "to_string") != 0) + return (-1); + + return (jsstr_print(strptr, B_FALSE, bufp, lenp)); +} + +static int +jsobj_print_jsobject(uintptr_t addr, boolean_t printaddr, int indent, + int depth, char **bufp, size_t *lenp) +{ + uintptr_t ptr, map; + uintptr_t *props, *descs, *content; + size_t ii, size, nprops, rndescs, ndescs, ncontent; + uint8_t type, ninprops; + + if (depth == 0) { + (void) bsnprintf(bufp, lenp, "[...]"); + return (0); + } + + /* + * Objects have either "fast" properties represented with a FixedArray + * or slow properties represented with a Dictionary. We only support + * the former, so we check that up front. + */ + if (read_heap_ptr(&ptr, addr, "JSObject", "properties") != 0) + return (-1); + + if (read_typebyte(&type, ptr) != 0) + return (-1); + + if (strcmp(enum_lookup_str(v8_types, type, ""), "FixedArray") != 0) { + (void) bsnprintf(bufp, lenp, "{ /* unknown property */ }"); + return (0); + } + + if (read_heap_array(ptr, &props, &nprops) != 0) + return (-1); + + /* + * To iterate the properties, we need to examine the instance + * descriptors of the associated Map object. Some properties may be + * stored inside the object itself, in which case we need to know how + * big the object is and how many such properties there are. + */ + if (read_heap_ptr(&map, addr, "HeapObject", "map") != 0 || + read_heap_ptr(&ptr, map, "Map", "instance_descriptors") != 0 || + read_heap_array(ptr, &descs, &ndescs) != 0) + return (-1); + + if (read_size(&size, addr) != 0) + size = 0; + + if (read_heap_byte(&ninprops, map, "Map", "inobject_properties") != 0) + return (-1); + + if (V8_PROP_IDX_CONTENT < ndescs && + read_heap_array(descs[V8_PROP_IDX_CONTENT], &content, + &ncontent) != 0) + return (-1); + + (void) bsnprintf(bufp, lenp, "{"); + + /* + * The first FIRST (2) entries in the descriptors array are special. + */ + rndescs = ndescs <= V8_PROP_IDX_FIRST ? 0 : ndescs - V8_PROP_IDX_FIRST; + + for (ii = 0; ii < rndescs; ii++) { + uintptr_t keyidx, validx, detidx; + intptr_t val; + + keyidx = V8_DESC_KEYIDX(ii); + validx = V8_DESC_VALIDX(ii); + detidx = V8_DESC_DETIDX(ii); + + if (detidx >= ncontent) { + mdb_warn("property descriptor %d: detidx (%d) " + "out of bounds for content array (length %d)\n", + ii, detidx, ncontent); + continue; + } + + if (!V8_DESC_ISFIELD(content[detidx])) + continue; + + if (keyidx >= ndescs) { + mdb_warn("property descriptor %d: keyidx (%d) " + "out of bounds for descriptor array (length %d)\n", + ii, keyidx, ndescs); + continue; + } + + (void) bsnprintf(bufp, lenp, "\n%*s", indent + 4, ""); + if (jsstr_print(descs[keyidx], B_FALSE, bufp, lenp) != 0) + continue; + + (void) bsnprintf(bufp, lenp, ": "); + + val = (intptr_t)content[validx]; + + if (!V8_IS_SMI(val)) { + mdb_warn("property descriptor %d: value index value " + "is not an SMI: %p\n", ii, val); + continue; + } + + val = V8_SMI_VALUE(val) - ninprops; + + if (val < 0) { + /* property is stored directly in the object */ + if (mdb_vread(&ptr, sizeof (ptr), addr + V8_OFF_HEAP( + size + val * sizeof (uintptr_t))) == -1) { + mdb_warn("failed to read in-object " + "property at %p\n", addr + V8_OFF_HEAP( + size + val * sizeof (uintptr_t))); + continue; + } + } else { + /* property should be in "props" array */ + if (val >= nprops) { + mdb_warn("property descriptor %d: value index " + "value (%d) out of bounds (%d)\n", ii, val, + nprops); + continue; + } + + ptr = props[val]; + } + + + (void) jsobj_print(ptr, printaddr, indent + 4, + depth - 1, bufp, lenp); + + (void) bsnprintf(bufp, lenp, ","); + } + + if (ii > 0) + (void) bsnprintf(bufp, lenp, "\n%*s", indent, ""); + + (void) bsnprintf(bufp, lenp, "}"); + + return (DCMD_OK); +} + +static int +jsobj_print_jsarray(uintptr_t addr, boolean_t printaddr, int indent, + int depth, char **bufp, size_t *lenp) +{ + uintptr_t ptr; + uintptr_t *elts; + size_t ii, len; + + if (depth == 0) { + (void) bsnprintf(bufp, lenp, "[...]"); + return (0); + } + + if (read_heap_ptr(&ptr, addr, "JSObject", "elements") != 0 || + read_heap_array(ptr, &elts, &len) != 0) + return (-1); + + if (len == 0) { + (void) bsnprintf(bufp, lenp, "[]"); + return (0); + } + + if (len == 1) { + (void) bsnprintf(bufp, lenp, "[ "); + (void) jsobj_print(elts[0], printaddr, indent + 4, + depth - 1, bufp, lenp); + (void) bsnprintf(bufp, lenp, " ]"); + return (0); + } + + (void) bsnprintf(bufp, lenp, "[\n"); + for (ii = 0; ii < len; ii++) { + (void) bsnprintf(bufp, lenp, "%*s", indent + 4, ""); + (void) jsobj_print(elts[ii], printaddr, indent + 4, + depth - 1, bufp, lenp); + (void) bsnprintf(bufp, lenp, ",\n"); + } + + (void) bsnprintf(bufp, lenp, "%*s", indent, ""); + (void) bsnprintf(bufp, lenp, "]"); + + return (0); +} + +static int +jsobj_print_jsfunction(uintptr_t addr, char **bufp, size_t *lenp) +{ + uintptr_t shared; + + if (read_heap_ptr(&shared, addr, "JSFunction", "shared") != 0) + return (-1); + + (void) bsnprintf(bufp, lenp, "function "); + return (jsfunc_name(shared, bufp, lenp) != 0); +} + +/* + * dcmd implementations + */ + +/* ARGSUSED */ +static int +dcmd_v8classes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + v8_class_t *clp; + + for (clp = v8_classes; clp != NULL; clp = clp->v8c_next) + mdb_printf("%s\n", clp->v8c_name); + + return (DCMD_OK); +} + +static void +dcmd_v8print_help(void) +{ + mdb_printf( + "Prints out \".\" (a V8 heap object) as an instance of its C++\n" + "class. With no arguments, the appropriate class is detected\n" + "automatically. The 'class' argument overrides this to print an\n" + "object as an instance of the given class. The list of known\n" + "classes can be viewed with ::jsclasses."); +} + +/* ARGSUSED */ +static int +dcmd_v8print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + const char *rqclass; + v8_class_t *clp; + char *bufp; + size_t len; + uint8_t type; + char buf[256]; + + if (argc < 1) { + /* + * If no type was specified, determine it automatically. + */ + bufp = buf; + len = sizeof (buf); + if (obj_jstype(addr, &bufp, &len, &type) != 0) + return (DCMD_ERR); + + if (type == 0) { + /* For SMI or Failure, just print out the type. */ + mdb_printf("%s\n", buf); + return (DCMD_OK); + } + + if ((rqclass = enum_lookup_str(v8_types, type, NULL)) == NULL) { + mdb_warn("object has unknown type\n"); + return (DCMD_ERR); + } + } else { + if (argv[0].a_type != MDB_TYPE_STRING) + return (DCMD_USAGE); + + rqclass = argv[0].a_un.a_str; + } + + for (clp = v8_classes; clp != NULL; clp = clp->v8c_next) { + if (strcmp(rqclass, clp->v8c_name) == 0) + break; + } + + if (clp == NULL) { + mdb_warn("unknown class '%s'\n", rqclass); + return (DCMD_USAGE); + } + + return (obj_print_class(addr, clp)); +} + +/* ARGSUSED */ +static int +dcmd_v8type(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + char buf[64]; + char *bufp = buf; + size_t len = sizeof (buf); + + if (obj_jstype(addr, &bufp, &len, NULL) != 0) + return (DCMD_ERR); + + mdb_printf("0x%p: %s\n", addr, buf); + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +dcmd_v8types(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + enum_print(v8_types); + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + uintptr_t ftype, funcp, funcinfop, tokpos, scriptp, lendsp, ptrp; + uintptr_t ii, nargs; + boolean_t opt_v = B_FALSE; + char typebuf[256]; + char funcname[64]; + char *bufp; + size_t len; + + if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, B_TRUE, &opt_v, + NULL) != argc) + return (DCMD_USAGE); + + /* + * First figure out what kind of frame this is using the same algorithm + * as V8's ComputeType function. We only print useful information for + * JavaScriptFrames. Conveniently, most other frame types are indicated + * by the presence of a frame type identifier on the stack. For + * ArgumentsAdaptorFrames, the type identifier is in the "context" slot, + * while for other frames the type identifier is in the "marker" slot. + * Like V8, we check for the AdaptorFrame first, then look for other + * types, and if we haven't found a frame type identifier then we assume + * we're looking at a JavaScriptFrame. + */ + if (mdb_vread(&ftype, sizeof (ftype), addr + V8_OFF_FP_CONTEXT) == -1) + return (DCMD_ERR); + + if (!V8_IS_SMI(ftype) && + mdb_vread(&ftype, sizeof (ftype), addr + V8_OFF_FP_MARKER) == -1) + return (DCMD_ERR); + + if (V8_IS_SMI(ftype)) { + mdb_printf("%p <%s>\n", addr, enum_lookup_str( + v8_frametypes, V8_SMI_VALUE(ftype), "<unknown>")); + return (DCMD_OK); + } + + if (mdb_vread(&funcp, sizeof (funcp), addr + V8_OFF_FP_FUNCTION) == -1) + return (DCMD_ERR); + + if (read_heap_ptr(&funcinfop, funcp, "JSFunction", "shared") != 0) + return (DCMD_ERR); + + bufp = funcname; + len = sizeof (funcname); + if (jsfunc_name(funcinfop, &bufp, &len) != 0) + return (DCMD_ERR); + + mdb_printf("%p %s", addr, funcname); + + /* + * Although the token position is technically an SMI, we're going to + * byte-compare it to other SMI values so we don't want decode it here. + */ + if (read_heap_ptr(&tokpos, funcinfop, + "SharedFunctionInfo", "function_token_position") != 0) + return (DCMD_ERR); + + if (read_heap_ptr(&scriptp, funcinfop, + "SharedFunctionInfo", "script") != 0) + return (DCMD_ERR); + + if (read_heap_ptr(&ptrp, scriptp, "Script", "name") != 0) + return (DCMD_ERR); + + bufp = typebuf; + len = sizeof (typebuf); + (void) jsstr_print(ptrp, B_FALSE, &bufp, &len); + + if (opt_v) { + mdb_printf("\n"); + (void) mdb_inc_indent(4); + mdb_printf("func: %p\n", funcp); + mdb_printf("file: %s\n", typebuf); + } else { + mdb_printf(" at %s ", typebuf); + } + + if (read_heap_ptr(&lendsp, scriptp, "Script", "line_ends") != 0) + return (DCMD_ERR); + + (void) jsfunc_lineno(lendsp, tokpos, typebuf, sizeof (typebuf)); + + if (opt_v) + mdb_printf("posn: %s\n", typebuf); + else + mdb_printf("%s\n", typebuf); + + if (opt_v) { + if (read_heap_smi(&nargs, funcinfop, + "SharedFunctionInfo", "length") == 0) { + for (ii = 0; ii < nargs; ii++) { + uintptr_t argptr; + + if (mdb_vread(&argptr, sizeof (argptr), + addr + V8_OFF_FP_ARGS + (nargs - ii - 1) * + sizeof (uintptr_t)) == -1) + continue; + + bufp = typebuf; + len = sizeof (typebuf); + (void) obj_jstype(argptr, &bufp, &len, NULL); + + mdb_printf("arg%d: %p (%s)\n", (ii + 1), + argptr, typebuf); + } + } + + (void) mdb_dec_indent(4); + } + + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + char *buf; + char *bufp; + size_t len, bufsz = 262144; + boolean_t verbose; + uint64_t depth; + int rv; + + verbose = B_FALSE; + depth = 2; + + if (mdb_getopts(argc, argv, + 'a', MDB_OPT_SETBITS, B_TRUE, &verbose, + 'd', MDB_OPT_UINT64, &depth, NULL) != argc) + return (DCMD_USAGE); + + if ((buf = mdb_zalloc(bufsz, UM_NOSLEEP)) == NULL) + return (DCMD_ERR); + + bufp = buf; + len = bufsz; + rv = jsobj_print(addr, verbose, 0, (int)depth, &bufp, &len); + (void) mdb_printf("%s\n", buf); + mdb_free(buf, bufsz); + return (rv == 0 ? DCMD_OK : DCMD_ERR); +} + +/* ARGSUSED */ +static int +dcmd_v8array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + uint8_t type; + uintptr_t *array; + size_t ii, len; + + if (read_typebyte(&type, addr) != 0) + return (DCMD_ERR); + + if (strcmp(enum_lookup_str(v8_types, type, ""), "FixedArray") != 0) { + mdb_warn("%p is not an instance of FixedArray\n", addr); + return (DCMD_ERR); + } + + if (read_heap_array(addr, &array, &len) != 0) + return (DCMD_ERR); + + for (ii = 0; ii < len; ii++) + mdb_printf("%p\n", array[ii]); + + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +dcmd_jsstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + if (mdb_walk_dcmd("jsframe", "jsframe", argc, argv) == -1) + return (DCMD_ERR); + + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +dcmd_v8str(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + boolean_t opt_v = B_FALSE; + char buf[256]; + char *bufp; + size_t len; + + if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, B_TRUE, &opt_v, + NULL) != argc) + return (DCMD_USAGE); + + bufp = buf; + len = sizeof (buf); + if (jsstr_print(addr, opt_v, &bufp, &len) != 0) + return (DCMD_ERR); + + mdb_printf("%s\n", buf); + return (DCMD_OK); +} + +static void +dcmd_v8load_help(void) +{ + v8_cfg_t *cfp; + + mdb_printf( + "To traverse in-memory V8 structures, the V8 dmod requires\n" + "configuration that describes the layout of various V8 structures\n" + "in memory. Normally, this information is pulled from metadata\n" + "in the target binary. However, it's possible to use the module\n" + "with a binary not built with metadata by loading one of the\n" + "canned configurations.\n\n"); + + mdb_printf("Available configurations:\n"); + + (void) mdb_inc_indent(4); + + for (cfp = v8_cfgs; cfp->v8cfg_name != NULL; cfp++) + mdb_printf("%-10s %s\n", cfp->v8cfg_name, cfp->v8cfg_label); + + (void) mdb_dec_indent(4); +} + +/* ARGSUSED */ +static int +dcmd_v8load(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + v8_cfg_t *cfgp; + + if (v8_classes != NULL) { + mdb_warn("v8 module already configured\n"); + return (DCMD_ERR); + } + + if (argc < 1 || argv->a_type != MDB_TYPE_STRING) + return (DCMD_USAGE); + + for (cfgp = v8_cfgs; cfgp->v8cfg_name != NULL; cfgp++) { + if (strcmp(argv->a_un.a_str, cfgp->v8cfg_name) == 0) + break; + } + + if (cfgp->v8cfg_name == NULL) { + mdb_warn("unknown configuration: \"%s\"\n", argv->a_un.a_str); + return (DCMD_ERR); + } + + if (autoconfigure(cfgp) == -1) { + mdb_warn("autoconfigure failed\n"); + return (DCMD_ERR); + } + + mdb_printf("V8 dmod configured based on %s\n", cfgp->v8cfg_name); + return (DCMD_OK); +} + +static int +walk_jsframes_init(mdb_walk_state_t *wsp) +{ + mdb_tid_t tid; + mdb_reg_t reg; + + tid = wsp->walk_addr != NULL ? + (mdb_tid_t)wsp->walk_addr : 1; + + if (mdb_getareg(tid, "ebp", ®) != 0) { + mdb_warn("failed to read ebp for thread %d", tid); + return (WALK_ERR); + } + + wsp->walk_addr = (uintptr_t)reg; + return (WALK_NEXT); +} + +static int +walk_jsframes_step(mdb_walk_state_t *wsp) +{ + uintptr_t ftype, addr, next; + int rv; + + addr = wsp->walk_addr; + rv = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); + + if (rv != WALK_NEXT) + return (rv); + + /* + * Figure out the type of this frame. + */ + if (mdb_vread(&ftype, sizeof (ftype), addr + V8_OFF_FP_MARKER) == -1) + return (WALK_ERR); + + if (V8_IS_SMI(ftype) && V8_SMI_VALUE(ftype) == 0) + return (WALK_DONE); + + if (mdb_vread(&next, sizeof (next), addr) == -1) + return (WALK_ERR); + + wsp->walk_addr = next; + return (WALK_NEXT); +} + +/* + * MDB linkage + */ + +static const mdb_dcmd_t v8_mdb_dcmds[] = { + /* + * Commands to inspect JavaScript-level state + */ + { "jsframe", ":[-v]", "summarize a JavaScript stack frame", + dcmd_jsframe }, + { "jsprint", ":[-a] [-d depth]", "print a JavaScript object", + dcmd_jsprint }, + { "jsstack", "[-v]", "print a JavaScript stacktrace", + dcmd_jsstack }, + + /* + * Commands to inspect V8-level state + */ + { "v8array", ":", "print elements of a V8 FixedArray", + dcmd_v8array }, + { "v8classes", NULL, "list known V8 heap object C++ classes", + dcmd_v8classes }, + { "v8load", "version", "load canned config for a specific V8 version", + dcmd_v8load, dcmd_v8load_help }, + { "v8print", ":[class]", "print a V8 heap object", + dcmd_v8print, dcmd_v8print_help }, + { "v8str", ":[-v]", "print the contents of a V8 string", + dcmd_v8str }, + { "v8type", ":", "print the type of a V8 heap object", + dcmd_v8type }, + { "v8types", NULL, "list known V8 heap object types", + dcmd_v8types }, + + { NULL } +}; + +static const mdb_walker_t v8_mdb_walkers[] = { + { "jsframe", "walk V8 JavaScript stack frames", + walk_jsframes_init, walk_jsframes_step }, + { NULL } +}; + +static mdb_modinfo_t v8_mdb = { MDB_API_VERSION, v8_mdb_dcmds, v8_mdb_walkers }; + +const mdb_modinfo_t * +_mdb_init(void) +{ + GElf_Sym sym; + + /* + * Do a quick check first for debug metadata included in the binary. If + * it's there, we autoconfigure based on this metadata. If not, we + * assume this is not a V8 binary and there's nothing for us to do. If + * there's no metadata but this really is V8, the user can attempt to + * load a canned configuration using ::v8load. + */ + if (mdb_lookup_by_name("v8dbg_SmiTag", &sym) == 0) { + if (autoconfigure(&v8_cfg_target) != 0) + mdb_warn("failed to autoconfigure from target\n"); + else + mdb_printf("Loaded V8 support.\n"); + } + + return (&v8_mdb); +} diff --git a/usr/src/cmd/mdb/common/modules/v8/mdb_v8_cfg.c b/usr/src/cmd/mdb/common/modules/v8/mdb_v8_cfg.c new file mode 100644 index 0000000000..05d25b65d6 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/v8/mdb_v8_cfg.c @@ -0,0 +1,715 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2011, Joyent, Inc. All rights reserved. + */ + +/* + * mdb_v8_cfg.c: canned configurations for previous V8 versions. + * + * The functions and data defined here enable this dmod to support debugging + * Node.js binaries that predated V8's built-in postmortem debugging support. + */ + +#include "v8cfg.h" + +/*ARGSUSED*/ +static int +v8cfg_target_iter(v8_cfg_t *cfgp, int (*func)(mdb_symbol_t *, void *), + void *arg) +{ + return (mdb_symbol_iter(MDB_OBJ_EVERY, MDB_SYMTAB, + MDB_BIND_GLOBAL | MDB_TYPE_OBJECT | MDB_TYPE_FUNC, + func, arg)); +} + +/*ARGSUSED*/ +static int +v8cfg_target_readsym(v8_cfg_t *cfgp, const char *name, intptr_t *valp) +{ + return (mdb_readsym(valp, sizeof (valp), name)); +} + +/* + * Analog of mdb_symbol_iter() for a canned configuration. + */ +static int +v8cfg_canned_iter(v8_cfg_t *cfgp, int (*func)(mdb_symbol_t *, void *), + void *arg) +{ + v8_cfg_symbol_t *v8sym; + mdb_symbol_t mdbsym; + int rv; + + for (v8sym = cfgp->v8cfg_symbols; v8sym->v8cs_name != NULL; v8sym++) { + mdbsym.sym_name = v8sym->v8cs_name; + mdbsym.sym_object = NULL; + mdbsym.sym_sym = NULL; + mdbsym.sym_table = 0; + mdbsym.sym_id = 0; + + if ((rv = func(&mdbsym, arg)) != 0) + return (rv); + } + + return (0); +} + +/* + * Analog of mdb_readsym() for a canned configuration. + */ +static int +v8cfg_canned_readsym(v8_cfg_t *cfgp, const char *name, intptr_t *valp) +{ + v8_cfg_symbol_t *v8sym; + + for (v8sym = cfgp->v8cfg_symbols; v8sym->v8cs_name != NULL; v8sym++) { + if (strcmp(name, v8sym->v8cs_name) == 0) + break; + } + + if (v8sym->v8cs_name == NULL) { + mdb_warn("no such canned symbol: %s\n", name); + return (-1); + } + + *valp = v8sym->v8cs_value; + return (0); +} + +/* + * Canned configuration for the V8 bundled with Node.js v0.4.8 and later. + */ +static v8_cfg_symbol_t v8_cfg_node_04[] = { + { "v8dbg_type_AccessCheckInfo__ACCESS_CHECK_INFO_TYPE", 0x91 }, + { "v8dbg_type_AccessorInfo__ACCESSOR_INFO_TYPE", 0x90 }, + { "v8dbg_type_BreakPointInfo__BREAK_POINT_INFO_TYPE", 0x9b }, + { "v8dbg_type_ByteArray__BYTE_ARRAY_TYPE", 0x86 }, + { "v8dbg_type_CallHandlerInfo__CALL_HANDLER_INFO_TYPE", 0x93 }, + { "v8dbg_type_Code__CODE_TYPE", 0x81 }, + { "v8dbg_type_CodeCache__CODE_CACHE_TYPE", 0x99 }, + { "v8dbg_type_ConsString__CONS_ASCII_STRING_TYPE", 0x5 }, + { "v8dbg_type_ConsString__CONS_ASCII_SYMBOL_TYPE", 0x45 }, + { "v8dbg_type_ConsString__CONS_STRING_TYPE", 0x1 }, + { "v8dbg_type_ConsString__CONS_SYMBOL_TYPE", 0x41 }, + { "v8dbg_type_DebugInfo__DEBUG_INFO_TYPE", 0x9a }, + { "v8dbg_type_ExternalAsciiString__EXTERNAL_ASCII_STRING_TYPE", 0x6 }, + { "v8dbg_type_ExternalAsciiString__EXTERNAL_ASCII_SYMBOL_TYPE", 0x46 }, + { "v8dbg_type_ExternalByteArray__EXTERNAL_BYTE_ARRAY_TYPE", 0x88 }, + { "v8dbg_type_ExternalFloatArray__EXTERNAL_FLOAT_ARRAY_TYPE", 0x8e }, + { "v8dbg_type_ExternalIntArray__EXTERNAL_INT_ARRAY_TYPE", 0x8c }, + { "v8dbg_type_ExternalShortArray__EXTERNAL_SHORT_ARRAY_TYPE", 0x8a }, + { "v8dbg_type_ExternalString__EXTERNAL_STRING_TYPE", 0x2 }, + { "v8dbg_type_ExternalString__EXTERNAL_SYMBOL_TYPE", 0x42 }, + { "v8dbg_type_ExternalUnsignedByteArray__" + "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", 0x89 }, + { "v8dbg_type_ExternalUnsignedIntArray__" + "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", 0x8d }, + { "v8dbg_type_ExternalUnsignedShortArray__" + "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", 0x8b }, + { "v8dbg_type_FixedArray__FIXED_ARRAY_TYPE", 0x9c }, + { "v8dbg_type_FunctionTemplateInfo__" + "FUNCTION_TEMPLATE_INFO_TYPE", 0x94 }, + { "v8dbg_type_HeapNumber__HEAP_NUMBER_TYPE", 0x84 }, + { "v8dbg_type_InterceptorInfo__INTERCEPTOR_INFO_TYPE", 0x92 }, + { "v8dbg_type_JSArray__JS_ARRAY_TYPE", 0xa5 }, + { "v8dbg_type_JSBuiltinsObject__JS_BUILTINS_OBJECT_TYPE", 0xa3 }, + { "v8dbg_type_JSFunction__JS_FUNCTION_TYPE", 0xa7 }, + { "v8dbg_type_JSGlobalObject__JS_GLOBAL_OBJECT_TYPE", 0xa2 }, + { "v8dbg_type_JSGlobalPropertyCell__" + "JS_GLOBAL_PROPERTY_CELL_TYPE", 0x83 }, + { "v8dbg_type_JSGlobalProxy__JS_GLOBAL_PROXY_TYPE", 0xa4 }, + { "v8dbg_type_JSMessageObject__JS_MESSAGE_OBJECT_TYPE", 0x9e }, + { "v8dbg_type_JSObject__JS_OBJECT_TYPE", 0xa0 }, + { "v8dbg_type_JSRegExp__JS_REGEXP_TYPE", 0xa6 }, + { "v8dbg_type_JSValue__JS_VALUE_TYPE", 0x9f }, + { "v8dbg_type_Map__MAP_TYPE", 0x80 }, + { "v8dbg_type_ObjectTemplateInfo__OBJECT_TEMPLATE_INFO_TYPE", 0x95 }, + { "v8dbg_type_Oddball__ODDBALL_TYPE", 0x82 }, + { "v8dbg_type_Script__SCRIPT_TYPE", 0x98 }, + { "v8dbg_type_SeqAsciiString__ASCII_STRING_TYPE", 0x4 }, + { "v8dbg_type_SeqAsciiString__ASCII_SYMBOL_TYPE", 0x44 }, + { "v8dbg_type_SharedFunctionInfo__SHARED_FUNCTION_INFO_TYPE", 0x9d }, + { "v8dbg_type_SignatureInfo__SIGNATURE_INFO_TYPE", 0x96 }, + { "v8dbg_type_String__STRING_TYPE", 0x0 }, + { "v8dbg_type_String__SYMBOL_TYPE", 0x40 }, + { "v8dbg_type_TypeSwitchInfo__TYPE_SWITCH_INFO_TYPE", 0x97 }, + + { "v8dbg_class_AccessCheckInfo__data__Object", 0xc }, + { "v8dbg_class_AccessCheckInfo__indexed_callback__Object", 0x8 }, + { "v8dbg_class_AccessCheckInfo__named_callback__Object", 0x4 }, + { "v8dbg_class_AccessorInfo__data__Object", 0xc }, + { "v8dbg_class_AccessorInfo__flag__Smi", 0x14 }, + { "v8dbg_class_AccessorInfo__getter__Object", 0x4 }, + { "v8dbg_class_AccessorInfo__name__Object", 0x10 }, + { "v8dbg_class_AccessorInfo__setter__Object", 0x8 }, + { "v8dbg_class_BreakPointInfo__break_point_objects__Object", 0x10 }, + { "v8dbg_class_BreakPointInfo__code_position__Smi", 0x4 }, + { "v8dbg_class_BreakPointInfo__source_position__Smi", 0x8 }, + { "v8dbg_class_BreakPointInfo__statement_position__Smi", 0xc }, + { "v8dbg_class_ByteArray__length__SMI", 0x4 }, + { "v8dbg_class_CallHandlerInfo__callback__Object", 0x4 }, + { "v8dbg_class_CallHandlerInfo__data__Object", 0x8 }, + { "v8dbg_class_Code__deoptimization_data__FixedArray", 0xc }, + { "v8dbg_class_Code__relocation_info__ByteArray", 0x8 }, + { "v8dbg_class_CodeCache__default_cache__FixedArray", 0x4 }, + { "v8dbg_class_CodeCache__normal_type_cache__Object", 0x8 }, + { "v8dbg_class_ConsString__first__String", 0xc }, + { "v8dbg_class_ConsString__second__String", 0x10 }, + { "v8dbg_class_DebugInfo__break_points__FixedArray", 0x14 }, + { "v8dbg_class_DebugInfo__code__Code", 0xc }, + { "v8dbg_class_DebugInfo__original_code__Code", 0x8 }, + { "v8dbg_class_DebugInfo__shared__SharedFunctionInfo", 0x4 }, + { "v8dbg_class_ExternalString__resource__Object", 0xc }, + { "v8dbg_class_FixedArray__data__uintptr_t", 0x8 }, + { "v8dbg_class_FixedArray__length__SMI", 0x4 }, + { "v8dbg_class_FunctionTemplateInfo__access_check_info__Object", 0x38 }, + { "v8dbg_class_FunctionTemplateInfo__call_code__Object", 0x10 }, + { "v8dbg_class_FunctionTemplateInfo__class_name__Object", 0x2c }, + { "v8dbg_class_FunctionTemplateInfo__flag__Smi", 0x3c }, + { "v8dbg_class_FunctionTemplateInfo__" + "indexed_property_handler__Object", 0x24 }, + { "v8dbg_class_FunctionTemplateInfo__" + "instance_call_handler__Object", 0x34 }, + { "v8dbg_class_FunctionTemplateInfo__instance_template__Object", 0x28 }, + { "v8dbg_class_FunctionTemplateInfo__" + "named_property_handler__Object", 0x20 }, + { "v8dbg_class_FunctionTemplateInfo__parent_template__Object", 0x1c }, + { "v8dbg_class_FunctionTemplateInfo__" + "property_accessors__Object", 0x14 }, + { "v8dbg_class_FunctionTemplateInfo__" + "prototype_template__Object", 0x18 }, + { "v8dbg_class_FunctionTemplateInfo__serial_number__Object", 0xc }, + { "v8dbg_class_FunctionTemplateInfo__signature__Object", 0x30 }, + { "v8dbg_class_GlobalObject__builtins__JSBuiltinsObject", 0xc }, + { "v8dbg_class_GlobalObject__global_context__Context", 0x10 }, + { "v8dbg_class_GlobalObject__global_receiver__JSObject", 0x14 }, + { "v8dbg_class_HeapNumber__value__SMI", 0x4 }, + { "v8dbg_class_HeapObject__map__Map", 0x0 }, + { "v8dbg_class_InterceptorInfo__data__Object", 0x18 }, + { "v8dbg_class_InterceptorInfo__deleter__Object", 0x10 }, + { "v8dbg_class_InterceptorInfo__enumerator__Object", 0x14 }, + { "v8dbg_class_InterceptorInfo__getter__Object", 0x4 }, + { "v8dbg_class_InterceptorInfo__query__Object", 0xc }, + { "v8dbg_class_InterceptorInfo__setter__Object", 0x8 }, + { "v8dbg_class_JSArray__length__Object", 0xc }, + { "v8dbg_class_JSFunction__literals__FixedArray", 0x1c }, + { "v8dbg_class_JSFunction__next_function_link__Object", 0x20 }, + { "v8dbg_class_JSFunction__prototype_or_initial_map__Object", 0x10 }, + { "v8dbg_class_JSFunction__shared__SharedFunctionInfo", 0x14 }, + { "v8dbg_class_JSGlobalProxy__context__Object", 0xc }, + { "v8dbg_class_JSMessageObject__arguments__JSArray", 0x10 }, + { "v8dbg_class_JSMessageObject__end_position__SMI", 0x24 }, + { "v8dbg_class_JSMessageObject__script__Object", 0x14 }, + { "v8dbg_class_JSMessageObject__stack_frames__Object", 0x1c }, + { "v8dbg_class_JSMessageObject__stack_trace__Object", 0x18 }, + { "v8dbg_class_JSMessageObject__start_position__SMI", 0x20 }, + { "v8dbg_class_JSMessageObject__type__String", 0xc }, + { "v8dbg_class_JSObject__elements__Object", 0x8 }, + { "v8dbg_class_JSObject__properties__FixedArray", 0x4 }, + { "v8dbg_class_JSRegExp__data__Object", 0xc }, + { "v8dbg_class_JSValue__value__Object", 0xc }, + { "v8dbg_class_Map__code_cache__Object", 0x18 }, + { "v8dbg_class_Map__constructor__Object", 0x10 }, + { "v8dbg_class_Map__inobject_properties__int", 0x5 }, + { "v8dbg_class_Map__instance_size__int", 0x4 }, + { "v8dbg_class_Map__instance_attributes__int", 0x8 }, + { "v8dbg_class_Map__instance_descriptors__DescriptorArray", 0x14 }, + { "v8dbg_class_ObjectTemplateInfo__constructor__Object", 0xc }, + { "v8dbg_class_ObjectTemplateInfo__" + "internal_field_count__Object", 0x10 }, + { "v8dbg_class_Oddball__to_number__Object", 0x8 }, + { "v8dbg_class_Oddball__to_string__String", 0x4 }, + { "v8dbg_class_Script__column_offset__Smi", 0x10 }, + { "v8dbg_class_Script__compilation_type__Smi", 0x24 }, + { "v8dbg_class_Script__context_data__Object", 0x18 }, + { "v8dbg_class_Script__data__Object", 0x14 }, + { "v8dbg_class_Script__eval_from_instructions_offset__Smi", 0x34 }, + { "v8dbg_class_Script__eval_from_shared__Object", 0x30 }, + { "v8dbg_class_Script__id__Object", 0x2c }, + { "v8dbg_class_Script__line_ends__Object", 0x28 }, + { "v8dbg_class_Script__line_offset__Smi", 0xc }, + { "v8dbg_class_Script__name__Object", 0x8 }, + { "v8dbg_class_Script__source__Object", 0x4 }, + { "v8dbg_class_Script__type__Smi", 0x20 }, + { "v8dbg_class_Script__wrapper__Proxy", 0x1c }, + { "v8dbg_class_SeqAsciiString__chars__char", 0xc }, + { "v8dbg_class_SharedFunctionInfo__compiler_hints__SMI", 0x50 }, + { "v8dbg_class_SharedFunctionInfo__construct_stub__Code", 0x10 }, + { "v8dbg_class_SharedFunctionInfo__debug_info__Object", 0x20 }, + { "v8dbg_class_SharedFunctionInfo__end_position__SMI", 0x48 }, + { "v8dbg_class_SharedFunctionInfo__" + "expected_nof_properties__SMI", 0x3c }, + { "v8dbg_class_SharedFunctionInfo__formal_parameter_count__SMI", 0x38 }, + { "v8dbg_class_SharedFunctionInfo__function_data__Object", 0x18 }, + { "v8dbg_class_SharedFunctionInfo__" + "function_token_position__SMI", 0x4c }, + { "v8dbg_class_SharedFunctionInfo__inferred_name__String", 0x24 }, + { "v8dbg_class_SharedFunctionInfo__initial_map__Object", 0x28 }, + { "v8dbg_class_SharedFunctionInfo__instance_class_name__Object", 0x14 }, + { "v8dbg_class_SharedFunctionInfo__length__SMI", 0x34 }, + { "v8dbg_class_SharedFunctionInfo__name__Object", 0x4 }, + { "v8dbg_class_SharedFunctionInfo__num_literals__SMI", 0x40 }, + { "v8dbg_class_SharedFunctionInfo__opt_count__SMI", 0x58 }, + { "v8dbg_class_SharedFunctionInfo__script__Object", 0x1c }, + { "v8dbg_class_SharedFunctionInfo__" + "start_position_and_type__SMI", 0x44 }, + { "v8dbg_class_SharedFunctionInfo__" + "this_property_assignments__Object", 0x2c }, + { "v8dbg_class_SharedFunctionInfo__" + "this_property_assignments_count__SMI", 0x54 }, + { "v8dbg_class_SignatureInfo__args__Object", 0x8 }, + { "v8dbg_class_SignatureInfo__receiver__Object", 0x4 }, + { "v8dbg_class_String__length__SMI", 0x4 }, + { "v8dbg_class_TemplateInfo__property_list__Object", 0x8 }, + { "v8dbg_class_TemplateInfo__tag__Object", 0x4 }, + { "v8dbg_class_TypeSwitchInfo__types__Object", 0x4 }, + + { "v8dbg_parent_AccessCheckInfo__Struct", 0x0 }, + { "v8dbg_parent_AccessorInfo__Struct", 0x0 }, + { "v8dbg_parent_BreakPointInfo__Struct", 0x0 }, + { "v8dbg_parent_ByteArray__HeapObject", 0x0 }, + { "v8dbg_parent_CallHandlerInfo__Struct", 0x0 }, + { "v8dbg_parent_Code__HeapObject", 0x0 }, + { "v8dbg_parent_CodeCache__Struct", 0x0 }, + { "v8dbg_parent_ConsString__String", 0x0 }, + { "v8dbg_parent_DebugInfo__Struct", 0x0 }, + { "v8dbg_parent_DeoptimizationInputData__FixedArray", 0x0 }, + { "v8dbg_parent_DeoptimizationOutputData__FixedArray", 0x0 }, + { "v8dbg_parent_DescriptorArray__FixedArray", 0x0 }, + { "v8dbg_parent_ExternalArray__HeapObject", 0x0 }, + { "v8dbg_parent_ExternalAsciiString__ExternalString", 0x0 }, + { "v8dbg_parent_ExternalByteArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalFloatArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalIntArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalShortArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalString__String", 0x0 }, + { "v8dbg_parent_ExternalTwoByteString__ExternalString", 0x0 }, + { "v8dbg_parent_ExternalUnsignedByteArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalUnsignedIntArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalUnsignedShortArray__ExternalArray", 0x0 }, + { "v8dbg_parent_Failure__MaybeObject", 0x0 }, + { "v8dbg_parent_FixedArray__HeapObject", 0x0 }, + { "v8dbg_parent_FunctionTemplateInfo__TemplateInfo", 0x0 }, + { "v8dbg_parent_GlobalObject__JSObject", 0x0 }, + { "v8dbg_parent_HeapNumber__HeapObject", 0x0 }, + { "v8dbg_parent_HeapObject__Object", 0x0 }, + { "v8dbg_parent_InterceptorInfo__Struct", 0x0 }, + { "v8dbg_parent_JSArray__JSObject", 0x0 }, + { "v8dbg_parent_JSBuiltinsObject__GlobalObject", 0x0 }, + { "v8dbg_parent_JSFunction__JSObject", 0x0 }, + { "v8dbg_parent_JSFunctionResultCache__FixedArray", 0x0 }, + { "v8dbg_parent_JSGlobalObject__GlobalObject", 0x0 }, + { "v8dbg_parent_JSGlobalPropertyCell__HeapObject", 0x0 }, + { "v8dbg_parent_JSGlobalProxy__JSObject", 0x0 }, + { "v8dbg_parent_JSMessageObject__JSObject", 0x0 }, + { "v8dbg_parent_JSObject__HeapObject", 0x0 }, + { "v8dbg_parent_JSRegExp__JSObject", 0x0 }, + { "v8dbg_parent_JSRegExpResult__JSArray", 0x0 }, + { "v8dbg_parent_JSValue__JSObject", 0x0 }, + { "v8dbg_parent_Map__HeapObject", 0x0 }, + { "v8dbg_parent_NormalizedMapCache__FixedArray", 0x0 }, + { "v8dbg_parent_Object__MaybeObject", 0x0 }, + { "v8dbg_parent_ObjectTemplateInfo__TemplateInfo", 0x0 }, + { "v8dbg_parent_Oddball__HeapObject", 0x0 }, + { "v8dbg_parent_Script__Struct", 0x0 }, + { "v8dbg_parent_SeqAsciiString__SeqString", 0x0 }, + { "v8dbg_parent_SeqString__String", 0x0 }, + { "v8dbg_parent_SeqTwoByteString__SeqString", 0x0 }, + { "v8dbg_parent_SharedFunctionInfo__HeapObject", 0x0 }, + { "v8dbg_parent_SignatureInfo__Struct", 0x0 }, + { "v8dbg_parent_Smi__Object", 0x0 }, + { "v8dbg_parent_String__HeapObject", 0x0 }, + { "v8dbg_parent_Struct__HeapObject", 0x0 }, + { "v8dbg_parent_TemplateInfo__Struct", 0x0 }, + { "v8dbg_parent_TypeSwitchInfo__Struct", 0x0 }, + + { "v8dbg_frametype_ArgumentsAdaptorFrame", 0x8 }, + { "v8dbg_frametype_ConstructFrame", 0x7 }, + { "v8dbg_frametype_EntryConstructFrame", 0x2 }, + { "v8dbg_frametype_EntryFrame", 0x1 }, + { "v8dbg_frametype_ExitFrame", 0x3 }, + { "v8dbg_frametype_InternalFrame", 0x6 }, + { "v8dbg_frametype_JavaScriptFrame", 0x4 }, + { "v8dbg_frametype_OptimizedFrame", 0x5 }, + + { "v8dbg_off_fp_context", -0x4 }, + { "v8dbg_off_fp_function", -0x8 }, + { "v8dbg_off_fp_marker", -0x8 }, + { "v8dbg_off_fp_args", 0x8 }, + + { "v8dbg_prop_idx_content", 0x0 }, + { "v8dbg_prop_idx_first", 0x2 }, + { "v8dbg_prop_type_field", 0x1 }, + { "v8dbg_prop_type_first_phantom", 0x6 }, + { "v8dbg_prop_type_mask", 0xf }, + + { "v8dbg_AsciiStringTag", 0x4 }, + { "v8dbg_ConsStringTag", 0x1 }, + { "v8dbg_ExternalStringTag", 0x2 }, + { "v8dbg_FailureTag", 0x3 }, + { "v8dbg_FailureTagMask", 0x3 }, + { "v8dbg_FirstNonstringType", 0x80 }, + { "v8dbg_HeapObjectTag", 0x1 }, + { "v8dbg_HeapObjectTagMask", 0x3 }, + { "v8dbg_IsNotStringMask", 0x80 }, + { "v8dbg_NotStringTag", 0x80 }, + { "v8dbg_SeqStringTag", 0x0 }, + { "v8dbg_SmiTag", 0x0 }, + { "v8dbg_SmiTagMask", 0x1 }, + { "v8dbg_SmiValueShift", 0x1 }, + { "v8dbg_StringEncodingMask", 0x4 }, + { "v8dbg_StringRepresentationMask", 0x3 }, + { "v8dbg_StringTag", 0x0 }, + { "v8dbg_TwoByteStringTag", 0x0 }, + { "v8dbg_PointerSizeLog2", 0x2 }, + + { NULL } +}; + +/* + * Canned configuration for the V8 bundled with Node.js v0.6.5. + */ +static v8_cfg_symbol_t v8_cfg_node_065[] = { + { "v8dbg_type_AccessCheckInfo__ACCESS_CHECK_INFO_TYPE", 0x93 }, + { "v8dbg_type_AccessorInfo__ACCESSOR_INFO_TYPE", 0x92 }, + { "v8dbg_type_BreakPointInfo__BREAK_POINT_INFO_TYPE", 0x9e }, + { "v8dbg_type_ByteArray__BYTE_ARRAY_TYPE", 0x86 }, + { "v8dbg_type_CallHandlerInfo__CALL_HANDLER_INFO_TYPE", 0x95 }, + { "v8dbg_type_Code__CODE_TYPE", 0x81 }, + { "v8dbg_type_CodeCache__CODE_CACHE_TYPE", 0x9b }, + { "v8dbg_type_ConsString__CONS_ASCII_STRING_TYPE", 0x5 }, + { "v8dbg_type_ConsString__CONS_ASCII_SYMBOL_TYPE", 0x45 }, + { "v8dbg_type_ConsString__CONS_STRING_TYPE", 0x1 }, + { "v8dbg_type_ConsString__CONS_SYMBOL_TYPE", 0x41 }, + { "v8dbg_type_DebugInfo__DEBUG_INFO_TYPE", 0x9d }, + { "v8dbg_type_ExternalAsciiString__EXTERNAL_ASCII_STRING_TYPE", 0x6 }, + { "v8dbg_type_ExternalAsciiString__EXTERNAL_ASCII_SYMBOL_TYPE", 0x46 }, + { "v8dbg_type_ExternalByteArray__EXTERNAL_BYTE_ARRAY_TYPE", 0x87 }, + { "v8dbg_type_ExternalDoubleArray__EXTERNAL_DOUBLE_ARRAY_TYPE", 0x8e }, + { "v8dbg_type_ExternalFloatArray__EXTERNAL_FLOAT_ARRAY_TYPE", 0x8d }, + { "v8dbg_type_ExternalIntArray__EXTERNAL_INT_ARRAY_TYPE", 0x8b }, + { "v8dbg_type_ExternalPixelArray__EXTERNAL_PIXEL_ARRAY_TYPE", 0x8f }, + { "v8dbg_type_ExternalShortArray__EXTERNAL_SHORT_ARRAY_TYPE", 0x89 }, + { "v8dbg_type_ExternalTwoByteString__EXTERNAL_STRING_TYPE", 0x2 }, + { "v8dbg_type_ExternalTwoByteString__EXTERNAL_SYMBOL_TYPE", 0x42 }, + { "v8dbg_type_ExternalUnsignedByteArray__" + "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", 0x88 }, + { "v8dbg_type_ExternalUnsignedIntArray__" + "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", 0x8c }, + { "v8dbg_type_ExternalUnsignedShortArray__" + "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", 0x8a }, + { "v8dbg_type_FixedArray__FIXED_ARRAY_TYPE", 0x9f }, + { "v8dbg_type_FixedDoubleArray__FIXED_DOUBLE_ARRAY_TYPE", 0x90 }, + { "v8dbg_type_Foreign__FOREIGN_TYPE", 0x85 }, + { "v8dbg_type_FunctionTemplateInfo__FUNCTION_TEMPLATE_INFO_TYPE", + 0x96 }, + { "v8dbg_type_HeapNumber__HEAP_NUMBER_TYPE", 0x84 }, + { "v8dbg_type_InterceptorInfo__INTERCEPTOR_INFO_TYPE", 0x94 }, + { "v8dbg_type_JSArray__JS_ARRAY_TYPE", 0xa8 }, + { "v8dbg_type_JSBuiltinsObject__JS_BUILTINS_OBJECT_TYPE", 0xa6 }, + { "v8dbg_type_JSFunction__JS_FUNCTION_TYPE", 0xac }, + { "v8dbg_type_JSFunctionProxy__JS_FUNCTION_PROXY_TYPE", 0xad }, + { "v8dbg_type_JSGlobalObject__JS_GLOBAL_OBJECT_TYPE", 0xa5 }, + { "v8dbg_type_JSGlobalPropertyCell__JS_GLOBAL_PROPERTY_CELL_TYPE", + 0x83 }, + { "v8dbg_type_JSMessageObject__JS_MESSAGE_OBJECT_TYPE", 0xa1 }, + { "v8dbg_type_JSObject__JS_OBJECT_TYPE", 0xa3 }, + { "v8dbg_type_JSProxy__JS_PROXY_TYPE", 0xa9 }, + { "v8dbg_type_JSRegExp__JS_REGEXP_TYPE", 0xab }, + { "v8dbg_type_JSValue__JS_VALUE_TYPE", 0xa2 }, + { "v8dbg_type_JSWeakMap__JS_WEAK_MAP_TYPE", 0xaa }, + { "v8dbg_type_Map__MAP_TYPE", 0x80 }, + { "v8dbg_type_ObjectTemplateInfo__OBJECT_TEMPLATE_INFO_TYPE", 0x97 }, + { "v8dbg_type_Oddball__ODDBALL_TYPE", 0x82 }, + { "v8dbg_type_PolymorphicCodeCache__POLYMORPHIC_CODE_CACHE_TYPE", + 0x9c }, + { "v8dbg_type_Script__SCRIPT_TYPE", 0x9a }, + { "v8dbg_type_SeqAsciiString__ASCII_STRING_TYPE", 0x4 }, + { "v8dbg_type_SeqAsciiString__ASCII_SYMBOL_TYPE", 0x44 }, + { "v8dbg_type_SeqTwoByteString__STRING_TYPE", 0x0 }, + { "v8dbg_type_SeqTwoByteString__SYMBOL_TYPE", 0x40 }, + { "v8dbg_type_SharedFunctionInfo__SHARED_FUNCTION_INFO_TYPE", 0xa0 }, + { "v8dbg_type_SignatureInfo__SIGNATURE_INFO_TYPE", 0x98 }, + { "v8dbg_type_SlicedString__SLICED_ASCII_STRING_TYPE", 0x7 }, + { "v8dbg_type_SlicedString__SLICED_STRING_TYPE", 0x3 }, + { "v8dbg_type_TypeSwitchInfo__TYPE_SWITCH_INFO_TYPE", 0x99 }, + + { "v8dbg_class_AccessCheckInfo__data__Object", 0xc }, + { "v8dbg_class_AccessCheckInfo__indexed_callback__Object", 0x8 }, + { "v8dbg_class_AccessCheckInfo__named_callback__Object", 0x4 }, + { "v8dbg_class_AccessorInfo__data__Object", 0xc }, + { "v8dbg_class_AccessorInfo__flag__Smi", 0x14 }, + { "v8dbg_class_AccessorInfo__getter__Object", 0x4 }, + { "v8dbg_class_AccessorInfo__name__Object", 0x10 }, + { "v8dbg_class_AccessorInfo__setter__Object", 0x8 }, + { "v8dbg_class_BreakPointInfo__break_point_objects__Object", 0x10 }, + { "v8dbg_class_BreakPointInfo__code_position__Smi", 0x4 }, + { "v8dbg_class_BreakPointInfo__source_position__Smi", 0x8 }, + { "v8dbg_class_BreakPointInfo__statement_position__Smi", 0xc }, + { "v8dbg_class_CallHandlerInfo__callback__Object", 0x4 }, + { "v8dbg_class_CallHandlerInfo__data__Object", 0x8 }, + { "v8dbg_class_Code__deoptimization_data__FixedArray", 0xc }, + { "v8dbg_class_Code__next_code_flushing_candidate__Object", 0x10 }, + { "v8dbg_class_Code__relocation_info__ByteArray", 0x8 }, + { "v8dbg_class_CodeCache__default_cache__FixedArray", 0x4 }, + { "v8dbg_class_CodeCache__normal_type_cache__Object", 0x8 }, + { "v8dbg_class_ConsString__first__String", 0xc }, + { "v8dbg_class_ConsString__second__String", 0x10 }, + { "v8dbg_class_DebugInfo__break_points__FixedArray", 0x14 }, + { "v8dbg_class_DebugInfo__code__Code", 0xc }, + { "v8dbg_class_DebugInfo__original_code__Code", 0x8 }, + { "v8dbg_class_DebugInfo__shared__SharedFunctionInfo", 0x4 }, + { "v8dbg_class_ExternalString__resource__Object", 0xc }, + { "v8dbg_class_FixedArray__data__uintptr_t", 0x8 }, + { "v8dbg_class_FixedArrayBase__length__SMI", 0x4 }, + { "v8dbg_class_FunctionTemplateInfo__access_check_info__Object", 0x38 }, + { "v8dbg_class_FunctionTemplateInfo__call_code__Object", 0x10 }, + { "v8dbg_class_FunctionTemplateInfo__class_name__Object", 0x2c }, + { "v8dbg_class_FunctionTemplateInfo__flag__Smi", 0x3c }, + { "v8dbg_class_FunctionTemplateInfo__indexed_property_handler__Object", + 0x24 }, + { "v8dbg_class_FunctionTemplateInfo__instance_call_handler__Object", + 0x34 }, + { "v8dbg_class_FunctionTemplateInfo__instance_template__Object", 0x28 }, + { "v8dbg_class_FunctionTemplateInfo__named_property_handler__Object", + 0x20 }, + { "v8dbg_class_FunctionTemplateInfo__parent_template__Object", 0x1c }, + { "v8dbg_class_FunctionTemplateInfo__property_accessors__Object", + 0x14 }, + { "v8dbg_class_FunctionTemplateInfo__prototype_template__Object", + 0x18 }, + { "v8dbg_class_FunctionTemplateInfo__serial_number__Object", 0xc }, + { "v8dbg_class_FunctionTemplateInfo__signature__Object", 0x30 }, + { "v8dbg_class_GlobalObject__builtins__JSBuiltinsObject", 0xc }, + { "v8dbg_class_GlobalObject__global_context__Context", 0x10 }, + { "v8dbg_class_GlobalObject__global_receiver__JSObject", 0x14 }, + { "v8dbg_class_HeapNumber__value__double", 0x4 }, + { "v8dbg_class_HeapObject__map__Map", 0x0 }, + { "v8dbg_class_InterceptorInfo__data__Object", 0x18 }, + { "v8dbg_class_InterceptorInfo__deleter__Object", 0x10 }, + { "v8dbg_class_InterceptorInfo__enumerator__Object", 0x14 }, + { "v8dbg_class_InterceptorInfo__getter__Object", 0x4 }, + { "v8dbg_class_InterceptorInfo__query__Object", 0xc }, + { "v8dbg_class_InterceptorInfo__setter__Object", 0x8 }, + { "v8dbg_class_JSArray__length__Object", 0xc }, + { "v8dbg_class_JSFunction__literals__FixedArray", 0x1c }, + { "v8dbg_class_JSFunction__next_function_link__Object", 0x20 }, + { "v8dbg_class_JSFunction__prototype_or_initial_map__Object", 0x10 }, + { "v8dbg_class_JSFunction__shared__SharedFunctionInfo", 0x14 }, + { "v8dbg_class_JSFunctionProxy__call_trap__Object", 0x8 }, + { "v8dbg_class_JSFunctionProxy__construct_trap__Object", 0xc }, + { "v8dbg_class_JSGlobalProxy__context__Object", 0xc }, + { "v8dbg_class_JSMessageObject__arguments__JSArray", 0x10 }, + { "v8dbg_class_JSMessageObject__end_position__SMI", 0x24 }, + { "v8dbg_class_JSMessageObject__script__Object", 0x14 }, + { "v8dbg_class_JSMessageObject__stack_frames__Object", 0x1c }, + { "v8dbg_class_JSMessageObject__stack_trace__Object", 0x18 }, + { "v8dbg_class_JSMessageObject__start_position__SMI", 0x20 }, + { "v8dbg_class_JSMessageObject__type__String", 0xc }, + { "v8dbg_class_JSObject__elements__Object", 0x8 }, + { "v8dbg_class_JSObject__properties__FixedArray", 0x4 }, + { "v8dbg_class_JSProxy__handler__Object", 0x4 }, + { "v8dbg_class_JSRegExp__data__Object", 0xc }, + { "v8dbg_class_JSValue__value__Object", 0xc }, + { "v8dbg_class_JSWeakMap__next__Object", 0x10 }, + { "v8dbg_class_JSWeakMap__table__ObjectHashTable", 0xc }, + { "v8dbg_class_Map__code_cache__Object", 0x18 }, + { "v8dbg_class_Map__constructor__Object", 0x10 }, + { "v8dbg_class_Map__inobject_properties__int", 0x5 }, + { "v8dbg_class_Map__instance_attributes__int", 0x8 }, + { "v8dbg_class_Map__instance_descriptors__int", 0x14 }, + { "v8dbg_class_Map__instance_size__int", 0x4 }, + { "v8dbg_class_Map__prototype_transitions__FixedArray", 0x1c }, + { "v8dbg_class_ObjectTemplateInfo__constructor__Object", 0xc }, + { "v8dbg_class_ObjectTemplateInfo__internal_field_count__Object", + 0x10 }, + { "v8dbg_class_Oddball__to_number__Object", 0x8 }, + { "v8dbg_class_Oddball__to_string__String", 0x4 }, + { "v8dbg_class_PolymorphicCodeCache__cache__Object", 0x4 }, + { "v8dbg_class_Script__column_offset__Smi", 0x10 }, + { "v8dbg_class_Script__compilation_type__Smi", 0x24 }, + { "v8dbg_class_Script__context_data__Object", 0x18 }, + { "v8dbg_class_Script__data__Object", 0x14 }, + { "v8dbg_class_Script__eval_from_instructions_offset__Smi", 0x34 }, + { "v8dbg_class_Script__eval_from_shared__Object", 0x30 }, + { "v8dbg_class_Script__id__Object", 0x2c }, + { "v8dbg_class_Script__line_ends__Object", 0x28 }, + { "v8dbg_class_Script__line_offset__Smi", 0xc }, + { "v8dbg_class_Script__name__Object", 0x8 }, + { "v8dbg_class_Script__source__Object", 0x4 }, + { "v8dbg_class_Script__type__Smi", 0x20 }, + { "v8dbg_class_Script__wrapper__Foreign", 0x1c }, + { "v8dbg_class_SeqAsciiString__chars__char", 0xc }, + { "v8dbg_class_SharedFunctionInfo__compiler_hints__SMI", 0x50 }, + { "v8dbg_class_SharedFunctionInfo__construct_stub__Code", 0x10 }, + { "v8dbg_class_SharedFunctionInfo__debug_info__Object", 0x20 }, + { "v8dbg_class_SharedFunctionInfo__end_position__SMI", 0x48 }, + { "v8dbg_class_SharedFunctionInfo__expected_nof_properties__SMI", + 0x3c }, + { "v8dbg_class_SharedFunctionInfo__formal_parameter_count__SMI", 0x38 }, + { "v8dbg_class_SharedFunctionInfo__function_data__Object", 0x18 }, + { "v8dbg_class_SharedFunctionInfo__function_token_position__SMI", + 0x4c }, + { "v8dbg_class_SharedFunctionInfo__inferred_name__String", 0x24 }, + { "v8dbg_class_SharedFunctionInfo__initial_map__Object", 0x28 }, + { "v8dbg_class_SharedFunctionInfo__instance_class_name__Object", 0x14 }, + { "v8dbg_class_SharedFunctionInfo__length__SMI", 0x34 }, + { "v8dbg_class_SharedFunctionInfo__name__Object", 0x4 }, + { "v8dbg_class_SharedFunctionInfo__num_literals__SMI", 0x40 }, + { "v8dbg_class_SharedFunctionInfo__opt_count__SMI", 0x58 }, + { "v8dbg_class_SharedFunctionInfo__script__Object", 0x1c }, + { "v8dbg_class_SharedFunctionInfo__" + "start_position_and_type__SMI", 0x44 }, + { "v8dbg_class_SharedFunctionInfo__" + "this_property_assignments__Object", 0x2c }, + { "v8dbg_class_SharedFunctionInfo__" + "this_property_assignments_count__SMI", 0x54 }, + { "v8dbg_class_SignatureInfo__args__Object", 0x8 }, + { "v8dbg_class_SignatureInfo__receiver__Object", 0x4 }, + { "v8dbg_class_SlicedString__offset__SMI", 0x10 }, + { "v8dbg_class_String__length__SMI", 0x4 }, + { "v8dbg_class_TemplateInfo__property_list__Object", 0x8 }, + { "v8dbg_class_TemplateInfo__tag__Object", 0x4 }, + { "v8dbg_class_TypeSwitchInfo__types__Object", 0x4 }, + + { "v8dbg_parent_AccessCheckInfo__Struct", 0x0 }, + { "v8dbg_parent_AccessorInfo__Struct", 0x0 }, + { "v8dbg_parent_BreakPointInfo__Struct", 0x0 }, + { "v8dbg_parent_ByteArray__FixedArrayBase", 0x0 }, + { "v8dbg_parent_CallHandlerInfo__Struct", 0x0 }, + { "v8dbg_parent_Code__HeapObject", 0x0 }, + { "v8dbg_parent_CodeCache__Struct", 0x0 }, + { "v8dbg_parent_ConsString__String", 0x0 }, + { "v8dbg_parent_DebugInfo__Struct", 0x0 }, + { "v8dbg_parent_DeoptimizationInputData__FixedArray", 0x0 }, + { "v8dbg_parent_DeoptimizationOutputData__FixedArray", 0x0 }, + { "v8dbg_parent_DescriptorArray__FixedArray", 0x0 }, + { "v8dbg_parent_ExternalArray__FixedArrayBase", 0x0 }, + { "v8dbg_parent_ExternalAsciiString__ExternalString", 0x0 }, + { "v8dbg_parent_ExternalByteArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalDoubleArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalFloatArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalIntArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalPixelArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalShortArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalString__String", 0x0 }, + { "v8dbg_parent_ExternalTwoByteString__ExternalString", 0x0 }, + { "v8dbg_parent_ExternalUnsignedByteArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalUnsignedIntArray__ExternalArray", 0x0 }, + { "v8dbg_parent_ExternalUnsignedShortArray__ExternalArray", 0x0 }, + { "v8dbg_parent_Failure__MaybeObject", 0x0 }, + { "v8dbg_parent_FixedArray__FixedArrayBase", 0x0 }, + { "v8dbg_parent_FixedArrayBase__HeapObject", 0x0 }, + { "v8dbg_parent_FixedDoubleArray__FixedArrayBase", 0x0 }, + { "v8dbg_parent_Foreign__HeapObject", 0x0 }, + { "v8dbg_parent_FunctionTemplateInfo__TemplateInfo", 0x0 }, + { "v8dbg_parent_GlobalObject__JSObject", 0x0 }, + { "v8dbg_parent_HashTable__FixedArray", 0x0 }, + { "v8dbg_parent_HeapNumber__HeapObject", 0x0 }, + { "v8dbg_parent_HeapObject__Object", 0x0 }, + { "v8dbg_parent_InterceptorInfo__Struct", 0x0 }, + { "v8dbg_parent_JSArray__JSObject", 0x0 }, + { "v8dbg_parent_JSBuiltinsObject__GlobalObject", 0x0 }, + { "v8dbg_parent_JSFunction__JSObject", 0x0 }, + { "v8dbg_parent_JSFunctionProxy__JSProxy", 0x0 }, + { "v8dbg_parent_JSFunctionResultCache__FixedArray", 0x0 }, + { "v8dbg_parent_JSGlobalObject__GlobalObject", 0x0 }, + { "v8dbg_parent_JSGlobalPropertyCell__HeapObject", 0x0 }, + { "v8dbg_parent_JSMessageObject__JSObject", 0x0 }, + { "v8dbg_parent_JSObject__JSReceiver", 0x0 }, + { "v8dbg_parent_JSProxy__JSReceiver", 0x0 }, + { "v8dbg_parent_JSReceiver__HeapObject", 0x0 }, + { "v8dbg_parent_JSRegExp__JSObject", 0x0 }, + { "v8dbg_parent_JSRegExpResult__JSArray", 0x0 }, + { "v8dbg_parent_JSValue__JSObject", 0x0 }, + { "v8dbg_parent_JSWeakMap__JSObject", 0x0 }, + { "v8dbg_parent_Map__HeapObject", 0x0 }, + { "v8dbg_parent_NormalizedMapCache__FixedArray", 0x0 }, + { "v8dbg_parent_ObjectTemplateInfo__TemplateInfo", 0x0 }, + { "v8dbg_parent_Oddball__HeapObject", 0x0 }, + { "v8dbg_parent_PolymorphicCodeCache__Struct", 0x0 }, + { "v8dbg_parent_Script__Struct", 0x0 }, + { "v8dbg_parent_SeqAsciiString__SeqString", 0x0 }, + { "v8dbg_parent_SeqString__String", 0x0 }, + { "v8dbg_parent_SeqTwoByteString__SeqString", 0x0 }, + { "v8dbg_parent_SharedFunctionInfo__HeapObject", 0x0 }, + { "v8dbg_parent_SignatureInfo__Struct", 0x0 }, + { "v8dbg_parent_SlicedString__String", 0x0 }, + { "v8dbg_parent_Smi__Object", 0x0 }, + { "v8dbg_parent_String__HeapObject", 0x0 }, + { "v8dbg_parent_Struct__HeapObject", 0x0 }, + { "v8dbg_parent_TemplateInfo__Struct", 0x0 }, + { "v8dbg_parent_TypeSwitchInfo__Struct", 0x0 }, + + { "v8dbg_frametype_ArgumentsAdaptorFrame", 0x8 }, + { "v8dbg_frametype_ConstructFrame", 0x7 }, + { "v8dbg_frametype_EntryConstructFrame", 0x2 }, + { "v8dbg_frametype_EntryFrame", 0x1 }, + { "v8dbg_frametype_ExitFrame", 0x3 }, + { "v8dbg_frametype_InternalFrame", 0x6 }, + { "v8dbg_frametype_JavaScriptFrame", 0x4 }, + { "v8dbg_frametype_OptimizedFrame", 0x5 }, + + { "v8dbg_off_fp_args", 0x8 }, + { "v8dbg_off_fp_context", -0x4 }, + { "v8dbg_off_fp_function", -0x8 }, + { "v8dbg_off_fp_marker", -0x8 }, + + { "v8dbg_prop_idx_content", 0x1 }, + { "v8dbg_prop_idx_first", 0x3 }, + { "v8dbg_prop_type_field", 0x1 }, + { "v8dbg_prop_type_first_phantom", 0x6 }, + { "v8dbg_prop_type_mask", 0xf }, + + { "v8dbg_AsciiStringTag", 0x4 }, + { "v8dbg_PointerSizeLog2", 0x2 }, + { "v8dbg_SeqStringTag", 0x0 }, + { "v8dbg_SmiTag", 0x0 }, + { "v8dbg_SmiTagMask", 0x1 }, + { "v8dbg_SmiValueShift", 0x1 }, + { "v8dbg_StringEncodingMask", 0x4 }, + { "v8dbg_StringRepresentationMask", 0x3 }, + { "v8dbg_StringTag", 0x0 }, + { "v8dbg_TwoByteStringTag", 0x0 }, + { "v8dbg_ConsStringTag", 0x1 }, + { "v8dbg_ExternalStringTag", 0x2 }, + { "v8dbg_FailureTag", 0x3 }, + { "v8dbg_FailureTagMask", 0x3 }, + { "v8dbg_FirstNonstringType", 0x80 }, + { "v8dbg_HeapObjectTag", 0x1 }, + { "v8dbg_HeapObjectTagMask", 0x3 }, + { "v8dbg_IsNotStringMask", 0x80 }, + { "v8dbg_NotStringTag", 0x80 }, + + { NULL }, +}; + +v8_cfg_t v8_cfgs[] = { + { "node-0.4", "node 0.4 versions starting with 0.4.8", v8_cfg_node_04, + v8cfg_canned_iter, v8cfg_canned_readsym }, + { "node-0.6.5", "node v0.6.5", v8_cfg_node_065, + v8cfg_canned_iter, v8cfg_canned_readsym }, + { NULL } +}; + +v8_cfg_t v8_cfg_target = { NULL, NULL, NULL, v8cfg_target_iter, + v8cfg_target_readsym }; diff --git a/usr/src/cmd/mdb/common/modules/v8/v8cfg.h b/usr/src/cmd/mdb/common/modules/v8/v8cfg.h new file mode 100644 index 0000000000..398e9b418b --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/v8/v8cfg.h @@ -0,0 +1,53 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2011, Joyent, Inc. All rights reserved. + */ + +/* + * v8cfg.h: canned configurations for previous V8 versions + */ + +#ifndef V8CFG_H +#define V8CFG_H + +#include <sys/types.h> +#include <sys/mdb_modapi.h> + +typedef struct { + const char *v8cs_name; /* symbol name */ + intptr_t v8cs_value; /* symbol value */ +} v8_cfg_symbol_t; + +typedef struct v8_cfg { + const char *v8cfg_name; /* canned config name */ + const char *v8cfg_label; /* description */ + v8_cfg_symbol_t *v8cfg_symbols; /* actual symbol values */ + + int (*v8cfg_iter)(struct v8_cfg *, int (*)(mdb_symbol_t *, void *), + void *); + int (*v8cfg_readsym)(struct v8_cfg *, const char *, intptr_t *); +} v8_cfg_t; + +extern v8_cfg_t v8_cfg_target; +extern v8_cfg_t v8_cfgs[]; + +#endif diff --git a/usr/src/cmd/mdb/common/modules/v8/v8dbg.h b/usr/src/cmd/mdb/common/modules/v8/v8dbg.h new file mode 100644 index 0000000000..486ac5e255 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/v8/v8dbg.h @@ -0,0 +1,81 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2011, Joyent, Inc. All rights reserved. + */ + +/* + * v8dbg.h: macros for use by V8 heap inspection tools. The consumer must + * define values for various tags and shifts. The MDB module gets these + * constants from information encoded in the binary itself. + */ + +#ifndef _V8DBG_H +#define _V8DBG_H + +/* + * Recall that while V8 heap objects are always 4-byte aligned, heap object + * pointers always have the last bit set. So when looking for a field nominally + * at offset X, one must be sure to clear the tag bit first. + */ +#define V8_OFF_HEAP(x) ((x) - V8_HeapObjectTag) + +/* + * Determine whether a given pointer refers to a SMI, Failure, or HeapObject. + */ +#define V8_IS_SMI(ptr) (((ptr) & V8_SmiTagMask) == V8_SmiTag) +#define V8_IS_FAILURE(ptr) (((ptr) & V8_FailureTagMask) == V8_FailureTag) +#define V8_IS_HEAPOBJECT(ptr) \ + (((ptr) & V8_HeapObjectTagMask) == V8_HeapObjectTag) + +/* + * Extract the value of a SMI "pointer". Recall that small integers are stored + * using the upper 31 bits. + */ +#define V8_SMI_VALUE(smi) ((smi) >> 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) + +/* + * Several of the following constants and transformations are hardcoded in V8 as + * well, so there's no way to extract them programmatically from the binary. + */ +#define V8_DESC_KEYIDX(x) ((x) + V8_PROP_IDX_FIRST) +#define V8_DESC_VALIDX(x) ((x) << 1) +#define V8_DESC_DETIDX(x) (((x) << 1) + 1) + +#define V8_DESC_ISFIELD(x) \ + (V8_SMI_VALUE((x) & V8_PROP_TYPE_MASK) == V8_PROP_TYPE_FIELD) + +#endif /* _V8DBG_H */ diff --git a/usr/src/cmd/mdb/intel/ia32/v8/Makefile b/usr/src/cmd/mdb/intel/ia32/v8/Makefile new file mode 100644 index 0000000000..a824d4a8e3 --- /dev/null +++ b/usr/src/cmd/mdb/intel/ia32/v8/Makefile @@ -0,0 +1,42 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 2011, Joyent, Inc. All rights reserved. +# + +MODULE = v8.so +MDBTGT = proc + +MODSRCS_DIR = ../../../common/modules/v8 + +MODSRCS = mdb_v8.c mdb_v8_cfg.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module + +%.o: $(MODSRCS_DIR)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + +%.ln: $(MODSRCS_DIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/pkg/manifests/developer-build-onbld.mf b/usr/src/pkg/manifests/developer-build-onbld.mf index 3d44a0cccb..acfefd75cf 100644 --- a/usr/src/pkg/manifests/developer-build-onbld.mf +++ b/usr/src/pkg/manifests/developer-build-onbld.mf @@ -21,9 +21,8 @@ # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. -# - # Copyright 2010, Richard Lowe +# set name=pkg.fmri value=pkg:/developer/build/onbld@$(PKGVERS) set name=pkg.description value="tools used to build the OS-Net consolidation" @@ -107,7 +106,7 @@ file path=opt/onbld/bin/findcrypto mode=0555 file path=opt/onbld/bin/flg.flp mode=0555 file path=opt/onbld/bin/genoffsets mode=0555 file path=opt/onbld/bin/get_depend_info mode=0555 -file path=opt/onbld/bin/git-active mode=0555 +file path=opt/onbld/bin/git-pbchk mode=0555 file path=opt/onbld/bin/hdrchk mode=0555 file path=opt/onbld/bin/hg-active mode=0555 file path=opt/onbld/bin/hgsetup mode=0555 @@ -237,6 +236,7 @@ file path=opt/onbld/man/man1/cw.1 file path=opt/onbld/man/man1/find_elf.1 file path=opt/onbld/man/man1/findunref.1 file path=opt/onbld/man/man1/flg.flp.1 +file path=opt/onbld/man/man1/git-pbchk.1 file path=opt/onbld/man/man1/hdrchk.1 file path=opt/onbld/man/man1/hgsetup.1 file path=opt/onbld/man/man1/interface_check.1 @@ -266,7 +266,9 @@ license usr/src/tools/ctf/dwarf/THIRDPARTYLICENSE \ license=usr/src/tools/ctf/dwarf/THIRDPARTYLICENSE license usr/src/tools/onbld/THIRDPARTYLICENSE \ license=usr/src/tools/onbld/THIRDPARTYLICENSE +link path=opt/onbld/bin/git-nits target=git-pbchk link path=opt/onbld/lib/python target=python2.4 +link path=opt/onbld/man/man1/git-nits.1 target=git-pbchk.1 # DbLookups.py requires elementtree depend fmri=library/python-2/python-extra-24 type=require # webrev(1) requires ps2pdf diff --git a/usr/src/tools/scripts/Makefile b/usr/src/tools/scripts/Makefile index 7849565fde..19e58d0244 100644 --- a/usr/src/tools/scripts/Makefile +++ b/usr/src/tools/scripts/Makefile @@ -68,13 +68,16 @@ PERLMODULES= \ PYFILES= \ cddlchk \ copyrightchk \ - git-active \ + git-pbchk \ hdrchk \ hg-active \ mapfilechk \ validate_pkg \ wsdiff +SCRIPTLINKS= \ + git-nits + MAN1FILES= \ Install.1 \ bldenv.1 \ @@ -85,6 +88,7 @@ MAN1FILES= \ cstyle.1 \ find_elf.1 \ flg.flp.1 \ + git-pbchk.1 \ hdrchk.1 \ interface_check.1 \ interface_cmp.1 \ @@ -100,6 +104,9 @@ MAN1FILES= \ wsdiff.1 \ xref.1 +MAN1LINKS= \ + git-nits.1 + MAKEFILES= \ xref.mk @@ -117,6 +124,8 @@ CLEANFILES = $(SHFILES) $(PERLFILES) $(PYFILES) bldenv.1 include ../Makefile.tools +ROOTONBLDSCRIPTLINKS = $(SCRIPTLINKS:%=$(ROOTONBLDBIN)/%) +ROOTONBLDMAN1LINKS = $(MAN1LINKS:%=$(ROOTONBLDMAN1)/%) $(ROOTONBLDETCFILES) := FILEMODE= 644 $(ROOTONBLDEXCEPTFILES) := FILEMODE= 644 @@ -129,10 +138,19 @@ $(ROOTONBLDMAN1FILES) := FILEMODE= 644 all: $(SHFILES) $(PERLFILES) $(PERLMODULES) $(PYFILES) \ $(MAN1FILES) $(MAKEFILES) +$(ROOTONBLDBIN)/git-nits: + $(RM) $(ROOTONBLDBIN)/git-nits + $(SYMLINK) git-pbchk $(ROOTONBLDBIN)/git-nits + +$(ROOTONBLDMAN1)/git-nits.1: + $(RM) $(ROOTONBLDMAN1)/git-nits.1 + $(SYMLINK) git-pbchk.1 $(ROOTONBLDMAN1)/git-nits.1 + install: all .WAIT $(ROOTONBLDSHFILES) $(ROOTONBLDPERLFILES) \ $(ROOTONBLDPERLMODULES) $(ROOTONBLDPYFILES) \ - $(ROOTONBLDMAN1FILES) $(ROOTONBLDMAKEFILES) \ - $(ROOTONBLDETCFILES) $(ROOTONBLDEXCEPTFILES) + $(ROOTONBLDSCRIPTLINKS) $(ROOTONBLDMAN1FILES) \ + $(ROOTONBLDMAKEFILES) $(ROOTONBLDETCFILES) \ + $(ROOTONBLDEXCEPTFILES) $(ROOTONBLDMAN1LINKS) clean: $(RM) $(CLEANFILES) diff --git a/usr/src/tools/scripts/flg.flp.sh b/usr/src/tools/scripts/flg.flp.sh index 40239cf9e7..38d6278e4e 100644 --- a/usr/src/tools/scripts/flg.flp.sh +++ b/usr/src/tools/scripts/flg.flp.sh @@ -72,7 +72,7 @@ find_files() pat=$1 shift - if [ "$SCM_MODE" = "teamware" ] ; then + if [[ "$SCM_MODE" = "teamware" ]]; then for dir; do if [ -d $CODEMGR_WS/$dir ]; then cd $CODEMGR_WS @@ -81,7 +81,7 @@ find_files() cd - > /dev/null fi done - elif [ "$SCM_MODE" = "mercurial" ]; then + elif [[ "$SCM_MODE" = "mercurial" || "$SCM_MODE" == "git" ]]; then dirs="" for dir; do if [ -d $CODEMGR_WS/$dir ]; then @@ -179,7 +179,9 @@ which_scm | read SCM_MODE CODEMGR_WS || exit 1 if [[ $SCM_MODE == "unknown" ]]; then fail "Unable to determine SCM type currently in use." elif [[ $SCM_MODE == "mercurial" ]]; then - FILELIST=`hg manifest` + FILELIST=$(hg manifest) +elif [[ $SCM_MODE == "git" ]]; then + FILELIST=$(cd $(dirname $(git rev-parse --git-dir)); git ls-files) elif [[ $SCM_MODE != "teamware" ]]; then fail "Unsupported SCM in use: $SCM_MODE" fi diff --git a/usr/src/tools/scripts/git-pbchk.1 b/usr/src/tools/scripts/git-pbchk.1 new file mode 100644 index 0000000000..bb672e7182 --- /dev/null +++ b/usr/src/tools/scripts/git-pbchk.1 @@ -0,0 +1,94 @@ +'\" t +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 2011 Richard Lowe. +.\" + +.TH "GIT\-PBCHK" "1" "December 2011" "" "" + +.SH "NAME" +\fBgit\-pbchk\fR \- nits and pre\-putback checks for git + +.SH "SYNOPSIS" +git\-pbchk [\-b \fIbranch\fR] + +.P +git\-nits [\-b \fIbranch\fR] + +.SH "DESCRIPTION" +Check your workspace for common nits and putback\-ending mistakes, a simple set of checks are run over various parts of your workspace and errors encountered are reported, afll of which should, generally, be fixed\. + +.TP +Comment format +Check that putback comments follow the prescribed format (only run for pbchk) + +.TP +Copyrights +Check that each source file contains a copyright notice for the current year\. You need to fix this if you, the potential new copyright holder, chooses not to + +.TP +C style +Check that C source files conform to the Illumos C style rules + +.TP +Header check +Check that C header files conform to the Illumos header style rules (in addition to the general C rules) + +.TP +Java style +Check that Java source files conform to the Illumos Java style rules (which differ from the traditionally recommended Java style) + +.TP +SCCS Keywords +Check that no source files contain unexpanded SCCS keywords\. It is possible that this check may false positive on certain inputs\. It is generally obvious when this is the case\. + +.IP +This check does not check for expanded SCCS keywords, though the common \'ident\'\-style lines should be removed regardless of whether they are expanded\. + +.TP +Mapfile check +Check that linker mapfiles contain a comment directing anyone editing to read the directions in \fBusr/lib/README\.mapfiles\fR\. + +.SH "OPTIONS" + +.TP +\fB\-b branch\fR: + +.IP +Compare the current workspace to /branch/ for the purposes of generating file and comment lists\. + +.IP +If this option is not specified an attempt is made to determine this automatically, if the git branch configuration contains this information\. + +.IP +If no branch is specified and none can be determined automatically \fBorigin/master\fR is used\. + +.SH "FILES" +\fBgit nits\fR and \fBgit pbchk\fR support NOT files of the form used by Cadmium with Mercurial\. These are looked for in \fB$CODEMGR_WS/\.git/\fR and in \fB$CODEMGR_WS/exception_lists/\fR as normal\. The files are named after the check from which they exclude files\. + +.IP "\(bu" 4 +\fBcopyright\.NOT\fR: exclude files listed from copyright checking + +.IP "\(bu" 4 +\fBcstyle\.NOT\fR: exclude files from the C style check + +.IP "\(bu" 4 +\fBhdrchk\.NOT\fR: exclude files from the C header style check + +.IP "\(bu" 4 +\fBkeywords\.NOT\fR: exclude files from the SCCS keywords check + +.IP "\(bu" 4 +\fBmapfilechk\.NOT\fR: exclude files from the linker mapfile check + +.IP "" 0 + diff --git a/usr/src/tools/scripts/git-pbchk.py b/usr/src/tools/scripts/git-pbchk.py new file mode 100755 index 0000000000..2bcac59d2c --- /dev/null +++ b/usr/src/tools/scripts/git-pbchk.py @@ -0,0 +1,285 @@ +#!/usr/bin/python2.4 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2008, 2011 Richard Lowe +# + +import getopt +import os +import re +import subprocess +import sys + +from cStringIO import StringIO + +# This is necessary because, in a fit of pique, we used hg-format ignore lists +# for NOT files. +from mercurial import ignore + +sys.path.insert(1, os.path.join('/opt/onbld/lib', + "python%d.%d" % sys.version_info[:2])) + +from onbld.Checks import Comments, Copyright, CStyle, HdrChk +from onbld.Checks import JStyle, Keywords, Mapfile + +def run(command): + if type(command) != list: + command = command.split() + + p = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + err = p.wait() + return err != 0 and None or p.stdout + +def git_root(): + p = run('git rev-parse --git-dir') + + if not p: + sys.stderr.write("Failed finding git workspace\n") + sys.exit(err) + + return os.path.abspath(os.path.join(p.readlines()[0], + os.path.pardir)) + +def git_branch(): + p = run('git branch') + + if not p: + sys.stderr.write("Failed finding git branch\n") + sys.exit(err) + + for elt in p: + if elt[0] == '*': + return elt.split()[1] + +def git_parent_branch(branch): + p = run(["git", "for-each-ref", + "--format=%(refname:short) %(upstream:short)", + "refs/heads/"]) + + if not p: + sys.stderr.write("Failed finding git parent branch\n") + sys.exit(err) + + for line in p: + # Git 1.7 will leave a ' ' trailing any non-tracking branch + if ' ' in line and not line.endswith(' \n'): + local, remote = line.split() + if local == branch: + return remote + return 'origin/master' + +def git_comments(branch): + p = run('git log --pretty=format:%%B %s..' % branch) + + if not p: + sys.stderr.write("Failed getting git comments\n") + sys.exit(err) + + return map(lambda x: x.strip(), p.readlines()) + + +def git_file_list(branch, paths=''): + '''Set of files which have ever changed between BRANCH and here''' + p = run("git log --name-only --pretty=format: %s.. %s" % + (branch, paths)) + + if not p: + sys.stderr.write("Failed building file-list from git\n") + sys.exit(err) + + ret = set() + for fname in p: + if fname and not fname.isspace() and fname not in ret: + ret.add(fname.strip()) + + return ret + + +def not_check(root, cmd): + '''Return a function to do NOT matching''' + + ignorefiles = filter(os.path.exists, + [os.path.join(root, ".git", "%s.NOT" % cmd), + os.path.join(root, "exception_lists", cmd)]) + if len(ignorefiles) > 0: + return ignore.ignore(root, ignorefiles, sys.stderr.write) + else: + return lambda x: False + + +def gen_files(root, branch, paths, exclude): + # Taken entirely from 2.6's os.path.relpath which we would use if we + # could. + def relpath(path, here): + c = os.path.abspath(os.path.join(root, path)).split(os.path.sep) + s = os.path.abspath(here).split(os.path.sep) + l = len(os.path.commonprefix((s, c))) + return os.path.join(*[os.path.pardir] * (len(s)-l) + c[l:]) + + def ret(select=lambda x: True): + for f in git_file_list(branch, paths): + f = relpath(f, '.') + if (os.path.exists(f) and select(f) and not exclude(f)): + yield f + return ret + +def comchk(root, branch, flist, output): + output.write("Comments:\n") + + return Comments.comchk(git_comments(branch), check_db=True, + output=output) + +def mapfilechk(root, branch, flist, output): + ret = 0 + + # We are interested in examining any file that has the following + # in its final path segment: + # - Contains the word 'mapfile' + # - Begins with 'map.' + # - Ends with '.map' + # We don't want to match unless these things occur in final path segment + # because directory names with these strings don't indicate a mapfile. + # We also ignore files with suffixes that tell us that the files + # are not mapfiles. + MapfileRE = re.compile(r'.*((mapfile[^/]*)|(/map\.+[^/]*)|(\.map))$', + re.IGNORECASE) + NotMapSuffixRE = re.compile(r'.*\.[ch]$', re.IGNORECASE) + + output.write("Mapfile comments:\n") + + for f in flist(lambda x: MapfileRE.match(x) and not + NotMapSuffixRE.match(x)): + fh = open(f, 'r') + ret |= Mapfile.mapfilechk(fh, output=output) + fh.close() + return ret + + +def copyright(root, branch, flist, output): + ret = 0 + output.write("Copyrights:\n") + for f in flist(): + fh = open(f, 'r') + ret |= Copyright.copyright(fh, output=output) + fh.close() + return ret + + +def hdrchk(root, branch, flist, output): + ret = 0 + output.write("Header format:\n") + for f in flist(lambda x: x.endswith('.h')): + fh = open(f, 'r') + ret |= HdrChk.hdrchk(fh, lenient=True, output=output) + fh.close() + return ret + + +def cstyle(root, branch, flist, output): + ret = 0 + output.write("C style:\n") + for f in flist(lambda x: x.endswith('.c') or x.endswith('.h')): + fh = open(f, 'r') + ret |= CStyle.cstyle(fh, output=output, picky=True, + check_posix_types=True, + check_continuation=True) + fh.close() + return ret + + +def jstyle(root, branch, flist, output): + ret = 0 + output.write("Java style:\n") + for f in flist(lambda x: x.endswith('.java')): + fh = open(f, 'r') + ret |= JStyle.jstyle(fh, output=output, picky=True) + fh.close() + return ret + + +def keywords(root, branch, flist, output): + ret = 0 + output.write("SCCS Keywords:\n") + for f in flist(): + fh = open(f, 'r') + ret |= Keywords.keywords(fh, output=output) + fh.close() + return ret + + +def run_checks(root, branch, cmds, paths='', opts={}): + ret = 0 + + for cmd in cmds: + s = StringIO() + + exclude = not_check(root, cmd.func_name) + result = cmd(root, branch, gen_files(root, branch, paths, exclude), + output=s) + ret |= result + + if result != 0: + print s.getvalue() + + return ret + + +def nits(root, branch, paths=''): + cmds = [copyright, + cstyle, + hdrchk, + jstyle, + keywords, + mapfilechk] + run_checks(root, branch, cmds, paths='') + +def pbchk(root, branch): + cmds = [comchk, + copyright, + cstyle, + hdrchk, + jstyle, + keywords, + mapfilechk] + run_checks(root, branch, cmds) + +if __name__ == '__main__': + branch = None + + try: + opts, args = getopt.getopt(sys.argv[1:], 'b:') + except getopt.GetoptError, e: + sys.stderr.write(str(e)) + sys.stderr.write("Usage: git-nits [-b branch] [path...]\n") + sys.exit(1) + + for opt, arg in opts: + if opt == '-b': + branch = arg + + if not branch: + branch = git_parent_branch(git_branch()) + + func = nits + if sys.argv[0].endswith('/git-pbchk'): + func = pbchk + + func(git_root(), branch) diff --git a/usr/src/tools/scripts/nightly.sh b/usr/src/tools/scripts/nightly.sh index abebb16b51..b64ed6f8ad 100644 --- a/usr/src/tools/scripts/nightly.sh +++ b/usr/src/tools/scripts/nightly.sh @@ -2138,7 +2138,7 @@ if [ "$i_FLAG" = "n" -a -d "$SRC" ]; then # Remove all .make.state* files, just in case we are restarting # the build after having interrupted a previous 'make clobber'. - find . \( -name SCCS -o -name .hg -o -name .svn -o -name .git \ + find . \( -name SCCS -o -name .hg -o -name .svn -o name .git \ -o -name 'interfaces.*' \) -prune \ -o -name '.make.*' -print | xargs rm -f @@ -2173,7 +2173,7 @@ if [ "$i_FLAG" = "n" -a -d "$SRC" ]; then # under source code control, so leave them alone. # We should probably blow away temporary directories too. cd $SRC - find $relsrcdirs \( -name SCCS -o -name .hg -o -name .svn -o -name .git\ + find $relsrcdirs \( -name SCCS -o -name .hg -o -name .svn -o name .git\ -o -name 'interfaces.*' \) -prune -o \ \( -name '.make.*' -o -name 'lib*.a' -o -name 'lib*.so*' -o \ -name '*.o' \) -print | \ diff --git a/usr/src/tools/scripts/webrev.1 b/usr/src/tools/scripts/webrev.1 index e83acd80f8..b0cf41080e 100644 --- a/usr/src/tools/scripts/webrev.1 +++ b/usr/src/tools/scripts/webrev.1 @@ -22,7 +22,7 @@ .\" Use is subject to license terms. .\" .\" -.TH webrev 1 "22 Feb 2010" +.TH webrev 1 "6 Dec 2010" .SH NAME webrev \- Generate HTML codereview materials .SH SYNOPSIS @@ -60,7 +60,7 @@ Note that the -l option is only applicable to TeamWare workspaces. .B webrev builds a set of HTML files suitable for performing code review of source changes in a web browser. -It supports Mercurial, Subversion and Teamware repositories. +It supports Mercurial, Git, Subversion and Teamware repositories. At its most basic, usage is: .nf $ webrev @@ -174,9 +174,22 @@ or to reference a teamware flp (file list program). In the case of Mercurial \fBwebrev\fR will attempt to use the output from the .BR hg (1) -"hg root" to identify the workspace root, and the +"hg root" command to identify the workspace root, and the "hg path default" command to identify the parent workspace. +.SS Git +In the case of Git \fBwebrev\fR will attempt to use the output from the +.BR git (1) +"git rev-parse --git-dir" command to identify the workspace root, and will +attempt to use the remote branch which the current branch is tracking as the +parent, if none is specified 'origin/master' will be used. + +The parent specified when git is, in all cases, a git 'tree-ish' and never an +actual git repository, remote or otherwise. Anything specifiable to git as a +tree-ish should, similarly, be specifiable as a parent for webrev. This +includes branches, explicit revisions, reflog entries, etc. See +.BR git-rev-parse (1) + .SS Subversion In the case of Subversion \fBwebrev\fR will attempt to use the output from the @@ -458,6 +471,7 @@ This will remove just the \fIbugfix.onnv\fR directory. .BR putback "(1)," .BR workspace "(1)," .BR hg "(1)," +.BR git "(1)," .BR ssh_config "(4)," .BR svn "(1)," .BR which_scm "(1)" diff --git a/usr/src/tools/scripts/webrev.sh b/usr/src/tools/scripts/webrev.sh index 018341fe71..318feff6cb 100644 --- a/usr/src/tools/scripts/webrev.sh +++ b/usr/src/tools/scripts/webrev.sh @@ -516,6 +516,16 @@ html_quote() $SED -e "s/&/\&/g" -e "s/</\</g" -e "s/>/\>/g" "$@" | expand } +# +# Trim a digest-style revision to a conventionally readable yet useful length +# +trim_digest() +{ + typeset digest=$1 + + echo $digest | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/' +} + # # input_cmd | its2url | output_cmd # @@ -1780,36 +1790,75 @@ function flist_from_mercurial } # -# Call git-active to get the active list output in the wx active list format +# Transform a specified 'git log' output format into a wx-like active list. # -function git_active_wxfile +function git_wxfile { - typeset child=$1 - typeset parent=$2 + typeset child="$1" + typeset parent="$2" TMPFLIST=/tmp/$$.active - $GIT_ACTIVE -w $child -p $parent -o $TMPFLIST + $PERL -e 'my (%files, %realfiles, $msg); + my $branch = $ARGV[0]; + + open(F, "git diff -M --name-status $branch |"); + while (<F>) { + chomp; + if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename + if ($1 >= 75) { # Probably worth treating as a rename + $realfiles{$3} = $2 + } else { + $realfiles{$3} = $3; + $realfiles{$2} = $2; + } + } else { + my $f = (split /\s+/, $_)[1]; + $realfiles{$f} = $f; + } + } + close(F); + + my $state = 1; # 0|comments, 1|files + open(F, "git whatchanged --pretty=format:%B $branch.. |"); + while (<F>) { + chomp; + if (/^:[0-9]{6}/) { + my $fname = (split /\t/, $_)[1]; + next if !defined($realfiles{$fname}); # No real change + $state = 1; + $files{$fname} = $msg; + } else { + if ($state == 1) { + $state = 0; + $msg = /^\n/ ? "" : "\n"; + } + $msg .= "$_\n" if ($_); + } + } + close(F); + + for (sort keys %files) { + if ($realfiles{$_} ne $_) { + print "$_ $realfiles{$_}\n$files{$_}\n"; + } else { + print "$_\n$files{$_}\n" + } + }' ${parent} > $TMPFLIST + wxfile=$TMPFLIST } # # flist_from_git -# Call git-active to get a wx-style active list, and hand it off to -# flist_from_wx +# Build a wx-style active list, and hand it off to flist_from_wx # function flist_from_git { typeset child=$1 typeset parent=$2 - print " File list from: git-active -p $parent ...\c" - - if [[ ! -x $GIT_ACTIVE ]]; then - print # Blank line for the \c above - print -u2 "Error: git-active tool not found. Exiting" - exit 1 - fi - git_active_wxfile $child $parent + print " File list from: git ...\c" + git_wxfile "$child" "$parent"; # flist_from_wx prints the Done, so we don't have to. flist_from_wx $TMPFLIST @@ -2039,36 +2088,41 @@ function build_old_new_git { typeset olddir="$1" typeset newdir="$2" - typeset ws_top_dir=$(dirname $3) typeset o_mode= typeset n_mode= typeset o_object= typeset n_object= + typeset OWD=$PWD typeset file typeset type + cd $CWS + # # Get old file and its mode from the git object tree # if [[ "$PDIR" == "." ]]; then file="$PF" else - file="$PDIR/$PF" + file="$PDIR/$PF" fi - curr_dir=$(pwd) - cd $ws_top_dir - - git ls-tree $GIT_PARENT $file | read o_mode type o_object junk - git cat-file $type $o_object > $olddir/$file 2>/dev/null - - if (( $? != 0 )); then - rm -f $olddir/$file - elif [[ -n $o_mode ]]; then - chmod $o_mode $olddir/$file + if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then + cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF else - # should never happen - print -u2 "ERROR: set mode of $olddir/$file" + $GIT ls-tree $GIT_PARENT $file | read o_mode type o_object junk + $GIT cat-file $type $o_object > $olddir/$file 2>/dev/null + + if (( $? != 0 )); then + rm -f $olddir/$file + elif [[ -n $o_mode ]]; then + # Strip the first 3 digits, to get a regular octal mode + o_mode=${o_mode/???/} + chmod $o_mode $olddir/$file + else + # should never happen + print -u2 "ERROR: set mode of $olddir/$file" + fi fi # @@ -2080,16 +2134,12 @@ function build_old_new_git file="$DIR/$F" fi rm -rf $newdir/$file - git ls-tree HEAD $file | read n_mode type n_object junk - git cat-file $type $n_object > $newdir/$file 2>/dev/null - cd $curr_dir - if [[ -n $n_mode ]]; then - chmod $n_mode $newdir/$file - else - # should never happen - print -u2 "ERROR: set mode of $newdir/$file" - fi + if [[ -e $CWS/$DIR/$F ]]; then + cp $CWS/$DIR/$F $newdir/$DIR/$F + chmod $(get_file_mode $CWS/$DIR/$F) $newdir/$DIR/$F + fi + cd $OWD } function build_old_new_subversion @@ -2153,7 +2203,7 @@ function build_old_new elif [[ $SCM_MODE == "mercurial" ]]; then build_old_new_mercurial "$olddir" "$newdir" elif [[ $SCM_MODE == "git" ]]; then - build_old_new_git "$olddir" "$newdir" "$CWS" + build_old_new_git "$olddir" "$newdir" elif [[ $SCM_MODE == "subversion" ]]; then build_old_new_subversion "$olddir" "$newdir" elif [[ $SCM_MODE == "unknown" ]]; then @@ -2215,12 +2265,12 @@ trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15 set +o noclobber -PATH=$(dirname $(whence $0)):$PATH +PATH=$(dirname "$(whence $0)"):$PATH [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff` [[ -z $WX ]] && WX=`look_for_prog wx` [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active` -[[ -z $GIT_ACTIVE ]] && GIT_ACTIVE=`look_for_prog git-active` +[[ -z $GIT ]] && GIT=`look_for_prog git` [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm` [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview` [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf` @@ -2410,15 +2460,16 @@ elif [[ $SCM_MODE == "git" ]]; then # 2. git rev-parse --git-dir from directory of invocation # [[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \ - codemgr_ws=$(git --git-dir=$CODEMGR_WS rev-parse --git-dir \ - 2>/dev/null) + codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \ + 2>/dev/null) [[ -z $codemgr_ws ]] && \ - codemgr_ws=$(git rev-parse --git-dir 2>/dev/null) + codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null) if [[ "$codemgr_ws" == ".git" ]]; then - codemgr_ws="$PWD/.git" + codemgr_ws="${PWD}/${codemgr_ws}" fi + codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git' CWS="$codemgr_ws" elif [[ $SCM_MODE == "subversion" ]]; then # @@ -2471,8 +2522,8 @@ fi # then note that fact and set the parent to the raw_files/new subdirectory. # if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then - parent_webrev="$codemgr_parent" - codemgr_parent="$codemgr_parent/raw_files/new" + parent_webrev=$(readlink -f "$codemgr_parent") + codemgr_parent=$(readlink -f "$codemgr_parent/raw_files/new") fi if [[ -z $wflag && -z $lflag ]]; then @@ -2665,7 +2716,6 @@ elif [[ $SCM_MODE == "mercurial" ]]; then codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null` fi - CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null` PWS=$codemgr_parent # @@ -2729,23 +2779,36 @@ elif [[ $SCM_MODE == "mercurial" ]]; then print -u2 "Error: Cannot discover parent revision" exit 1 fi + + pnode=$(trim_digest $HG_PARENT) + PRETTY_PWS="${PWS} (at ${pnode})" + cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \ + 2>/dev/null) + PRETTY_CWS="${CWS} (at ${cnode})"} elif [[ $SCM_MODE == "git" ]]; then # - # Parent can either be specified with -p - # Specified with CODEMGR_PARENT in the environment - # or taken from git config. + # Parent can either be specified with -p, or specified with + # CODEMGR_PARENT in the environment. # if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then codemgr_parent=$CODEMGR_PARENT fi + # Try to figure out the parent based on the branch the current + # branch is tracking, if we fail, use origin/master + this_branch=$($GIT branch | nawk '$1 == "*" { print $2 }') + par_branch="origin/master" + + $GIT for-each-ref \ + --format='%(refname:short) %(upstream:short)' refs/heads/ | \ + while read local remote; do \ + [[ "$local" == "$this_branch" ]] && par_branch="$remote"; \ + done + if [[ -z $codemgr_parent ]]; then - codemgr_parent=$(git --git-dir=$codemgr_ws config \ - remote.origin.url 2>/dev/null) + codemgr_parent=$par_branch fi - - CWS_REV=$(git --git-dir=$codemgr_ws rev-parse HEAD 2>/dev/null) PWS=$codemgr_parent # @@ -2753,63 +2816,56 @@ elif [[ $SCM_MODE == "git" ]]; then # the natural workspace parent (file list, comments, etc) # if [[ -n $parent_webrev ]]; then - real_parent=$(git --git-dir $codemgr_ws config \ - remote.origin.url 2>/dev/null) + real_parent=$par_branch else real_parent=$PWS fi - # - # If git-active exists, then we run it. In the case of no explicit - # flist given, we'll use it for our comments. In the case of an - # explicit flist given we'll try to use it for comments for any - # files mentioned in the flist. - # if [[ -z $flist_done ]]; then - flist_from_git $CWS $real_parent + flist_from_git "$CWS" "$real_parent" flist_done=1 fi # # If we have a file list now, pull out any variables set - # therein. We do this now (rather than when we possibly use - # git-active to find comments) to avoid stomping specifications - # in the user-specified flist. + # therein. # if [[ -n $flist_done ]]; then env_from_flist fi # - # Only call git-active if we don't have a wx formatted file already + # If we don't have a wx-format file list, build one we can pull change + # comments from. # - if [[ -x $GIT_ACTIVE && -z $wxfile ]]; then - print " Comments from: git-active -p $real_parent ...\c" - git_active_wxfile $CWS $real_parent + if [[ -z $wxfile ]]; then + print " Comments from: git...\c" + git_wxfile "$CWS" "$real_parent" print " Done." fi - # - # At this point we must have a wx flist either from git-active, - # or in general. Use it to try and find our parent revision, - # if we don't have one. - # if [[ -z $GIT_PARENT ]]; then - eval `$SED -e "s/#.*$//" $wxfile | $GREP GIT_PARENT=` + GIT_PARENT=$($GIT merge-base "$real_parent" HEAD) fi - - # - # If we still don't have a parent, we must have been given a - # wx-style active list with no GIT_PARENT specification, run - # git-active and pull an GIT_PARENT out of it, ignore the rest. - # - if [[ -z $GIT_PARENT && -x $GIT_ACTIVE ]]; then - $GIT_ACTIVE -w $codemgr_ws -p $real_parent | \ - eval `$SED -e "s/#.*$//" | $GREP GIT_PARENT=` - elif [[ -z $GIT_PARENT ]]; then + if [[ -z $GIT_PARENT ]]; then print -u2 "Error: Cannot discover parent revision" exit 1 fi + + pnode=$(trim_digest $GIT_PARENT) + + if [[ $real_parent == */* ]]; then + origin=$(echo $real_parent | cut -d/ -f1) + origin=$($GIT remote -v | \ + $AWK '$1 == "'$origin'" { print $2; exit }') + PRETTY_PWS="${PWS} (${origin} at ${pnode})" + else + PRETTY_PWS="${PWS} (at ${pnode})" + fi + + cnode=$($GIT --git-dir=${codemgr_ws}/.git rev-parse --short=12 HEAD \ + 2>/dev/null) + PRETTY_CWS="${CWS} (at ${cnode})" elif [[ $SCM_MODE == "subversion" ]]; then # @@ -2876,7 +2932,7 @@ typeset -A itsinfo typeset -r its_sed_script=/tmp/$$.its_sed valid_prefixes= if [[ -z $nflag ]]; then - DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg" + DEFREGFILE="$(dirname "$(whence $0)")/../etc/its.reg" if [[ -n $Iflag ]]; then REGFILE=$ITSREG elif [[ -r $HOME/.its.reg ]]; then @@ -2905,7 +2961,7 @@ if [[ -z $nflag ]]; then done - DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf" + DEFCONFFILE="$(dirname "$(whence $0)")/../etc/its.conf" CONFFILES=$DEFCONFFILE if [[ -r $HOME/.its.conf ]]; then CONFFILES="${CONFFILES} $HOME/.its.conf" @@ -3094,21 +3150,11 @@ fi # # Summarize what we're going to do. # -if [[ -n $CWS_REV ]]; then - print " Workspace: $CWS (at $CWS_REV)" -else - print " Workspace: $CWS" -fi +print " Workspace: ${PRETTY_CWS:-$CWS}" if [[ -n $parent_webrev ]]; then print "Compare against: webrev at $parent_webrev" else - if [[ -n $HG_PARENT ]]; then - hg_parent_short=`echo $HG_PARENT \ - | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'` - print "Compare against: $PWS (at $hg_parent_short)" - else - print "Compare against: $PWS" - fi + print "Compare against: ${PRETTY_PWS:-$PWS}" fi [[ -n $INCLUDE_FILE ]] && print " Including: $INCLUDE_FILE" @@ -3459,19 +3505,13 @@ fi PREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z) print "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>" -print "<tr><th>Workspace:</th><td>$CWS" -if [[ -n $CWS_REV ]]; then - print "(at $CWS_REV)" -fi +print "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}" print "</td></tr>" print "<tr><th>Compare against:</th><td>" if [[ -n $parent_webrev ]]; then print "webrev at $parent_webrev" else - print "$PWS" - if [[ -n $hg_parent_short ]]; then - print "(at $hg_parent_short)" - fi + print "${PRETTY_PWS:-$PWS}" fi print "</td></tr>" print "<tr><th>Summary of changes:</th><td>" diff --git a/usr/src/tools/scripts/which_scm.1 b/usr/src/tools/scripts/which_scm.1 index 25510f3c7e..c7e4c671be 100644 --- a/usr/src/tools/scripts/which_scm.1 +++ b/usr/src/tools/scripts/which_scm.1 @@ -21,7 +21,7 @@ .\" Copyright 2008 Sun Microsystems, Inc. All rights reserved. .\" Use is subject to license terms. .\" -.TH which_scm 1 "5 October 2010" +.TH which_scm 1 "18 September 2009" .SH NAME which_scm \- Report Source Code Management system .SH SYNOPSIS diff --git a/usr/src/tools/scripts/ws.sh b/usr/src/tools/scripts/ws.sh index afe91916f2..9ffa7bf171 100644 --- a/usr/src/tools/scripts/ws.sh +++ b/usr/src/tools/scripts/ws.sh @@ -87,6 +87,14 @@ check_proto() "${proto##https://}" == "$proto" ]; then echo "${proto}/root_${MACH}" fi + elif [ "$SCM_MODE" = "git" ]; then + # + # For git, we make no attempt to deal with the possibility of + # remote parent workspaces because, in the protodefs file, we + # don't actually acknowledge the concept of a parent workspace + # at all, in keeping with the rest of our git support. + # + echo "${1}/root_${MACH}" fi } @@ -105,7 +113,7 @@ else setenv=false fi -WHICH_SCM=$(dirname $(whence $0))/which_scm +WHICH_SCM=$(/bin/dirname $(whence $0))/which_scm if [[ ! -x $WHICH_SCM ]]; then WHICH_SCM=which_scm fi @@ -217,6 +225,10 @@ elif [ "$SCM_MODE" = "mercurial" -a -d ${wsname}/.hg ]; then CM_DATA=".hg" wsosdir=$CODEMGR_WS/$CM_DATA protofile=$wsosdir/org.opensolaris.protodefs +elif [ "$SCM_MODE" = "git" -a -d ${wsname}/.git ]; then + CM_DATA=".git" + wsosdir=$CODEMGR_WS/$CM_DATA + protofile=$wsosdir/org.opensolaris.protodefs else echo "$wsname is not a supported workspace; type is $SCM_MODE" >&2 if $setenv; then @@ -362,7 +374,7 @@ if [[ ! -v CLOSED_IS_PRESENT ]]; then fi if [[ -z "$ONBLD_DIR" ]]; then - ONBLD_DIR=$(dirname $(whence $0)) + ONBLD_DIR=$(/bin/dirname $(whence $0)) fi if ! echo ":$PATH:" | grep ":${ONBLD_DIR}:" > /dev/null; then diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c index 0f880f2458..290494147f 100644 --- a/usr/src/uts/common/dtrace/dtrace.c +++ b/usr/src/uts/common/dtrace/dtrace.c @@ -119,7 +119,7 @@ dtrace_optval_t dtrace_dof_maxsize = (256 * 1024); size_t dtrace_global_maxsize = (16 * 1024); size_t dtrace_actions_max = (16 * 1024); size_t dtrace_retain_max = 1024; -dtrace_optval_t dtrace_helper_actions_max = 32; +dtrace_optval_t dtrace_helper_actions_max = 1024; dtrace_optval_t dtrace_helper_providers_max = 32; dtrace_optval_t dtrace_dstate_defsize = (1 * 1024 * 1024); size_t dtrace_strsize_default = 256; diff --git a/usr/src/uts/common/fs/zfs/dbuf.c b/usr/src/uts/common/fs/zfs/dbuf.c index 7a0abd22b5..16e42b951a 100644 --- a/usr/src/uts/common/fs/zfs/dbuf.c +++ b/usr/src/uts/common/fs/zfs/dbuf.c @@ -2703,7 +2703,8 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx) dr->dt.dl.dr_copies); mutex_exit(&db->db_mtx); } else if (db->db_state == DB_NOFILL) { - ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF); + ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF || + zp.zp_checksum == ZIO_CHECKSUM_NOPARITY); dr->dr_zio = zio_write(zio, os->os_spa, txg, db->db_blkptr, NULL, db->db.db_size, &zp, dbuf_write_nofill_ready, dbuf_write_nofill_done, db, diff --git a/usr/src/uts/common/fs/zfs/vdev_raidz.c b/usr/src/uts/common/fs/zfs/vdev_raidz.c index 736683b6ef..6094e01876 100644 --- a/usr/src/uts/common/fs/zfs/vdev_raidz.c +++ b/usr/src/uts/common/fs/zfs/vdev_raidz.c @@ -1546,8 +1546,6 @@ vdev_raidz_physio(vdev_t *vd, caddr_t data, size_t size, SPA_MAXBLOCKSIZE, origoffset, tvd->vdev_ashift, vd->vdev_children, vd->vdev_nparity); - ASSERT3U(rm->rm_asize, ==, vdev_psize_to_asize(vd, size)); - coloffset = origoffset; for (c = rm->rm_firstdatacol; c < rm->rm_cols; |