summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2015-02-13 13:58:47 +0000
committerRobert Mustacchi <rm@joyent.com>2015-02-13 13:58:47 +0000
commit39fb3e855a4aecad22321e329e58359504b39555 (patch)
treefc78f004574ceb35febc58259402a28df6e94b82 /usr/src/cmd
parent8062190bde2b194ecd0aa6e2063cf3dddcc5d741 (diff)
parenteb20fbe2fac1596990392cf5a8ea5030948e4768 (diff)
downloadillumos-joyent-dev-overlay.tar.gz
[illumos-joyent merge]dev-overlay
commit 3b13a1ef7511135ec0c75b5f94de8075454efd79 5322 tree connect from Windows 7 fails commit 200c7a6f5f903a9dcd83c319bddeee9b627406ac OS-3820 lxbrand ptrace(2): the next generation OS-3685 lxbrand PTRACE_O_TRACEFORK race condition OS-3834 lxbrand 64-bit strace(1) reports 64-bit process as using x32 ABI OS-3794 lxbrand panic on init signal death commit f1630c2becf4af570cefc47794212e8110eb79e3 OS-3796 lxbrand remove netstat overlay script commit 653f0ca3cc17876745f96a5e25fb60faa72b33f3 OS-3798 lxbrand populate /proc/net/snmp commit d72cf7bfa828bceb8c81f81282e9b81712d032e2 OS-3797 lxbrand populate /proc/net/unix commit d0fcb88af333aa48dd2b958f3681f1b597b924cc 4545 _t_create(): Use after free in error code paths commit c62da27859e36f9fdd8cee3c6df3ad567543dcf9 4539 _t_checkfd() should not call find_tilink() if force_sync is set commit a2ca8683ba75b01f3468a17061812db2731decb6 OS-3826 lxbrand ipv4 networking broken after OS-3800 commit 6529d7987e7f46c8a923ae661b04c896f3815d91 OS-3800 lx_thunk core dumps on centos 6.6 commit f4cf1a6a363de08977c8db91c119df49e9f6c296 5186 The door_call(3c) man page contains too much commit 23c88c5ab36a96068ae184ebd20bf625426c3773 5594 nodename(4): Duplicate paragraph in the man page commit 5c644dd8f2c88f1e78ae4866f22c749a3d1b0157 5585 Typo in gethostname(3c): current processor commit 7825e891f35613dcf9e7e6d6848401511f3f96eb 4717 Missing period (.) in man pages commit 270be59d332e9c2003ef54b622a67d6f0e3ef7fc 5263 Missing space in getrbuf(9f) man page commit faf5add516ff7b15d67af766e32716c04c75716d 5528 devid_str_free() should be used for devid_get_minor_name() too commit 4812581794004eff0af2b765b832403b30bf64ab 4996 rtld _init race leads to incorrect symbol values commit 5ae8d2a82dbf2dc1b22ae6755ecefed000d7532e OS-3822 OS-3780 creates a life of fd crime in libproc commit 1f2ca518aeecee8616fccc0c46a339773faea7d5 4863 illumos-gate can't be built with fresh perl versions commit 386e9c9ebfe4116f62e7a0950acd30564fc60125 5566 elfexec is overzealous with vpages 5572 elfexec and mapelfexec can disagree on aux vectors commit 8a986bad744c8a479dfacfcdc16bcad15bbb1ec6 5101 privileges(5) manual page missing some privileges commit 9ef283481583d677cd2cf5449ef49b90eacc97d4 5261 libm should stop using synonyms.h (fix studio build) commit ed1591688000a5d179c4ba27793cae55590c55d2 5590 improper use of NULL in tools/protocmp commit ad0b1ea5d69a45fe23c434277599e315f29a5fca 5589 improper use of NULL in tools/ctf commit 8bf1e4f3b335466afe9b85d761b3822ec8c1a371 OS-3816 sync up mdb_v8 with upstream commit 97a9db610324e7db4393415018e0e737485a94cd 4393 /etc/rpc: 100133 and 100169 should be added commit dc1de1110df1be3c207fa275c52056314a438b95 OS-3806 /proc/self/fd/2 is no longer working in LX commit ebb8db03bc1050fa9dd3b184c99634f4c2eae56c OS-3810 tar doesn't properly wait for its children OS-3813 Clean up unused variables and parenthesis warnings in tar commit 4190e41f9d08bc0e41bed63c0b3641af9cfa1a1d OS-3811 LTP signal_test_05 now fails commit 86851d81a7ab61819497cbc95630c7fc812d00c9 OS-3808 lx_boot_zone_redhat relies on /tmp being cleared on reboot commit d41c05b714ac5cd589b3edd49c55f21d1d8f2589 OS-3802 LTP kill11 test case fails after vsyscall signal changes OS-3803 LTP kill12 test failing OS-3804 LTP signal03 failing OS-3805 LTP waitpid05 failing commit e3e63864a2ed092a7da41db4ea4998f461524a18 OS-3807 lx brand: asynchronous I/O operations can hang commit 91600d919baafe4e4d8bdee4168878036351c556 5578 file(1) should validate Elf_Shdr->sh_name commit 30e6ec63ea67bd88d75811ab11b9c115ff026ab3 OS-3795 lxbrand initial centos 6.6 support commit 9d47dec0481d8cd53b2c1053c96bfa3f78357d6a 5592 NULL pointer dereference in dsl_prop_notify_all_cb() commit 71ceaec61a50dff6050c6905ac8352dd58c89311 OS-3801 update boot copyright date commit 823c8a3d4ff8d31f222cb81ed5b0685e318215e1 OS-3793 lxbrand /proc/pid/maps formatted incorrectly commit da4b59e7b4853d1b5018cd3e37eb592574a673b4 OS-3768 snoop could fail more cleanly on large files commit 643588d2256f94df9beb942b812ffaa83665c09a OS-3799 lxbrand panic when accessing /proc/net/tcp from GZ commit 9a3dc1f68894cc036075fdabc3764446d5d5fa52 OS-3485 lxbrand populate /proc for netstat commit 12e2b6203a3d75549383615f039c435ab4418037 OS-3790 lxbrand vsyscall segfault when SIGSEGV handler set to SIG_DFL commit d5fef2f4802f515505a545dfee6c81b5fd377a96 OS-3792 platform uses obsolete nfs mount command commit bd181d5a0c2b96669dcb4aa44619e0b7dbbedab9 1100 cpustat usage message is incorrect commit 2515f5d4dbff605ba645d47a6851d8d0bac5b994 5527 ::spa_space fails with mdb: couldn't find member dd_phys of type struct zfs`dsl_dir' commit 6e062f4a9c9a27ea6e2e980c1b5f4c41e33aba45 5563 Some traverse() callers do strange things commit bb633f5b0e92fa59f65274f8b5637a7107ca29ec OS-3782 lx brand: vsyscall can induce fatal SIGSEGV commit 4d01dc17bafd21a83dfb4383d30137cf0ab74ed1 OS-3777 zlogin -I needs to work with docker run when in logging mode commit de267ec7980943d6c76defc73d2a3d8356d3acb2 OS-3776 project rctls should be in sync with zone rctls commit b9acd3d9851f7716ce41f37dcd04dd6067a21146 OS-3780 libproc could know about .gnu_debuglink for remote symbol tables commit 10648e3fb261910e63f8354af96444b02d016f44 OS-3773 lxbrand ltp shmctl ipcinfo can fail on a machine with >4GB of memory OS-3779 lxbrand shmctl_ipcinfo struct incorrect for 64-bit commit 181d66828bce1fbd366a3b3a9224593577390463 OS-3778 lxbrand panic when ptracing native process commit 63098359d8842cf81b6fb1b81567e12c671db06f 5511 stat.h(3head) manpage #define typo commit 7eb15eeb0b1a3f960946b7563765e128425fc13b 5568 'allthreads' needs to be global commit 32b5e9f0cda85eef94eb578dd053e155df43fed3 5554 kmdb can't trace stacks that begin within itself
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c5
-rw-r--r--usr/src/cmd/cpc/common/cpustat.c6
-rw-r--r--usr/src/cmd/file/elf_read.c20
-rw-r--r--usr/src/cmd/fs.d/nfs/mount/Makefile14
-rw-r--r--usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c30
-rw-r--r--usr/src/cmd/mdb/common/modules/v8/mdb_v8.c1535
-rw-r--r--usr/src/cmd/mdb/common/modules/v8/v8dbg.h12
-rw-r--r--usr/src/cmd/mdb/common/modules/zfs/zfs.c37
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c39
-rw-r--r--usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c40
-rw-r--r--usr/src/cmd/perl/Makefile.perl8
-rw-r--r--usr/src/cmd/perl/Makefile.targ6
-rw-r--r--usr/src/cmd/ptools/pflags/pflags.c5
-rw-r--r--usr/src/cmd/rpcsvc/net_files/rpc26
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/cmd/sgs/rtld/common/util.c14
-rw-r--r--usr/src/cmd/tar/Makefile2
-rw-r--r--usr/src/cmd/tar/tar.c38
-rw-r--r--usr/src/cmd/zlogin/zlogin.c35
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c49
20 files changed, 1574 insertions, 348 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
index 54fbdc844b..8fbf3fc15f 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
@@ -29,6 +29,7 @@
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/signal.h>
@@ -618,6 +619,10 @@ cap_open_read(const char *name)
if (fstat(capfile_in, &st) < 0)
pr_err("couldn't stat %s: %m", name);
+ if (st.st_size > INT_MAX)
+ pr_err("input file size (%llu bytes) exceeds maximum "
+ "supported size (%d bytes)",
+ (unsigned long long)st.st_size, INT_MAX);
cap_len = st.st_size;
cap_buffp = mmap(0, cap_len, PROT_READ, MAP_PRIVATE, capfile_in, 0);
diff --git a/usr/src/cmd/cpc/common/cpustat.c b/usr/src/cmd/cpc/common/cpustat.c
index 8d405bb625..965fbadfea 100644
--- a/usr/src/cmd/cpc/common/cpustat.c
+++ b/usr/src/cmd/cpc/common/cpustat.c
@@ -251,9 +251,9 @@ main(int argc, char *argv[])
if (errcnt != 0 || opts->dohelp ||
(opts->nsets = cpc_setgrp_numsets(opts->master)) == 0) {
(void) fprintf(opts->dohelp ? stdout : stderr, gettext(
- "Usage:\n\t%s [-c events] [-p period] [-nstD] "
- "[-T d|u] [interval [count]]\n\n"
- "\t-c events specify processor events to be monitored\n"
+ "Usage:\n\t%s -c spec [-c spec]... [-p period] [-T u|d]\n"
+ "\t\t[-sntD] [interval [count]]\n\n"
+ "\t-c spec\t specify processor events to be monitored\n"
"\t-n\t suppress titles\n"
"\t-p period cycle through event list periodically\n"
"\t-s\t run user soaker thread for system-only events\n"
diff --git a/usr/src/cmd/file/elf_read.c b/usr/src/cmd/file/elf_read.c
index 7ccf8e2bb3..03c73f57a9 100644
--- a/usr/src/cmd/file/elf_read.c
+++ b/usr/src/cmd/file/elf_read.c
@@ -419,7 +419,8 @@ process_shdr(Elf_Info *EI)
int i, j, idx;
FILE_ELF_OFF_T cap_off;
FILE_ELF_SIZE_T csize;
- char *section_name;
+ char *strtab;
+ size_t strtab_sz;
Elf_Cap Chdr;
Elf_Shdr *shdr = &EI_Shdr;
@@ -435,16 +436,18 @@ process_shdr(Elf_Info *EI)
if (get_shdr(EI, EI_Ehdr_shstrndx) == ELF_READ_FAIL)
return (ELF_READ_FAIL);
- if ((section_name = malloc(shdr->sh_size)) == NULL)
+ if ((strtab = malloc(shdr->sh_size)) == NULL)
return (ELF_READ_FAIL);
- if (pread64(EI->elffd, section_name, shdr->sh_size, shdr->sh_offset)
+ if (pread64(EI->elffd, strtab, shdr->sh_size, shdr->sh_offset)
!= shdr->sh_size)
return (ELF_READ_FAIL);
+ strtab_sz = shdr->sh_size;
+
/* read all the sections and process them */
for (idx = 1, i = 0; i < EI_Ehdr_shnum; idx++, i++) {
- char *str;
+ char *shnam;
if (get_shdr(EI, i) == ELF_READ_FAIL)
return (ELF_READ_FAIL);
@@ -538,16 +541,19 @@ process_shdr(Elf_Info *EI)
continue;
}
- str = &section_name[shdr->sh_name];
+ if (shdr->sh_name >= strtab_sz)
+ shnam = NULL;
+ else
+ shnam = &strtab[shdr->sh_name];
if (!(EI->stripped & E_DBGINF) &&
((shdr->sh_type == SHT_SUNW_DEBUG) ||
(shdr->sh_type == SHT_SUNW_DEBUGSTR) ||
- (is_in_list(str)))) {
+ (shnam != NULL && is_in_list(shnam)))) {
EI->stripped |= E_DBGINF;
}
}
- free(section_name);
+ free(strtab);
return (ELF_READ_OKAY);
}
diff --git a/usr/src/cmd/fs.d/nfs/mount/Makefile b/usr/src/cmd/fs.d/nfs/mount/Makefile
index dad33922a3..c2485208a8 100644
--- a/usr/src/cmd/fs.d/nfs/mount/Makefile
+++ b/usr/src/cmd/fs.d/nfs/mount/Makefile
@@ -19,18 +19,12 @@
# CDDL HEADER END
#
# Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014, Joyent, Inc. All rights reserved.
#
# cmd/fs.d/nfs/mount/Makefile
FSTYPE= nfs
LIBPROG= mount
-ROOTFS_PROG= $(LIBPROG)
-
-# duplicate ROOTLIBFSTYPE value needed for installation rule
-# we must define this before including Makefile.fstype
-ROOTLIBFSTYPE = $(ROOT)/usr/lib/fs/$(FSTYPE)
-$(ROOTLIBFSTYPE)/%: $(ROOTLIBFSTYPE) %
- $(RM) $@; $(SYMLINK) ../../../../etc/fs/$(FSTYPE)/$(LIBPROG) $@
include ../../Makefile.fstype
@@ -65,7 +59,7 @@ CLOBBERFILES += $(LIBPROG)
.KEEP_STATE:
-all: $(ROOTFS_PROG)
+all: $(LIBPROG)
$(LIBPROG): webnfs.h $(OBJS)
$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
@@ -114,7 +108,9 @@ $(POFILE): $(SRCS)
sed "/^domain/d" messages.po > $@
$(RM) $(POFILE).i messages.po
-install: $(ROOTETCPROG)
+install: all $(FSTYPEPROG)
+ $(RM) $(ROOTETCPROG)
+ $(SYMLINK) ../../../usr/lib/fs/$(FSTYPE)/$(LIBPROG) $(ROOTETCPROG)
lint: webnfs.h webnfs_xdr.c webnfs_client.c lint_SRCS
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
index 83ffae0634..eaa381cc47 100644
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
@@ -688,9 +688,12 @@ static const smb_exp_t smb_session_exp[] =
{ SMB_OPT_REQUEST,
offsetof(smb_session_t, s_req_list.sl_list),
"smbreq", "smb_request"},
- { SMB_OPT_USER | SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
+ { SMB_OPT_USER,
offsetof(smb_session_t, s_user_list.ll_list),
"smbuser", "smb_user"},
+ { SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
+ offsetof(smb_session_t, s_tree_list.ll_list),
+ "smbtree", "smb_tree"},
{ 0, 0, NULL, NULL}
};
@@ -963,17 +966,6 @@ static const char *smb_user_state[SMB_USER_STATE_SENTINEL] =
"LOGGED_OFF"
};
-/*
- * List of objects that can be expanded under a user structure.
- */
-static const smb_exp_t smb_user_exp[] =
-{
- { SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
- offsetof(smb_user_t, u_tree_list.ll_list),
- "smbtree", "smb_tree"},
- { 0, 0, NULL, NULL}
-};
-
static void
smb_dcmd_user_help(void)
{
@@ -983,17 +975,13 @@ smb_dcmd_user_help(void)
mdb_printf("%<b>OPTIONS%</b>\n");
(void) mdb_inc_indent(2);
mdb_printf(
- "-v\tDisplay verbose smb_user information\n"
- "-d\tDisplay the list of smb_odirs attached\n"
- "-f\tDisplay the list of smb_ofiles attached\n"
- "-t\tDisplay the list of smb_trees attached\n");
+ "-v\tDisplay verbose smb_user information\n");
}
static int
smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t opts;
- ulong_t indent = 0;
if (smb_dcmd_getopt(&opts, argc, argv))
return (DCMD_USAGE);
@@ -1009,8 +997,6 @@ smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
smb_user_t *user;
char *account;
- indent = SMB_DCMD_INDENT;
-
user = mdb_alloc(sizeof (*user), UM_SLEEP | UM_GC);
if (mdb_vread(user, sizeof (*user), addr) == -1) {
mdb_warn("failed to read smb_user at %p", addr);
@@ -1058,8 +1044,6 @@ smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
account);
}
}
- if (smb_obj_expand(addr, opts, smb_user_exp, indent))
- return (DCMD_ERR);
return (DCMD_OK);
}
@@ -1217,6 +1201,8 @@ smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
addr);
mdb_printf("State: %d (%s)\n", od->d_state, state);
mdb_printf("SID: %u\n", od->d_odid);
+ mdb_printf("User: %p\n", od->d_user);
+ mdb_printf("Tree: %p\n", od->d_tree);
mdb_printf("Reference Count: %d\n", od->d_refcnt);
mdb_printf("Pattern: %s\n", od->d_pattern);
mdb_printf("SMB Node: %p\n\n", od->d_dnode);
@@ -1292,6 +1278,8 @@ smb_dcmd_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
((of->f_flags & SMB_OFLAGS_LLF_POS_VALID) ?
"Valid" : "Invalid"));
mdb_printf("Flags: 0x%08x\n", of->f_flags);
+ mdb_printf("User: %p\n", of->f_user);
+ mdb_printf("Tree: %p\n", of->f_tree);
mdb_printf("Credential: %p\n\n", of->f_cr);
} else {
if (DCMD_HDRSPEC(flags))
diff --git a/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c b/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c
index aa597e7a01..6609097742 100644
--- a/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c
+++ b/usr/src/cmd/mdb/common/modules/v8/mdb_v8.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
*/
/*
@@ -50,6 +50,7 @@
#include <sys/mdb_modapi.h>
#include <assert.h>
#include <ctype.h>
+#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@@ -148,10 +149,11 @@ static intptr_t V8_DICT_SHIFT;
static intptr_t V8_DICT_PREFIX_SIZE;
static intptr_t V8_DICT_ENTRY_SIZE;
static intptr_t V8_DICT_START_INDEX;
+static intptr_t V8_FIELDINDEX_MASK;
+static intptr_t V8_FIELDINDEX_SHIFT;
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;
static intptr_t V8_PROP_DESC_KEY;
static intptr_t V8_PROP_DESC_DETAILS;
@@ -161,6 +163,7 @@ static intptr_t V8_TRANSITIONS_IDX_DESC;
static intptr_t V8_TYPE_JSOBJECT = -1;
static intptr_t V8_TYPE_JSARRAY = -1;
+static intptr_t V8_TYPE_JSFUNCTION = -1;
static intptr_t V8_TYPE_FIXEDARRAY = -1;
static intptr_t V8_ELEMENTS_KIND_SHIFT;
@@ -214,10 +217,12 @@ static ssize_t V8_OFF_SLICEDSTRING_PARENT;
static ssize_t V8_OFF_SLICEDSTRING_OFFSET;
static ssize_t V8_OFF_STRING_LENGTH;
-#define NODE_OFF_EXTSTR_DATA 0x4 /* see node_string.h */
+/* see node_string.h */
+#define NODE_OFF_EXTSTR_DATA sizeof (uintptr_t)
#define V8_CONSTANT_OPTIONAL 1
#define V8_CONSTANT_HASFALLBACK 2
+#define V8_CONSTANT_REMOVED 4
#define V8_CONSTANT_MAJORSHIFT 3
#define V8_CONSTANT_MAJORMASK ((1 << 4) - 1)
@@ -233,6 +238,10 @@ static ssize_t V8_OFF_STRING_LENGTH;
(V8_CONSTANT_OPTIONAL | V8_CONSTANT_HASFALLBACK | \
((maj) << V8_CONSTANT_MAJORSHIFT) | ((min) << V8_CONSTANT_MINORSHIFT))
+#define V8_CONSTANT_REMOVED_SINCE(maj, min) \
+ (V8_CONSTANT_REMOVED | \
+ ((maj) << V8_CONSTANT_MAJORSHIFT) | ((min) << V8_CONSTANT_MINORSHIFT))
+
/*
* Table of constants used directly by this file.
*/
@@ -262,8 +271,10 @@ static v8_constant_t v8_constants[] = {
{ &V8_SlicedStringTag, "v8dbg_SlicedStringTag",
V8_CONSTANT_FALLBACK(0, 0), 0x3 },
{ &V8_ExternalStringTag, "v8dbg_ExternalStringTag" },
- { &V8_FailureTag, "v8dbg_FailureTag" },
- { &V8_FailureTagMask, "v8dbg_FailureTagMask" },
+ { &V8_FailureTag, "v8dbg_FailureTag",
+ V8_CONSTANT_REMOVED_SINCE(3, 28) },
+ { &V8_FailureTagMask, "v8dbg_FailureTagMask",
+ V8_CONSTANT_REMOVED_SINCE(3, 28) },
{ &V8_HeapObjectTag, "v8dbg_HeapObjectTag" },
{ &V8_HeapObjectTagMask, "v8dbg_HeapObjectTagMask" },
{ &V8_SmiTag, "v8dbg_SmiTag" },
@@ -277,7 +288,7 @@ static v8_constant_t v8_constants[] = {
#endif
{ &V8_PointerSizeLog2, "v8dbg_PointerSizeLog2" },
- { &V8_DICT_SHIFT, "v8dbg_dict_shift",
+ { &V8_DICT_SHIFT, "v8dbg_bit_field3_dictionary_map_shift",
V8_CONSTANT_FALLBACK(3, 13), 24 },
{ &V8_DICT_PREFIX_SIZE, "v8dbg_dict_prefix_size",
V8_CONSTANT_FALLBACK(3, 11), 2 },
@@ -285,11 +296,14 @@ static v8_constant_t v8_constants[] = {
V8_CONSTANT_FALLBACK(3, 11), 3 },
{ &V8_DICT_START_INDEX, "v8dbg_dict_start_index",
V8_CONSTANT_FALLBACK(3, 11), 3 },
+ { &V8_FIELDINDEX_MASK, "v8dbg_fieldindex_mask",
+ V8_CONSTANT_FALLBACK(3, 26), 0x3ff00000 },
+ { &V8_FIELDINDEX_SHIFT, "v8dbg_fieldindex_shift",
+ V8_CONSTANT_FALLBACK(3, 26), 20 },
{ &V8_ISSHARED_SHIFT, "v8dbg_isshared_shift",
V8_CONSTANT_FALLBACK(3, 11), 0 },
{ &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" },
{ &V8_PROP_IDX_CONTENT, "v8dbg_prop_idx_content",
V8_CONSTANT_OPTIONAL },
@@ -430,6 +444,66 @@ static void conf_class_compute_offsets(v8_class_t *);
static int read_typebyte(uint8_t *, uintptr_t);
static int heap_offset(const char *, const char *, ssize_t *);
+static int jsfunc_name(uintptr_t, char **, size_t *);
+
+/*
+ * When iterating properties, it's useful to keep track of what kinds of
+ * properties were found. This is useful for developers to identify objects of
+ * different kinds in order to debug them.
+ */
+typedef enum {
+ JPI_NONE = 0,
+
+ /*
+ * Indicates how properties are stored in this object. There can be
+ * both numeric properties and some of the other kinds.
+ */
+ JPI_NUMERIC = 0x01, /* numeric-named properties in "elements" */
+ JPI_DICT = 0x02, /* dictionary properties */
+ JPI_INOBJECT = 0x04, /* properties stored inside object */
+ JPI_PROPS = 0x08, /* "properties" array */
+
+ /* error-like cases */
+ JPI_SKIPPED = 0x10, /* some properties were skipped */
+ JPI_BADLAYOUT = 0x20, /* we didn't recognize the layout at all */
+
+ /* fallback cases */
+ JPI_HASTRANSITIONS = 0x100, /* found a transitions array */
+ JPI_HASCONTENT = 0x200, /* found a separate content array */
+} jspropinfo_t;
+
+typedef struct jsobj_print {
+ char **jsop_bufp;
+ size_t *jsop_lenp;
+ int jsop_indent;
+ uint64_t jsop_depth;
+ boolean_t jsop_printaddr;
+ uintptr_t jsop_baseaddr;
+ int jsop_nprops;
+ const char *jsop_member;
+ boolean_t jsop_found;
+ boolean_t jsop_descended;
+ jspropinfo_t jsop_propinfo;
+} jsobj_print_t;
+
+static int jsobj_print_number(uintptr_t, jsobj_print_t *);
+static int jsobj_print_oddball(uintptr_t, jsobj_print_t *);
+static int jsobj_print_jsobject(uintptr_t, jsobj_print_t *);
+static int jsobj_print_jsarray(uintptr_t, jsobj_print_t *);
+static int jsobj_print_jsfunction(uintptr_t, jsobj_print_t *);
+static int jsobj_print_jsdate(uintptr_t, jsobj_print_t *);
+
+/*
+ * Returns 1 if the V8 version v8_major.v8.minor is strictly older than
+ * the V8 version represented by "flags".
+ * Returns 0 otherwise.
+ */
+static int
+v8_version_older(uintptr_t v8_major, uintptr_t v8_minor, uint32_t flags) {
+ return (v8_major < V8_CONSTANT_MAJOR(flags) ||
+ (v8_major == V8_CONSTANT_MAJOR(flags) &&
+ v8_minor < V8_CONSTANT_MINOR(flags)));
+}
/*
* Invoked when this dmod is initially loaded to load the set of classes, enums,
@@ -477,7 +551,9 @@ autoconfigure(v8_cfg_t *cfgp)
continue;
}
- if (!(cnp->v8c_flags & V8_CONSTANT_OPTIONAL)) {
+ if (!(cnp->v8c_flags & V8_CONSTANT_OPTIONAL) &&
+ (!(cnp->v8c_flags & V8_CONSTANT_REMOVED) ||
+ v8_version_older(v8_major, v8_minor, cnp->v8c_flags))) {
mdb_warn("failed to read \"%s\"", cnp->v8c_symbol);
failed++;
continue;
@@ -508,6 +584,9 @@ autoconfigure(v8_cfg_t *cfgp)
if (strcmp(ep->v8e_name, "JSArray") == 0)
V8_TYPE_JSARRAY = ep->v8e_value;
+ if (strcmp(ep->v8e_name, "JSFunction") == 0)
+ V8_TYPE_JSFUNCTION = ep->v8e_value;
+
if (strcmp(ep->v8e_name, "FixedArray") == 0)
V8_TYPE_FIXEDARRAY = ep->v8e_value;
}
@@ -522,6 +601,11 @@ autoconfigure(v8_cfg_t *cfgp)
failed++;
}
+ if (V8_TYPE_JSFUNCTION == -1) {
+ mdb_warn("couldn't find JSFunction type\n");
+ failed++;
+ }
+
if (V8_TYPE_FIXEDARRAY == -1) {
mdb_warn("couldn't find FixedArray type\n");
failed++;
@@ -963,11 +1047,8 @@ v8_warn(const char *format, ...)
}
}
-/*
- * 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)
+static v8_field_t *
+conf_field_lookup(const char *klass, const char *field)
{
v8_class_t *clp;
v8_field_t *flp;
@@ -978,13 +1059,26 @@ heap_offset(const char *klass, const char *field, ssize_t *offp)
}
if (clp == NULL)
- return (-1);
+ return (NULL);
for (flp = clp->v8c_fields; flp != NULL; flp = flp->v8f_next) {
if (strcmp(field, flp->v8f_name) == 0)
break;
}
+ return (flp);
+}
+
+/*
+ * 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)
+{
+ v8_field_t *flp;
+
+ flp = conf_field_lookup(klass, field);
+
if (flp == NULL)
return (-1);
@@ -1094,6 +1188,46 @@ read_heap_byte(uint8_t *valp, uintptr_t addr, ssize_t off)
}
/*
+ * This is truly horrific. Inside the V8 Script class are a number of
+ * small-integer fields like the function_token_position (an offset into the
+ * script's text where the "function" token appears). For 32-bit processes, V8
+ * stores these as a sequence of SMI fields, which we know how to interpret well
+ * enough. For 64-bit processes, "to avoid wasting space", they use a different
+ * trick: each 8-byte word contains two integer fields. The low word is
+ * represented like an SMI: shifted left by one. They don't bother shifting the
+ * high word, since its low bit will never be looked at (since it's not
+ * word-aligned).
+ *
+ * This function is used for cases where we would use read_heap_smi(), except
+ * that this is one of those fields that might be encoded or might not be,
+ * depending on whether the address is word-aligned.
+ */
+static int
+read_heap_maybesmi(uintptr_t *valp, uintptr_t addr, ssize_t off)
+{
+#ifdef _LP64
+ uint32_t readval;
+
+ if (mdb_vread(&readval, sizeof (readval), addr + off) == -1) {
+ *valp = -1;
+ v8_warn("failed to read offset %d from %p", off, addr);
+ return (-1);
+ }
+
+ /*
+ * If this was the low half-word, it needs to be shifted right.
+ */
+ if ((addr + off) % sizeof (uintptr_t) == 0)
+ readval >>= 1;
+
+ *valp = (uintptr_t)readval;
+ return (0);
+#else
+ return (read_heap_smi(valp, addr, off));
+#endif
+}
+
+/*
* 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.
@@ -1181,8 +1315,7 @@ read_heap_dict(uintptr_t addr,
if (V8_IS_SMI(dict[i])) {
intptr_t val = V8_SMI_VALUE(dict[i]);
-
- (void) snprintf(buf, sizeof (buf), "%ld", val);
+ (void) snprintf(buf, sizeof (buf), "%" PRIdPTR, val);
} else {
if (jsobj_is_hole(dict[i])) {
/*
@@ -1217,13 +1350,69 @@ out:
}
/*
+ * Given an object, returns in "buf" the name of the constructor function. With
+ * "verbose", prints the pointer to the JSFunction object. Given anything else,
+ * returns an error (and warns the user why).
+ */
+static int
+obj_jsconstructor(uintptr_t addr, char **bufp, size_t *lenp, boolean_t verbose)
+{
+ uint8_t type;
+ uintptr_t map, consfunc, funcinfop;
+ const char *constype;
+
+ if (!V8_IS_HEAPOBJECT(addr) ||
+ read_typebyte(&type, addr) != 0 ||
+ (type != V8_TYPE_JSOBJECT && type != V8_TYPE_JSARRAY)) {
+ mdb_warn("%p is not a JSObject\n", addr);
+ return (-1);
+ }
+
+ if (mdb_vread(&map, sizeof (map), addr + V8_OFF_HEAPOBJECT_MAP) == -1 ||
+ mdb_vread(&consfunc, sizeof (consfunc),
+ map + V8_OFF_MAP_CONSTRUCTOR) == -1) {
+ mdb_warn("unable to read object map\n");
+ return (-1);
+ }
+
+ if (read_typebyte(&type, consfunc) != 0)
+ return (-1);
+
+ constype = enum_lookup_str(v8_types, type, "");
+ if (strcmp(constype, "Oddball") == 0) {
+ jsobj_print_t jsop;
+ bzero(&jsop, sizeof (jsop));
+ jsop.jsop_bufp = bufp;
+ jsop.jsop_lenp = lenp;
+ return (jsobj_print_oddball(consfunc, &jsop));
+ }
+
+ if (strcmp(constype, "JSFunction") != 0) {
+ mdb_warn("constructor: expected JSFunction, found %s\n",
+ constype);
+ return (-1);
+ }
+
+ if (read_heap_ptr(&funcinfop, consfunc, V8_OFF_JSFUNCTION_SHARED) != 0)
+ return (-1);
+
+ if (jsfunc_name(funcinfop, bufp, lenp) != 0)
+ return (-1);
+
+ if (verbose)
+ bsnprintf(bufp, lenp, " (JSFunction: %p)", consfunc);
+
+ 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;
+ uintptr_t strptr, map, consfunc, funcinfop;
const char *typename;
if (V8_IS_FAILURE(addr)) {
@@ -1259,10 +1448,75 @@ obj_jstype(uintptr_t addr, char **bufp, size_t *lenp, uint8_t *typep)
}
}
+ if (strcmp(typename, "JSObject") == 0 &&
+ mdb_vread(&map, sizeof (map), addr + V8_OFF_HEAPOBJECT_MAP) != -1 &&
+ mdb_vread(&consfunc, sizeof (consfunc),
+ map + V8_OFF_MAP_CONSTRUCTOR) != -1 &&
+ read_typebyte(&typebyte, consfunc) == 0 &&
+ strcmp(enum_lookup_str(v8_types, typebyte, ""),
+ "JSFunction") == 0 &&
+ mdb_vread(&funcinfop, sizeof (funcinfop),
+ consfunc + V8_OFF_JSFUNCTION_SHARED) != -1) {
+ (void) bsnprintf(bufp, lenp, ": ");
+ (void) jsfunc_name(funcinfop, bufp, lenp);
+ }
+
return (0);
}
/*
+ * V8 allows implementers (like Node) to store pointer-sized values into
+ * internal fields within V8 heap objects. Implementors access these values by
+ * 0-based index (e.g., SetInternalField(0, value)). These values are stored as
+ * an array directly after the last actual C++ field in the C++ object.
+ *
+ * Node uses internal fields to refer to handles. For example, a socket's C++
+ * HandleWrap object is typically stored as internal field 0 in the JavaScript
+ * Socket object. Similarly, the native-heap-allocated chunk of memory
+ * associated with a Node Buffer is referenced by field 0 in the External array
+ * pointed-to by the Node Buffer JSObject.
+ */
+static int
+obj_v8internal(uintptr_t addr, uint_t idx, uintptr_t *valp)
+{
+ char *bufp;
+ size_t len;
+ ssize_t off;
+ uint8_t type;
+
+ v8_class_t *clp;
+ char buf[256];
+
+ bufp = buf;
+ len = sizeof (buf);
+ if (obj_jstype(addr, &bufp, &len, &type) != 0)
+ return (DCMD_ERR);
+
+ if (type == 0) {
+ mdb_warn("%p: unsupported type\n", addr);
+ return (DCMD_ERR);
+ }
+
+ for (clp = v8_classes; clp != NULL; clp = clp->v8c_next) {
+ if (strcmp(buf, clp->v8c_name) == 0)
+ break;
+ }
+
+ if (clp == NULL) {
+ mdb_warn("%p: didn't find expected class\n", addr);
+ return (DCMD_ERR);
+ }
+
+ off = clp->v8c_end + (idx * sizeof (uintptr_t)) - 1;
+ if (read_heap_ptr(valp, addr, off) != 0) {
+ mdb_warn("%p: failed to read from %p\n", addr, addr + off);
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
+/*
* Print out the fields of the given object that come from the given class.
*/
static int
@@ -1456,11 +1710,6 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
char *buf;
uint16_t chrval;
- if ((blen = MIN(*lenp, 256 * 1024)) == 0)
- return (0);
-
- buf = alloca(blen);
-
if (read_heap_smi(&nstrchrs, addr, V8_OFF_STRING_LENGTH) != 0) {
(void) bsnprintf(bufp, lenp,
"<string (failed to read length)>");
@@ -1470,17 +1719,22 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
if (slicelen != -1)
nstrchrs = slicelen;
+ blen = ((flags & JSSTR_ISASCII) != 0) ? *lenp : 2 * (*lenp);
+ if ((blen = MIN(blen, 256 * 1024)) == 0)
+ return (0);
+
if ((flags & JSSTR_ISASCII) != 0) {
nstrbytes = nstrchrs;
nreadoffset = sliceoffset;
+ nreadbytes = nstrbytes + sizeof ("\"\"") <= *lenp ?
+ nstrbytes : *lenp - sizeof ("\"\"[...]");
} else {
nstrbytes = 2 * nstrchrs;
nreadoffset = 2 * sliceoffset;
+ nreadbytes = nstrchrs + sizeof ("\"\"") <= *lenp ?
+ nstrbytes : 2 * (*lenp - sizeof ("\"\"[...]"));
}
- nreadbytes = nstrbytes + sizeof ("\"\"") <= blen ? nstrbytes :
- blen - sizeof ("\"\"[...]");
-
if (nreadbytes < 0) {
/*
* We don't even have the room to store the ellipsis; zero
@@ -1491,10 +1745,13 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
return (0);
}
- if (verbose)
+ if (verbose) {
mdb_printf("length: %d chars (%d bytes), "
"will read %d bytes from offset %d\n",
nstrchrs, nstrbytes, nreadbytes, nreadoffset);
+ mdb_printf("given buffer size: %d, internal buffer: %d\n",
+ *lenp, blen);
+ }
if (nstrbytes == 0) {
(void) bsnprintf(bufp, lenp, "%s%s",
@@ -1502,6 +1759,7 @@ jsstr_print_seq(uintptr_t addr, uint_t flags, char **bufp, size_t *lenp,
return (0);
}
+ buf = alloca(blen);
buf[0] = '\0';
if ((flags & JSSTR_ISASCII) != 0) {
@@ -1742,9 +2000,126 @@ jsobj_is_hole(uintptr_t addr)
return (jsobj_is_oddball(addr, "hole"));
}
+/*
+ * Iterate the properties of a JavaScript object "addr".
+ *
+ * Every heap object refers to a Map that describes how that heap object is laid
+ * out. The Map includes information like the constructor function used to
+ * create the object, how many bytes each object uses, and how many properties
+ * are stored inside the object. (A single Map object can be shared by many
+ * objects of the same general type, which is why this information is encoded by
+ * reference rather than contained in each object.)
+ *
+ * V8 knows about lots of different kinds of properties:
+ *
+ * o properties with numeric names (e.g., array elements)
+ * o dictionary properties
+ * o "fast" properties stored inside each object, much like a C struct
+ * o properties stored in the separate "properties" array
+ * o getters, setters, and other magic (not supported by this module)
+ *
+ * While property lookup in JavaScript involves traversing an object's prototype
+ * chain, this module only iterates the properties local to the object itself.
+ *
+ *
+ * Numeric properties
+ *
+ * Properties having numeric indexes are stored in the "elements" array attached
+ * to each object. Objects with numeric properties can also have other
+ * properties.
+ *
+ *
+ * Dictionary properties
+ *
+ * An object with dictionary properties is identified by one of the bits in
+ * "bitfield3" in the object's Map. For details on slow properties, see
+ * read_heap_dict().
+ *
+ *
+ * Other properties
+ *
+ * The Map object refers to an array of "instance descriptors". This array has
+ * a few metadata entries at the front, followed by groups of three entries for
+ * each property. In Node v0.10 and later, it looks roughly like this:
+ *
+ * +--------------+ +----------------------+
+ * | JSObject | +--> | Map |
+ * +--------------| | +----------------------+
+ * | map | ---+ | ... |
+ * | ... | | instance_descriptors | --+
+ * in-object | [prop 0 val] | | ... | |
+ * properties | [prop 1 val] | +----------------------+ |
+ * (not for all | ... | |
+ * objects) | [prop N val] | |
+ * +--------------+ |
+ * +------------------------------------------------+
+ * |
+ * +----> +------------------------------+
+ * | FixedArray |
+ * +------------------------------+
+ * | ... |
+ * | prop 0 "key" descriptor |
+ * | prop 0 "details" descriptor |
+ * | prop 0 "value" descriptor |
+ * | prop 1 "key" descriptor |
+ * | prop 1 "details" descriptor |
+ * | prop 1 "value" descriptor |
+ * | ... |
+ * | prop N "key" descriptor |
+ * | prop N "details" descriptor |
+ * | prop N "value" descriptor |
+ * +------------------------------+
+ *
+ * In versions of Node prior to 0.10, there's an extra level of indirection.
+ * The Map refers to a "transitions" array, which has an entry that points to
+ * the instance descriptors. In both cases, the descriptors look roughly the
+ * same.
+ *
+ * Each property is described by three pointer-sized entries:
+ *
+ * o key: a string denoting the name of the property
+ * o details: a bitfield describing attributes of this property
+ * o value: an integer describing where this property's value is stored
+ *
+ * "key" is straightforward: it's just the name of the property as the
+ * JavaScript programmer knows it.
+ *
+ * In versions prior to Node 0.12, "value" is an integer. If "value" is less
+ * than the number of properties stored inside the object (which is also
+ * recorded in the Map), then it denotes which of the in-object property value
+ * slots (shown above inside the JSObject object) stores the value for this
+ * property. If "value" is greater than the number of properties stored inside
+ * the object, then it denotes which index into the separate "properties" array
+ * (a separate field in the JSObject, not shown above) contains the value for
+ * this property.
+ *
+ * In Node 0.12, for properties that are stored inside the object, the offset is
+ * obtained not using "value", but using a bitfield from the "details" part of
+ * the descriptor.
+ *
+ * Terminology notes: it's important to keep straight the different senses of
+ * "object" and "property" here. We use "JavaScript objects" to refer to the
+ * things that JavaScript programmers would call objects, including instances of
+ * Object and Array and subclasses of those. These are a subset of V8 heap
+ * objects, since V8 uses its heap to manage lots of other objects that
+ * JavaScript programmers don't think about. This function iterates JavaScript
+ * properties of these JavaScript objects, not internal properties of heap
+ * objects in general.
+ *
+ * Relatedly, while JavaScript programmers frequently interchange the notions of
+ * property names, property values, and property configurations (e.g., getters
+ * and setters, read-only or not, hidden or not), these are all distinct in the
+ * implementation of the VM, and "property" typically refers to the whole
+ * configuration, which may include a way to get the property name and value.
+ *
+ * The canonical source of the information used here is the implementation of
+ * property lookup in the V8 source code, currently in Object::GetProperty.
+ */
+
static int
jsobj_properties(uintptr_t addr,
- int (*func)(const char *, uintptr_t, void *), void *arg)
+ int (*func)(const char *, uintptr_t, void *), void *arg,
+ jspropinfo_t *propinfop)
{
uintptr_t ptr, map, elements;
uintptr_t *props = NULL, *descs = NULL, *content = NULL, *trans, *elts;
@@ -1754,10 +2129,12 @@ jsobj_properties(uintptr_t addr,
int rval = -1;
size_t ps = sizeof (uintptr_t);
ssize_t off;
+ jspropinfo_t propinfo = JPI_NONE;
/*
- * Objects have either "fast" properties represented with a FixedArray
- * or slow properties represented with a Dictionary.
+ * First, check if the JSObject's "properties" field is a FixedArray.
+ * If not, then this is something we don't know how to deal with, and
+ * we'll just pass the caller a NULL value.
*/
if (mdb_vread(&ptr, ps, addr + V8_OFF_JSOBJECT_PROPERTIES) == -1)
return (-1);
@@ -1766,30 +2143,26 @@ jsobj_properties(uintptr_t addr,
return (-1);
if (type != V8_TYPE_FIXEDARRAY) {
- /*
- * If our properties aren't a fixed array, we'll emit a member
- * that contains the type name, but with a NULL value.
- */
char buf[256];
-
(void) mdb_snprintf(buf, sizeof (buf), "<%s>",
enum_lookup_str(v8_types, type, "unknown"));
-
+ if (propinfop != NULL)
+ *propinfop = JPI_BADLAYOUT;
return (func(buf, NULL, arg));
}
/*
- * To iterate the properties, we need to examine the instance
- * descriptors of the associated Map object. Depending on the version
- * of V8, this might be found directly from the map -- or indirectly
- * via the transitions array.
+ * As described above, we need the Map to figure out how to iterate the
+ * properties for this object.
*/
if (mdb_vread(&map, ps, addr + V8_OFF_HEAPOBJECT_MAP) == -1)
goto err;
/*
* Check to see if our elements member is an array and non-zero; if
- * so, it contains numerically-named properties.
+ * so, it contains numerically-named properties. Whether or not there
+ * are any numerically-named properties, there may be other kinds of
+ * properties.
*/
if (V8_ELEMENTS_KIND_SHIFT != -1 &&
read_heap_ptr(&elements, addr, V8_OFF_JSOBJECT_ELEMENTS) == 0 &&
@@ -1805,6 +2178,7 @@ jsobj_properties(uintptr_t addr,
kind = bit_field2 >> V8_ELEMENTS_KIND_SHIFT;
kind &= (1 << V8_ELEMENTS_KIND_BITCOUNT) - 1;
+ propinfo |= JPI_NUMERIC;
if (kind == V8_ELEMENTS_FAST_ELEMENTS ||
kind == V8_ELEMENTS_FAST_HOLEY_ELEMENTS) {
@@ -1815,7 +2189,7 @@ jsobj_properties(uintptr_t addr,
jsobj_is_hole(elts[ii]))
continue;
- snprintf(name, sizeof (name), "%d", ii);
+ snprintf(name, sizeof (name), "%" PRIdPTR, ii);
if (func(name, elts[ii], arg) != 0) {
mdb_free(elts, sz);
@@ -1823,6 +2197,7 @@ jsobj_properties(uintptr_t addr,
}
}
} else if (kind == V8_ELEMENTS_DICTIONARY_ELEMENTS) {
+ propinfo |= JPI_DICT;
if (read_heap_dict(elements, func, arg) != 0) {
mdb_free(elts, sz);
goto err;
@@ -1833,14 +2208,49 @@ jsobj_properties(uintptr_t addr,
}
if (V8_DICT_SHIFT != -1) {
+ v8_field_t *flp;
uintptr_t bit_field3;
- if (mdb_vread(&bit_field3, sizeof (bit_field3),
- map + V8_OFF_MAP_BIT_FIELD3) == -1)
- goto err;
+ /*
+ * If dictionary properties are supported (the V8_DICT_SHIFT
+ * offset is not -1), then bitfield 3 tells us if the properties
+ * for this object are stored in "properties" field of the
+ * object using a Dictionary representation.
+ *
+ * Versions of V8 prior to Node 0.12 treated bit_field3 as an
+ * SMI, so it was pointer-sized, and it has to be converted from
+ * an SMI before using it. In 0.12, it's treated as a raw
+ * uint32_t, meaning it's always int-sized and it should not be
+ * converted. We can tell which case we're in because the debug
+ * constant (v8dbg_class_map__bit_field3__TYPE) tells us whether
+ * the TYPE is "SMI" or "int".
+ */
- if (V8_SMI_VALUE(bit_field3) & (1 << V8_DICT_SHIFT))
+ flp = conf_field_lookup("Map", "bit_field3");
+ if (flp == NULL || flp->v8f_isbyte) {
+ /*
+ * v8f_isbyte indicates the type is "int", so we're in
+ * the int-sized not-a-SMI world.
+ */
+ unsigned int bf3_value;
+ if (mdb_vread(&bf3_value, sizeof (bf3_value),
+ map + V8_OFF_MAP_BIT_FIELD3) == -1)
+ goto err;
+ bit_field3 = (uintptr_t)bf3_value;
+ } else {
+ /* The metadata indicates this is an SMI. */
+ if (mdb_vread(&bit_field3, sizeof (bit_field3),
+ map + V8_OFF_MAP_BIT_FIELD3) == -1)
+ goto err;
+ bit_field3 = V8_SMI_VALUE(bit_field3);
+ }
+
+ if (bit_field3 & (1 << V8_DICT_SHIFT)) {
+ propinfo |= JPI_DICT;
+ if (propinfop != NULL)
+ *propinfop = propinfo;
return (read_heap_dict(ptr, func, arg));
+ }
} else if (V8_OFF_MAP_INSTANCE_DESCRIPTORS != -1) {
uintptr_t bit_field3;
@@ -1860,6 +2270,9 @@ jsobj_properties(uintptr_t addr,
* dictionary -- an assumption that is assuredly in
* error in some cases.
*/
+ propinfo |= JPI_DICT;
+ if (propinfop != NULL)
+ *propinfop = propinfo;
return (read_heap_dict(ptr, func, arg));
}
}
@@ -1867,7 +2280,12 @@ jsobj_properties(uintptr_t addr,
if (read_heap_array(ptr, &props, &nprops, UM_SLEEP) != 0)
goto err;
- if ((off = V8_OFF_MAP_INSTANCE_DESCRIPTORS) == -1) {
+ /*
+ * Check if we're looking at an older version of V8, where the instance
+ * descriptors are stored not directly in the Map, but in the
+ * "transitions" array that's stored in the Map.
+ */
+ if (V8_OFF_MAP_INSTANCE_DESCRIPTORS == -1) {
if (V8_OFF_MAP_TRANSITIONS == -1 ||
V8_TRANSITIONS_IDX_DESC == -1 ||
V8_PROP_IDX_CONTENT != -1) {
@@ -1877,47 +2295,71 @@ jsobj_properties(uintptr_t addr,
goto err;
}
+ propinfo |= JPI_HASTRANSITIONS;
off = V8_OFF_MAP_TRANSITIONS;
- }
-
- if (mdb_vread(&ptr, ps, map + off) == -1)
- goto err;
+ if (mdb_vread(&ptr, ps, map + off) == -1)
+ goto err;
- if (V8_OFF_MAP_INSTANCE_DESCRIPTORS == -1) {
if (read_heap_array(ptr, &trans, &ntrans, UM_SLEEP) != 0)
goto err;
ptr = trans[V8_TRANSITIONS_IDX_DESC];
mdb_free(trans, ntrans * sizeof (uintptr_t));
+ } else {
+ off = V8_OFF_MAP_INSTANCE_DESCRIPTORS;
+ if (mdb_vread(&ptr, ps, map + off) == -1)
+ goto err;
}
+ /*
+ * Either way, at this point "ptr" should refer to the descriptors
+ * array.
+ */
if (read_heap_array(ptr, &descs, &ndescs, UM_SLEEP) != 0)
goto err;
+ /*
+ * For cases where property values are stored directly inside the object
+ * ("fast properties"), we need to know the whole size of the object and
+ * the number of properties in the object in order to calculate the
+ * correct offset for each property.
+ */
if (read_size(&size, addr) != 0)
size = 0;
-
- if (mdb_vread(&ninprops, 1, map + V8_OFF_MAP_INOBJECT_PROPERTIES) == -1)
- goto err;
-
- if (V8_PROP_IDX_CONTENT != -1 && V8_PROP_IDX_CONTENT < ndescs &&
- read_heap_array(descs[V8_PROP_IDX_CONTENT], &content,
- &ncontent, UM_SLEEP) != 0)
+ if (mdb_vread(&ninprops, ps,
+ map + V8_OFF_MAP_INOBJECT_PROPERTIES) == -1)
goto err;
if (V8_PROP_IDX_CONTENT == -1) {
/*
- * On node v0.8 and later, the content is not stored in an
- * orthogonal FixedArray, but rather with the descriptors.
+ * On node v0.8 and later, the content is not stored in a
+ * separate FixedArray, but rather with the descriptors. The
+ * number of actual properties is the length of the array minus
+ * the first (non-property) elements divided by the number of
+ * elements per property.
*/
content = descs;
ncontent = ndescs;
rndescs = ndescs > V8_PROP_IDX_FIRST ?
(ndescs - V8_PROP_IDX_FIRST) / V8_PROP_DESC_SIZE : 0;
} else {
+ /*
+ * On older versions, the content is stored in a separate array,
+ * and there's one entry per property (rather than three).
+ */
+ if (V8_PROP_IDX_CONTENT < ndescs &&
+ read_heap_array(descs[V8_PROP_IDX_CONTENT], &content,
+ &ncontent, UM_SLEEP) != 0)
+ goto err;
+
rndescs = ndescs - V8_PROP_IDX_FIRST;
+ propinfo |= JPI_HASCONTENT;
}
+ /*
+ * At this point, we've read all the pieces we need to process the list
+ * of instance descriptors.
+ */
for (ii = 0; ii < rndescs; ii++) {
uintptr_t keyidx, validx, detidx, baseidx;
char buf[1024];
@@ -1941,48 +2383,91 @@ jsobj_properties(uintptr_t addr,
detidx = baseidx + V8_PROP_DESC_DETAILS;
}
+ /*
+ * Ignore cases where our understanding doesn't appear to match
+ * what's here.
+ */
if (detidx >= ncontent) {
+ propinfo |= JPI_SKIPPED;
v8_warn("property descriptor %d: detidx (%d) "
"out of bounds for content array (length %d)\n",
ii, detidx, ncontent);
continue;
}
+ /*
+ * We only process fields. There are other entries here
+ * (notably: transitions) that we don't care about (and these
+ * are not errors).
+ */
if (!V8_DESC_ISFIELD(content[detidx]))
continue;
if (keyidx >= ndescs) {
+ propinfo |= JPI_SKIPPED;
v8_warn("property descriptor %d: keyidx (%d) "
"out of bounds for descriptor array (length %d)\n",
ii, keyidx, ndescs);
continue;
}
- if (jsstr_print(descs[keyidx], JSSTR_NUDE, &c, &len) != 0)
+ if (jsstr_print(descs[keyidx], JSSTR_NUDE, &c, &len) != 0) {
+ propinfo |= JPI_SKIPPED;
continue;
+ }
val = (intptr_t)content[validx];
-
if (!V8_IS_SMI(val)) {
+ propinfo |= JPI_SKIPPED;
v8_warn("object %p: property descriptor %d: value "
- "index value is not an SMI: %p\n", addr, ii, val);
+ "index is not an SMI: %p\n", addr, ii, val);
continue;
}
+ /*
+ * The "value" part of each property descriptor tells us whether
+ * the property value is stored directly in the object or in the
+ * related "props" array. See JSObject::RawFastPropertyAt() in
+ * the V8 source.
+ */
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) {
+ uintptr_t propaddr;
+
+ /*
+ * The property is stored directly inside the object.
+ * In Node 0.10, "val - ninprops" is the (negative)
+ * index of the property counted from the end of the
+ * object. In that context, -1 refers to the last
+ * word in the object; -2 refers to the second-last
+ * word, and so on.
+ *
+ * In Node 0.12, we get the 0-based index from the
+ * first property inside the object by reading certain
+ * bits from the property descriptor details word.
+ * These constants are literal here because they're
+ * literal in the V8 source itself.
+ */
+ if (v8_major > 3 || (v8_major == 3 && v8_minor >= 26)) {
+ val = V8_PROP_FIELDINDEX(content[detidx]);
+ propaddr = addr + V8_OFF_HEAP(
+ size - (ninprops - val) * ps);
+ } else {
+ propaddr = addr + V8_OFF_HEAP(size + val * ps);
+ }
+
+ if (mdb_vread(&ptr, sizeof (ptr), propaddr) == -1) {
+ propinfo |= JPI_SKIPPED;
v8_warn("object %p: failed to read in-object "
- "property at %p\n", addr, addr +
- V8_OFF_HEAP(size + val *
- sizeof (uintptr_t)));
+ "property at %p", addr, propaddr);
continue;
}
+
+ propinfo |= JPI_INOBJECT;
} else {
- /* property should be in "props" array */
+ /*
+ * The property is in the separate "props" array.
+ */
if (val >= nprops) {
/*
* This can happen when properties are deleted.
@@ -1992,12 +2477,14 @@ jsobj_properties(uintptr_t addr,
if (val < rndescs)
continue;
+ propinfo |= JPI_SKIPPED;
v8_warn("object %p: property descriptor %d: "
"value index value (%d) out of bounds "
"(%d)\n", addr, ii, val, nprops);
goto err;
}
+ propinfo |= JPI_PROPS;
ptr = props[val];
}
@@ -2006,6 +2493,9 @@ jsobj_properties(uintptr_t addr,
}
rval = 0;
+ if (propinfop != NULL)
+ *propinfop = propinfo;
+
err:
if (props != NULL)
mdb_free(props, nprops * sizeof (uintptr_t));
@@ -2039,9 +2529,14 @@ jsfunc_lineno(uintptr_t lendsp, uintptr_t tokpos,
* The token position is an SMI, but it comes in as its raw
* value so we can more easily compare it to values in the line
* endings table. If we're just printing the position directly,
- * we must convert it here.
+ * we must convert it here, unless we're checking against the
+ * "-1" sentinel.
*/
- mdb_snprintf(buf, buflen, "position %d", V8_SMI_VALUE(tokpos));
+ if (tokpos == V8_VALUE_SMI(-1))
+ mdb_snprintf(buf, buflen, "unknown position");
+ else
+ mdb_snprintf(buf, buflen, "position %d",
+ V8_SMI_VALUE(tokpos));
if (lineno != NULL)
*lineno = 0;
@@ -2167,7 +2662,7 @@ jsfunc_lines(uintptr_t scriptp,
if (startline == -1 || endline == -1) {
mdb_warn("for script %p, could not determine startline/endline"
- " (start %ld, end %ld, nlines %d)",
+ " (start %ld, end %ld, nlines %d)\n",
scriptp, start, end, nlines);
mdb_free(buf, bufsz);
return;
@@ -2256,25 +2751,6 @@ jsfunc_name(uintptr_t funcinfop, char **bufp, size_t *lenp)
/*
* JavaScript-level object printing
*/
-typedef struct jsobj_print {
- char **jsop_bufp;
- size_t *jsop_lenp;
- int jsop_indent;
- uint64_t jsop_depth;
- boolean_t jsop_printaddr;
- uintptr_t jsop_baseaddr;
- int jsop_nprops;
- const char *jsop_member;
- boolean_t jsop_found;
- boolean_t jsop_descended;
-} jsobj_print_t;
-
-static int jsobj_print_number(uintptr_t, jsobj_print_t *);
-static int jsobj_print_oddball(uintptr_t, jsobj_print_t *);
-static int jsobj_print_jsobject(uintptr_t, jsobj_print_t *);
-static int jsobj_print_jsarray(uintptr_t, jsobj_print_t *);
-static int jsobj_print_jsfunction(uintptr_t, jsobj_print_t *);
-static int jsobj_print_jsdate(uintptr_t, jsobj_print_t *);
static int
jsobj_print(uintptr_t addr, jsobj_print_t *jsop)
@@ -2377,7 +2853,7 @@ jsobj_print_prop(const char *desc, uintptr_t val, void *arg)
char **bufp = jsop->jsop_bufp;
size_t *lenp = jsop->jsop_lenp;
- (void) bsnprintf(bufp, lenp, "%s\n%*s%s: ", jsop->jsop_nprops == 0 ?
+ (void) bsnprintf(bufp, lenp, "%s\n%*s\"%s\": ", jsop->jsop_nprops == 0 ?
"{" : "", jsop->jsop_indent + 4, "", desc);
descend = *jsop;
@@ -2438,7 +2914,8 @@ jsobj_print_jsobject(uintptr_t addr, jsobj_print_t *jsop)
size_t *lenp = jsop->jsop_lenp;
if (jsop->jsop_member != NULL)
- return (jsobj_properties(addr, jsobj_print_prop_member, jsop));
+ return (jsobj_properties(addr, jsobj_print_prop_member,
+ jsop, &jsop->jsop_propinfo));
if (jsop->jsop_depth == 0) {
(void) bsnprintf(bufp, lenp, "[...]");
@@ -2447,7 +2924,8 @@ jsobj_print_jsobject(uintptr_t addr, jsobj_print_t *jsop)
jsop->jsop_nprops = 0;
- if (jsobj_properties(addr, jsobj_print_prop, jsop) != 0)
+ if (jsobj_properties(addr, jsobj_print_prop, jsop,
+ &jsop->jsop_propinfo) != 0)
return (-1);
if (jsop->jsop_nprops > 0) {
@@ -2760,7 +3238,7 @@ dcmd_v8function(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
if (read_heap_ptr(&funcinfop, addr, V8_OFF_JSFUNCTION_SHARED) != 0 ||
- read_heap_ptr(&tokpos, funcinfop,
+ read_heap_maybesmi(&tokpos, funcinfop,
V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION) != 0 ||
read_heap_ptr(&scriptp, funcinfop,
V8_OFF_SHAREDFUNCTIONINFO_SCRIPT) != 0 ||
@@ -2768,6 +3246,13 @@ dcmd_v8function(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
read_heap_ptr(&lendsp, scriptp, V8_OFF_SCRIPT_LINE_ENDS) != 0)
goto err;
+ /*
+ * The token position is normally a SMI, so read_heap_maybesmi() will
+ * interpret the value for us. However, this code uses its SMI-encoded
+ * value, so convert it back here.
+ */
+ tokpos = V8_VALUE_SMI(tokpos);
+
bufp = buf;
len = sizeof (buf);
if (jsfunc_name(funcinfop, &bufp, &len) != 0)
@@ -2800,6 +3285,28 @@ err:
return (DCMD_ERR);
}
+/*
+ * Access an internal field of a V8 object.
+ */
+/* ARGSUSED */
+static int
+dcmd_v8internal(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ uintptr_t idx;
+ uintptr_t fieldaddr;
+
+ if (mdb_getopts(argc, argv, NULL) != argc - 1 ||
+ argv[argc - 1].a_type != MDB_TYPE_STRING)
+ return (DCMD_USAGE);
+
+ idx = mdb_strtoull(argv[argc - 1].a_un.a_str);
+ if (obj_v8internal(addr, idx, &fieldaddr) != 0)
+ return (DCMD_ERR);
+
+ mdb_printf("%p\n", fieldaddr);
+ return (DCMD_OK);
+}
+
/* ARGSUSED */
static int
dcmd_v8frametypes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
@@ -2921,11 +3428,39 @@ load_current_context(uintptr_t *fpp, uintptr_t *raddrp)
return (0);
}
+typedef struct jsframe {
+ boolean_t jsf_showall; /* show hidden frames and pointers */
+ boolean_t jsf_verbose; /* show arguments and JS code */
+ char *jsf_func; /* filter frames for named function */
+ char *jsf_prop; /* filter arguments */
+ uintptr_t jsf_nlines; /* lines of context (for verbose) */
+ uint_t jsf_nskipped; /* skipped frames */
+} jsframe_t;
+
+static void
+jsframe_skip(jsframe_t *jsf)
+{
+ jsf->jsf_nskipped++;
+}
+
+static void
+jsframe_print_skipped(jsframe_t *jsf)
+{
+ if (jsf->jsf_nskipped == 1)
+ mdb_printf(" (1 internal frame elided)\n");
+ else if (jsf->jsf_nskipped > 1)
+ mdb_printf(" (%d internal frames elided)\n",
+ jsf->jsf_nskipped);
+ jsf->jsf_nskipped = 0;
+}
+
static int
-do_jsframe_special(uintptr_t fptr, uintptr_t raddr, char *prop)
+do_jsframe_special(uintptr_t fptr, uintptr_t raddr, jsframe_t *jsf)
{
+ uint_t count;
uintptr_t ftype;
const char *ftypename;
+ char *prop = jsf->jsf_prop;
/*
* First see if this looks like a native frame rather than a JavaScript
@@ -2933,11 +3468,21 @@ do_jsframe_special(uintptr_t fptr, uintptr_t raddr, char *prop)
* symbolically. If that works, we assume this was NOT a V8 frame,
* since those are never in the symbol table.
*/
- if (mdb_snprintf(NULL, 0, "%A", raddr) > 1) {
+ count = mdb_snprintf(NULL, 0, "%A", raddr);
+ if (count > 1) {
if (prop != NULL)
return (0);
- mdb_printf("%p %a\n", fptr, raddr);
+ jsframe_print_skipped(jsf);
+ if (jsf->jsf_showall) {
+ mdb_printf("%p %a\n", fptr, raddr);
+ } else if (count <= 65) {
+ mdb_printf("native: %a\n", raddr);
+ } else {
+ char buf[65];
+ mdb_snprintf(buf, sizeof (buf), "%a", raddr);
+ mdb_printf("native: %s...\n", buf);
+ }
return (0);
}
@@ -2952,7 +3497,12 @@ do_jsframe_special(uintptr_t fptr, uintptr_t raddr, char *prop)
if (prop != NULL)
return (0);
- mdb_printf("%p %a <%s>\n", fptr, raddr, ftypename);
+ if (jsf->jsf_showall) {
+ jsframe_print_skipped(jsf);
+ mdb_printf("%p %a <%s>\n", fptr, raddr, ftypename);
+ } else {
+ jsframe_skip(jsf);
+ }
return (0);
}
@@ -2967,10 +3517,12 @@ do_jsframe_special(uintptr_t fptr, uintptr_t raddr, char *prop)
ftypename = enum_lookup_str(v8_frametypes, V8_SMI_VALUE(ftype),
NULL);
- if (ftypename != NULL)
+ if (jsf->jsf_showall && ftypename != NULL) {
+ jsframe_print_skipped(jsf);
mdb_printf("%p %a <%s>\n", fptr, raddr, ftypename);
- else
- mdb_printf("%p %a\n", fptr, raddr);
+ } else {
+ jsframe_skip(jsf);
+ }
return (0);
}
@@ -2979,9 +3531,14 @@ do_jsframe_special(uintptr_t fptr, uintptr_t raddr, char *prop)
}
static int
-do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
- char *func, char *prop, uintptr_t nlines)
+do_jsframe(uintptr_t fptr, uintptr_t raddr, jsframe_t *jsf)
{
+ boolean_t showall = jsf->jsf_showall;
+ boolean_t verbose = jsf->jsf_verbose;
+ const char *func = jsf->jsf_func;
+ const char *prop = jsf->jsf_prop;
+ uintptr_t nlines = jsf->jsf_nlines;
+
uintptr_t funcp, funcinfop, tokpos, endpos, scriptp, lendsp, ptrp;
uintptr_t ii, nargs;
const char *typename;
@@ -2994,7 +3551,7 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
/*
* Check for non-JavaScript frames first.
*/
- if (func == NULL && do_jsframe_special(fptr, raddr, prop) == 0)
+ if (func == NULL && do_jsframe_special(fptr, raddr, jsf) == 0)
return (DCMD_OK);
/*
@@ -3017,7 +3574,12 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
if (func != NULL || prop != NULL)
return (DCMD_OK);
- mdb_printf("%p %a\n", fptr, raddr);
+ if (showall) {
+ jsframe_print_skipped(jsf);
+ mdb_printf("%p %a\n", fptr, raddr);
+ } else {
+ jsframe_skip(jsf);
+ }
return (DCMD_OK);
}
@@ -3025,7 +3587,13 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
if (func != NULL || prop != NULL)
return (DCMD_OK);
- mdb_printf("%p %a internal (Code: %p)\n", fptr, raddr, funcp);
+ if (showall) {
+ jsframe_print_skipped(jsf);
+ mdb_printf("%p %a internal (Code: %p)\n",
+ fptr, raddr, funcp);
+ } else {
+ jsframe_skip(jsf);
+ }
return (DCMD_OK);
}
@@ -3033,8 +3601,13 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
if (func != NULL || prop != NULL)
return (DCMD_OK);
- mdb_printf("%p %a unknown (%s: %p)", fptr, raddr, typename,
- funcp);
+ if (showall) {
+ jsframe_print_skipped(jsf);
+ mdb_printf("%p %a unknown (%s: %p)",
+ fptr, raddr, typename, funcp);
+ } else {
+ jsframe_skip(jsf);
+ }
return (DCMD_OK);
}
@@ -3049,19 +3622,33 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
if (func != NULL && strcmp(buf, func) != 0)
return (DCMD_OK);
- if (prop == NULL)
- mdb_printf("%p %a %s (%p)\n", fptr, raddr, buf, funcp);
+ if (prop == NULL) {
+ jsframe_print_skipped(jsf);
+ if (showall)
+ mdb_printf("%p %a ", fptr, raddr);
+ else
+ mdb_printf("js: ");
+ mdb_printf("%s", buf);
+ if (showall)
+ mdb_printf(" (JSFunction: %p)\n", funcp);
+ else
+ mdb_printf("\n");
+ }
if (!verbose && prop == NULL)
return (DCMD_OK);
+ if (verbose)
+ jsframe_print_skipped(jsf);
+
/*
* 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,
+ if (read_heap_maybesmi(&tokpos, funcinfop,
V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION) != 0)
return (DCMD_ERR);
+ tokpos = V8_VALUE_SMI(tokpos);
if (read_heap_ptr(&scriptp, funcinfop,
V8_OFF_SHAREDFUNCTIONINFO_SCRIPT) != 0)
@@ -3080,25 +3667,54 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
}
if (prop == NULL) {
- (void) mdb_inc_indent(4);
+ (void) mdb_inc_indent(10);
mdb_printf("file: %s\n", buf);
}
if (read_heap_ptr(&lendsp, scriptp, V8_OFF_SCRIPT_LINE_ENDS) != 0)
return (DCMD_ERR);
- if (read_heap_smi(&nargs, funcinfop,
+ (void) jsfunc_lineno(lendsp, tokpos, buf, sizeof (buf), &lineno);
+
+ if (prop != NULL && strcmp(prop, "posn") == 0) {
+ mdb_printf("%s\n", buf);
+ return (DCMD_OK);
+ }
+
+ if (prop == NULL)
+ mdb_printf("posn: %s\n", buf);
+
+ if (read_heap_maybesmi(&nargs, funcinfop,
V8_OFF_SHAREDFUNCTIONINFO_LENGTH) == 0) {
- for (ii = 0; ii < nargs; ii++) {
- uintptr_t argptr;
- char arg[10];
+ uintptr_t argptr;
+ char arg[10];
+
+ if (mdb_vread(&argptr, sizeof (argptr),
+ fptr + V8_OFF_FP_ARGS + nargs * sizeof (uintptr_t)) != -1 &&
+ argptr != NULL) {
+ (void) snprintf(arg, sizeof (arg), "this");
+ if (prop != NULL && strcmp(arg, prop) == 0) {
+ mdb_printf("%p\n", argptr);
+ return (DCMD_OK);
+ }
+
+ if (prop == NULL) {
+ bufp = buf;
+ len = sizeof (buf);
+ (void) obj_jstype(argptr, &bufp, &len, NULL);
+ mdb_printf("this: %p (%s)\n", argptr, buf);
+ }
+ }
+
+ for (ii = 0; ii < nargs; ii++) {
if (mdb_vread(&argptr, sizeof (argptr),
fptr + V8_OFF_FP_ARGS + (nargs - ii - 1) *
sizeof (uintptr_t)) == -1)
continue;
- (void) snprintf(arg, sizeof (arg), "arg%d", ii + 1);
+ (void) snprintf(arg, sizeof (arg), "arg%" PRIuPTR,
+ ii + 1);
if (prop != NULL) {
if (strcmp(arg, prop) != 0)
@@ -3116,28 +3732,20 @@ do_jsframe(uintptr_t fptr, uintptr_t raddr, boolean_t verbose,
}
}
- (void) jsfunc_lineno(lendsp, tokpos, buf, sizeof (buf), &lineno);
if (prop != NULL) {
- if (strcmp(prop, "posn") == 0) {
- mdb_printf("%s\n", buf);
- return (DCMD_OK);
- }
-
mdb_warn("unknown frame property '%s'\n", prop);
return (DCMD_ERR);
}
- mdb_printf("posn: %s", buf);
-
- if (nlines != 0 && read_heap_smi(&endpos, funcinfop,
+ if (nlines != 0 && read_heap_maybesmi(&endpos, funcinfop,
V8_OFF_SHAREDFUNCTIONINFO_END_POSITION) == 0) {
jsfunc_lines(scriptp,
V8_SMI_VALUE(tokpos), endpos, nlines, "%5d ");
+ mdb_printf("\n");
}
- mdb_printf("\n");
- (void) mdb_dec_indent(4);
+ (void) mdb_dec_indent(10);
return (DCMD_OK);
}
@@ -3155,6 +3763,7 @@ typedef struct findjsobjects_instance {
typedef struct findjsobjects_obj {
findjsobjects_prop_t *fjso_props;
findjsobjects_prop_t *fjso_last;
+ jspropinfo_t fjso_propinfo;
size_t fjso_nprops;
findjsobjects_instance_t fjso_instances;
int fjso_ninstances;
@@ -3164,6 +3773,17 @@ typedef struct findjsobjects_obj {
char fjso_constructor[80];
} findjsobjects_obj_t;
+typedef struct findjsobjects_func {
+ findjsobjects_instance_t fjsf_instances;
+ int fjsf_ninstances;
+ avl_node_t fjsf_node;
+ struct findjsobjects_func *fjsf_next;
+ uintptr_t fjsf_shared;
+ char fjsf_funcname[40];
+ char fjsf_scriptname[80];
+ char fjsf_location[20];
+} findjsobjects_func_t;
+
typedef struct findjsobjects_stats {
int fjss_heapobjs;
int fjss_cached;
@@ -3172,6 +3792,9 @@ typedef struct findjsobjects_stats {
int fjss_objects;
int fjss_arrays;
int fjss_uniques;
+ int fjss_funcs;
+ int fjss_funcs_skipped;
+ int fjss_funcs_unique;
} findjsobjects_stats_t;
typedef struct findjsobjects_reference {
@@ -3200,10 +3823,12 @@ typedef struct findjsobjects_state {
boolean_t fjs_referred;
avl_tree_t fjs_tree;
avl_tree_t fjs_referents;
+ avl_tree_t fjs_funcinfo;
findjsobjects_referent_t *fjs_head;
findjsobjects_referent_t *fjs_tail;
findjsobjects_obj_t *fjs_current;
findjsobjects_obj_t *fjs_objects;
+ findjsobjects_func_t *fjs_funcs;
findjsobjects_stats_t fjs_stats;
} findjsobjects_state_t;
@@ -3268,6 +3893,14 @@ findjsobjects_cmp(findjsobjects_obj_t *lhs, findjsobjects_obj_t *rhs)
}
int
+findjsobjects_cmp_funcinfo(findjsobjects_func_t *lhs,
+ findjsobjects_func_t *rhs)
+{
+ int diff = lhs->fjsf_shared - rhs->fjsf_shared;
+ return (diff < 0 ? -1 : diff > 0 ? 1 : 0);
+}
+
+int
findjsobjects_cmp_referents(findjsobjects_referent_t *lhs,
findjsobjects_referent_t *rhs)
{
@@ -3369,6 +4002,71 @@ out:
v8_silent--;
}
+static void
+findjsobjects_jsfunc(findjsobjects_state_t *fjs, uintptr_t addr)
+{
+ findjsobjects_func_t *func, *ofunc;
+ findjsobjects_instance_t *inst;
+ uintptr_t funcinfo, script, name;
+ avl_index_t where;
+ int err;
+ char *bufp;
+ size_t len;
+
+ /*
+ * This may be somewhat expensive to do for all JSFunctions, but in most
+ * core files, there aren't that many. We could defer some of this work
+ * until the user tries to print the function ::jsfunctions, but this
+ * step is useful to do early to filter out garbage data.
+ */
+
+ v8_silent++;
+ if (read_heap_ptr(&funcinfo, addr, V8_OFF_JSFUNCTION_SHARED) != 0 ||
+ read_heap_ptr(&script, funcinfo,
+ V8_OFF_SHAREDFUNCTIONINFO_SCRIPT) != 0 ||
+ read_heap_ptr(&name, script, V8_OFF_SCRIPT_NAME) != 0) {
+ fjs->fjs_stats.fjss_funcs_skipped++;
+ v8_silent--;
+ return;
+ }
+
+ func = mdb_zalloc(sizeof (findjsobjects_func_t), UM_SLEEP);
+ func->fjsf_ninstances = 1;
+ func->fjsf_instances.fjsi_addr = addr;
+ func->fjsf_shared = funcinfo;
+
+ bufp = func->fjsf_funcname;
+ len = sizeof (func->fjsf_funcname);
+ err = jsfunc_name(funcinfo, &bufp, &len);
+
+ bufp = func->fjsf_scriptname;
+ len = sizeof (func->fjsf_scriptname);
+ err |= jsstr_print(name, JSSTR_NUDE, &bufp, &len);
+
+ v8_silent--;
+ if (err != 0) {
+ fjs->fjs_stats.fjss_funcs_skipped++;
+ mdb_free(func, sizeof (findjsobjects_func_t));
+ return;
+ }
+
+ fjs->fjs_stats.fjss_funcs++;
+ ofunc = avl_find(&fjs->fjs_funcinfo, func, &where);
+ if (ofunc == NULL) {
+ avl_add(&fjs->fjs_funcinfo, func);
+ func->fjsf_next = fjs->fjs_funcs;
+ fjs->fjs_funcs = func;
+ fjs->fjs_stats.fjss_funcs_unique++;
+ } else {
+ inst = mdb_alloc(sizeof (findjsobjects_instance_t), UM_SLEEP);
+ inst->fjsi_addr = addr;
+ inst->fjsi_next = ofunc->fjsf_instances.fjsi_next;
+ ofunc->fjsf_instances.fjsi_next = inst;
+ ofunc->fjsf_ninstances++;
+ mdb_free(func, sizeof (findjsobjects_func_t));
+ }
+}
+
int
findjsobjects_range(findjsobjects_state_t *fjs, uintptr_t addr, uintptr_t size)
{
@@ -3376,6 +4074,7 @@ findjsobjects_range(findjsobjects_state_t *fjs, uintptr_t addr, uintptr_t size)
findjsobjects_stats_t *stats = &fjs->fjs_stats;
uint8_t type;
int jsobject = V8_TYPE_JSOBJECT, jsarray = V8_TYPE_JSARRAY;
+ int jsfunction = V8_TYPE_JSFUNCTION;
caddr_t range = mdb_alloc(size, UM_SLEEP);
uintptr_t base = addr, mapaddr;
@@ -3414,6 +4113,11 @@ findjsobjects_range(findjsobjects_state_t *fjs, uintptr_t addr, uintptr_t size)
continue;
}
+ if (type == jsfunction) {
+ findjsobjects_jsfunc(fjs, addr);
+ continue;
+ }
+
if (type != jsobject && type != jsarray)
continue;
@@ -3423,7 +4127,8 @@ findjsobjects_range(findjsobjects_state_t *fjs, uintptr_t addr, uintptr_t size)
if (type == jsobject) {
if (jsobj_properties(addr,
- findjsobjects_prop, fjs) != 0) {
+ findjsobjects_prop, fjs,
+ &fjs->fjs_current->fjso_propinfo) != 0) {
findjsobjects_free(fjs->fjs_current);
fjs->fjs_current = NULL;
continue;
@@ -3625,7 +4330,7 @@ findjsobjects_references(findjsobjects_state_t *fjs)
fjs->fjs_addr = inst->fjsi_addr;
(void) jsobj_properties(inst->fjsi_addr,
- findjsobjects_references_prop, fjs);
+ findjsobjects_references_prop, fjs, NULL);
}
}
@@ -3716,6 +4421,26 @@ findjsobjects_match_constructor(findjsobjects_obj_t *obj,
mdb_printf("%p\n", obj->fjso_instances.fjsi_addr);
}
+static void
+findjsobjects_match_kind(findjsobjects_obj_t *obj, const char *propkind)
+{
+ jspropinfo_t p = obj->fjso_propinfo;
+
+ if (((p & JPI_NUMERIC) != 0 && strstr(propkind, "numeric") != NULL) ||
+ ((p & JPI_DICT) != 0 && strstr(propkind, "dict") != NULL) ||
+ ((p & JPI_INOBJECT) != 0 && strstr(propkind, "inobject") != NULL) ||
+ ((p & JPI_PROPS) != 0 && strstr(propkind, "props") != NULL) ||
+ ((p & JPI_HASTRANSITIONS) != 0 &&
+ strstr(propkind, "transitions") != NULL) ||
+ ((p & JPI_HASCONTENT) != 0 &&
+ strstr(propkind, "content") != NULL) ||
+ ((p & JPI_SKIPPED) != 0 && strstr(propkind, "skipped") != NULL) ||
+ ((p & JPI_BADLAYOUT) != 0 &&
+ strstr(propkind, "badlayout") != NULL)) {
+ mdb_printf("%p\n", obj->fjso_instances.fjsi_addr);
+ }
+}
+
static int
findjsobjects_match(findjsobjects_state_t *fjs, uintptr_t addr,
uint_t flags, void (*func)(findjsobjects_obj_t *, const char *),
@@ -3823,84 +4548,71 @@ dcmd_findjsobjects_help(void)
" -v Provide verbose statistics\n");
}
+static findjsobjects_state_t findjsobjects_state;
+
static int
-dcmd_findjsobjects(uintptr_t addr,
- uint_t flags, int argc, const mdb_arg_t *argv)
+findjsobjects_run(findjsobjects_state_t *fjs)
{
- static findjsobjects_state_t fjs;
- static findjsobjects_stats_t *stats = &fjs.fjs_stats;
- findjsobjects_obj_t *obj;
struct ps_prochandle *Pr;
- boolean_t references = B_FALSE, listlike = B_FALSE;
- const char *propname = NULL;
- const char *constructor = NULL;
-
- fjs.fjs_verbose = B_FALSE;
- fjs.fjs_brk = B_FALSE;
- fjs.fjs_marking = B_FALSE;
- fjs.fjs_allobjs = B_FALSE;
-
- if (mdb_getopts(argc, argv,
- 'a', MDB_OPT_SETBITS, B_TRUE, &fjs.fjs_allobjs,
- 'b', MDB_OPT_SETBITS, B_TRUE, &fjs.fjs_brk,
- 'c', MDB_OPT_STR, &constructor,
- 'l', MDB_OPT_SETBITS, B_TRUE, &listlike,
- 'm', MDB_OPT_SETBITS, B_TRUE, &fjs.fjs_marking,
- 'p', MDB_OPT_STR, &propname,
- 'r', MDB_OPT_SETBITS, B_TRUE, &references,
- 'v', MDB_OPT_SETBITS, B_TRUE, &fjs.fjs_verbose,
- NULL) != argc)
- return (DCMD_USAGE);
+ findjsobjects_obj_t *obj;
+ findjsobjects_stats_t *stats = &fjs->fjs_stats;
- if (!fjs.fjs_initialized) {
- avl_create(&fjs.fjs_tree,
+ if (!fjs->fjs_initialized) {
+ avl_create(&fjs->fjs_tree,
(int(*)(const void *, const void *))findjsobjects_cmp,
sizeof (findjsobjects_obj_t),
offsetof(findjsobjects_obj_t, fjso_node));
- avl_create(&fjs.fjs_referents,
+ avl_create(&fjs->fjs_referents,
(int(*)(const void *, const void *))
findjsobjects_cmp_referents,
sizeof (findjsobjects_referent_t),
offsetof(findjsobjects_referent_t, fjsr_node));
- fjs.fjs_initialized = B_TRUE;
+ avl_create(&fjs->fjs_funcinfo,
+ (int(*)(const void *, const void*))
+ findjsobjects_cmp_funcinfo,
+ sizeof (findjsobjects_func_t),
+ offsetof(findjsobjects_func_t, fjsf_node));
+
+ fjs->fjs_initialized = B_TRUE;
}
- if (avl_is_empty(&fjs.fjs_tree)) {
+ if (avl_is_empty(&fjs->fjs_tree)) {
findjsobjects_obj_t **sorted;
int nobjs, i;
hrtime_t start = gethrtime();
if (mdb_get_xdata("pshandle", &Pr, sizeof (Pr)) == -1) {
mdb_warn("couldn't read pshandle xdata");
- return (DCMD_ERR);
+ return (-1);
}
v8_silent++;
if (Pmapping_iter(Pr,
- (proc_map_f *)findjsobjects_mapping, &fjs) != 0) {
+ (proc_map_f *)findjsobjects_mapping, fjs) != 0) {
v8_silent--;
- return (DCMD_ERR);
+ return (-1);
}
- if ((nobjs = avl_numnodes(&fjs.fjs_tree)) != 0) {
+ if ((nobjs = avl_numnodes(&fjs->fjs_tree)) != 0) {
/*
* We have the objects -- now sort them.
*/
sorted = mdb_alloc(nobjs * sizeof (void *),
UM_SLEEP | UM_GC);
- for (obj = fjs.fjs_objects, i = 0; obj != NULL;
+ for (obj = fjs->fjs_objects, i = 0; obj != NULL;
obj = obj->fjso_next, i++) {
sorted[i] = obj;
}
- qsort(sorted, avl_numnodes(&fjs.fjs_tree),
+ qsort(sorted, avl_numnodes(&fjs->fjs_tree),
sizeof (void *), findjsobjects_cmp_ninstances);
- for (i = 1, fjs.fjs_objects = sorted[0]; i < nobjs; i++)
+ for (i = 1, fjs->fjs_objects = sorted[0];
+ i < nobjs; i++)
sorted[i - 1]->fjso_next = sorted[i];
sorted[nobjs - 1]->fjso_next = NULL;
@@ -3908,7 +4620,7 @@ dcmd_findjsobjects(uintptr_t addr,
v8_silent--;
- if (fjs.fjs_verbose) {
+ if (fjs->fjs_verbose) {
const char *f = "findjsobjects: %30s => %d\n";
int elapsed = (int)((gethrtime() - start) / NANOSEC);
@@ -3920,12 +4632,54 @@ dcmd_findjsobjects(uintptr_t addr,
mdb_printf(f, "processed objects", stats->fjss_objects);
mdb_printf(f, "processed arrays", stats->fjss_arrays);
mdb_printf(f, "unique objects", stats->fjss_uniques);
+ mdb_printf(f, "functions found", stats->fjss_funcs);
+ mdb_printf(f, "unique functions",
+ stats->fjss_funcs_unique);
+ mdb_printf(f, "functions skipped",
+ stats->fjss_funcs_skipped);
}
}
+ return (0);
+}
+
+static int
+dcmd_findjsobjects(uintptr_t addr,
+ uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ findjsobjects_state_t *fjs = &findjsobjects_state;
+ findjsobjects_obj_t *obj;
+ boolean_t references = B_FALSE, listlike = B_FALSE;
+ const char *propname = NULL;
+ const char *constructor = NULL;
+ const char *propkind = NULL;
+
+ fjs->fjs_verbose = B_FALSE;
+ fjs->fjs_brk = B_FALSE;
+ fjs->fjs_marking = B_FALSE;
+ fjs->fjs_allobjs = B_FALSE;
+
+ if (mdb_getopts(argc, argv,
+ 'a', MDB_OPT_SETBITS, B_TRUE, &fjs->fjs_allobjs,
+ 'b', MDB_OPT_SETBITS, B_TRUE, &fjs->fjs_brk,
+ 'c', MDB_OPT_STR, &constructor,
+ 'k', MDB_OPT_STR, &propkind,
+ 'l', MDB_OPT_SETBITS, B_TRUE, &listlike,
+ 'm', MDB_OPT_SETBITS, B_TRUE, &fjs->fjs_marking,
+ 'p', MDB_OPT_STR, &propname,
+ 'r', MDB_OPT_SETBITS, B_TRUE, &references,
+ 'v', MDB_OPT_SETBITS, B_TRUE, &fjs->fjs_verbose,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (findjsobjects_run(fjs) != 0)
+ return (DCMD_ERR);
+
if (listlike && !(flags & DCMD_ADDRSPEC)) {
- if (propname != NULL || constructor != NULL) {
- char opt = propname != NULL ? 'p' : 'c';
+ if (propname != NULL || constructor != NULL ||
+ propkind != NULL) {
+ char opt = propname != NULL ? 'p' :
+ propkind != NULL ? 'k' :'c';
mdb_warn("cannot specify -l with -%c; instead, pipe "
"output of ::findjsobjects -%c to "
@@ -3933,38 +4687,50 @@ dcmd_findjsobjects(uintptr_t addr,
return (DCMD_ERR);
}
- return (findjsobjects_match(&fjs, addr, flags,
+ return (findjsobjects_match(fjs, addr, flags,
findjsobjects_match_all, NULL));
}
if (propname != NULL) {
- if (constructor != NULL) {
+ if (constructor != NULL || propkind != NULL) {
mdb_warn("cannot specify both a property name "
- "and a constructor\n");
+ "and a %s\n", constructor != NULL ?
+ "constructor" : "property kind");
return (DCMD_ERR);
}
- return (findjsobjects_match(&fjs, addr, flags,
+ return (findjsobjects_match(fjs, addr, flags,
findjsobjects_match_propname, propname));
}
if (constructor != NULL) {
- return (findjsobjects_match(&fjs, addr, flags,
+ if (propkind != NULL) {
+ mdb_warn("cannot specify both a constructor name "
+ "and a property kind\n");
+ return (DCMD_ERR);
+ }
+
+ return (findjsobjects_match(fjs, addr, flags,
findjsobjects_match_constructor, constructor));
}
+ if (propkind != NULL) {
+ return (findjsobjects_match(fjs, addr, flags,
+ findjsobjects_match_kind, propkind));
+ }
+
if (references && !(flags & DCMD_ADDRSPEC) &&
- avl_is_empty(&fjs.fjs_referents)) {
+ avl_is_empty(&fjs->fjs_referents)) {
mdb_warn("must specify or mark an object to find references\n");
return (DCMD_ERR);
}
- if (fjs.fjs_marking && !(flags & DCMD_ADDRSPEC)) {
+ if (fjs->fjs_marking && !(flags & DCMD_ADDRSPEC)) {
mdb_warn("must specify an object to mark\n");
return (DCMD_ERR);
}
- if (references && fjs.fjs_marking) {
+ if (references && fjs->fjs_marking) {
mdb_warn("can't both mark an object and find its references\n");
return (DCMD_ERR);
}
@@ -3978,14 +4744,14 @@ dcmd_findjsobjects(uintptr_t addr,
* specified/marked objects (-r). (Note that the absence of
* any of these options implies -l.)
*/
- inst = findjsobjects_instance(&fjs, addr, &head);
+ inst = findjsobjects_instance(fjs, addr, &head);
if (inst == NULL) {
mdb_warn("%p is not a valid object\n", addr);
return (DCMD_ERR);
}
- if (!references && !fjs.fjs_marking) {
+ if (!references && !fjs->fjs_marking) {
for (inst = head; inst != NULL; inst = inst->fjsi_next)
mdb_printf("%p\n", inst->fjsi_addr);
@@ -3993,24 +4759,24 @@ dcmd_findjsobjects(uintptr_t addr,
}
if (!listlike) {
- findjsobjects_referent(&fjs, inst->fjsi_addr);
+ findjsobjects_referent(fjs, inst->fjsi_addr);
} else {
for (inst = head; inst != NULL; inst = inst->fjsi_next)
- findjsobjects_referent(&fjs, inst->fjsi_addr);
+ findjsobjects_referent(fjs, inst->fjsi_addr);
}
}
if (references)
- findjsobjects_references(&fjs);
+ findjsobjects_references(fjs);
- if (references || fjs.fjs_marking)
+ if (references || fjs->fjs_marking)
return (DCMD_OK);
mdb_printf("%?s %8s %8s %s\n", "OBJECT",
"#OBJECTS", "#PROPS", "CONSTRUCTOR: PROPS");
- for (obj = fjs.fjs_objects; obj != NULL; obj = obj->fjso_next) {
- if (obj->fjso_malformed && !fjs.fjs_allobjs)
+ for (obj = fjs->fjs_objects; obj != NULL; obj = obj->fjso_next) {
+ if (obj->fjso_malformed && !fjs->fjs_allobjs)
continue;
findjsobjects_print(obj);
@@ -4019,21 +4785,90 @@ dcmd_findjsobjects(uintptr_t addr,
return (DCMD_OK);
}
+/*
+ * Given a Node Buffer object, print out details about it. With "-a", just
+ * print the address.
+ */
+/* ARGSUSED */
+static int
+dcmd_nodebuffer(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ boolean_t opt_f = B_FALSE;
+ char buf[80];
+ char *bufp = buf;
+ size_t len = sizeof (buf);
+ uintptr_t elts, rawbuf;
+
+ /*
+ * The undocumented "-f" option allows users to override constructor
+ * checks.
+ */
+ if (mdb_getopts(argc, argv,
+ 'f', MDB_OPT_SETBITS, B_TRUE, &opt_f, NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (!opt_f) {
+ if (obj_jsconstructor(addr, &bufp, &len, B_FALSE) != 0)
+ return (DCMD_ERR);
+
+ if (strcmp(buf, "Buffer") != 0) {
+ mdb_warn("%p does not appear to be a buffer\n", addr);
+ return (DCMD_ERR);
+ }
+ }
+
+ if (read_heap_ptr(&elts, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0)
+ return (DCMD_ERR);
+
+ if (obj_v8internal(elts, 0, &rawbuf) != 0)
+ return (DCMD_ERR);
+
+ mdb_printf("%p\n", rawbuf);
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+dcmd_jsconstructor(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ boolean_t opt_v = B_FALSE;
+ char buf[80];
+ char *bufp;
+ size_t len = sizeof (buf);
+
+ if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, B_TRUE, &opt_v,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ bufp = buf;
+ if (obj_jsconstructor(addr, &bufp, &len, opt_v))
+ return (DCMD_ERR);
+
+ mdb_printf("%s\n", buf);
+ return (DCMD_OK);
+}
+
/* ARGSUSED */
static int
dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uintptr_t fptr, raddr;
- boolean_t opt_v = B_FALSE, opt_i = B_FALSE;
- char *opt_f = NULL, *opt_p = NULL;
- uintptr_t opt_n = 5;
+ boolean_t opt_i = B_FALSE;
+ jsframe_t jsf;
+ int rv;
+
+ bzero(&jsf, sizeof (jsf));
+ jsf.jsf_nlines = 5;
if (mdb_getopts(argc, argv,
- 'v', MDB_OPT_SETBITS, B_TRUE, &opt_v,
+ 'a', MDB_OPT_SETBITS, B_TRUE, &jsf.jsf_showall,
+ 'v', MDB_OPT_SETBITS, B_TRUE, &jsf.jsf_verbose,
'i', MDB_OPT_SETBITS, B_TRUE, &opt_i,
- 'f', MDB_OPT_STR, &opt_f,
- 'n', MDB_OPT_UINTPTR, &opt_n,
- 'p', MDB_OPT_STR, &opt_p, NULL) != argc)
+ 'f', MDB_OPT_STR, &jsf.jsf_func,
+ 'n', MDB_OPT_UINTPTR, &jsf.jsf_nlines,
+ 'p', MDB_OPT_STR, &jsf.jsf_prop, NULL) != argc)
return (DCMD_USAGE);
/*
@@ -4043,8 +4878,12 @@ dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
* actually stored with the next frame. For debugging, this can be
* overridden with the "-i" option (for "immediate").
*/
- if (opt_i)
- return (do_jsframe(addr, 0, opt_v, opt_f, opt_p, opt_n));
+ if (opt_i) {
+ rv = do_jsframe(addr, 0, &jsf);
+ if (rv == 0)
+ jsframe_print_skipped(&jsf);
+ return (rv);
+ }
if (mdb_vread(&raddr, sizeof (raddr),
addr + sizeof (uintptr_t)) == -1) {
@@ -4061,7 +4900,43 @@ dcmd_jsframe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
if (fptr == NULL)
return (DCMD_OK);
- return (do_jsframe(fptr, raddr, opt_v, opt_f, opt_p, opt_n));
+ rv = do_jsframe(fptr, raddr, &jsf);
+ if (rv == 0)
+ jsframe_print_skipped(&jsf);
+ return (rv);
+}
+
+static void
+jsobj_print_propinfo(jspropinfo_t propinfo)
+{
+ if (propinfo == JPI_NONE)
+ return;
+
+ mdb_printf("property kind: ");
+ if ((propinfo & JPI_NUMERIC) != 0)
+ mdb_printf("numeric-named ");
+ if ((propinfo & JPI_DICT) != 0)
+ mdb_printf("dictionary ");
+ if ((propinfo & JPI_INOBJECT) != 0)
+ mdb_printf("in-object ");
+ if ((propinfo & JPI_PROPS) != 0)
+ mdb_printf("\"properties\" array ");
+ mdb_printf("\n");
+
+ if ((propinfo & (JPI_HASTRANSITIONS | JPI_HASCONTENT)) != 0) {
+ mdb_printf("fallbacks: ");
+ if ((propinfo & JPI_HASTRANSITIONS) != 0)
+ mdb_printf("transitions ");
+ if ((propinfo & JPI_HASCONTENT) != 0)
+ mdb_printf("content ");
+ mdb_printf("\n");
+ }
+
+ if ((propinfo & JPI_SKIPPED) != 0)
+ mdb_printf(
+ "some properties skipped due to unexpected layout\n");
+ if ((propinfo & JPI_BADLAYOUT) != 0)
+ mdb_printf("object has unexpected layout\n");
}
/* ARGSUSED */
@@ -4072,6 +4947,7 @@ dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
size_t bufsz = 262144, len = bufsz;
jsobj_print_t jsop;
boolean_t opt_b = B_FALSE;
+ boolean_t opt_v = B_FALSE;
int rv, i;
bzero(&jsop, sizeof (jsop));
@@ -4081,7 +4957,8 @@ dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
i = mdb_getopts(argc, argv,
'a', MDB_OPT_SETBITS, B_TRUE, &jsop.jsop_printaddr,
'b', MDB_OPT_SETBITS, B_TRUE, &opt_b,
- 'd', MDB_OPT_UINT64, &jsop.jsop_depth, NULL);
+ 'd', MDB_OPT_UINT64, &jsop.jsop_depth,
+ 'v', MDB_OPT_SETBITS, B_TRUE, &opt_v, NULL);
if (opt_b)
jsop.jsop_baseaddr = addr;
@@ -4139,9 +5016,209 @@ dcmd_jsprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_printf("\n");
+ if (opt_v)
+ jsobj_print_propinfo(jsop.jsop_propinfo);
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+dcmd_jssource(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ const char *typename;
+ uintptr_t nlines = 5;
+ uintptr_t funcinfop, scriptp, funcnamep;
+ uintptr_t tokpos, endpos;
+ uint8_t type;
+ char buf[256];
+ char *bufp = buf;
+ size_t len = sizeof (buf);
+
+ if (mdb_getopts(argc, argv, 'n', MDB_OPT_UINTPTR, &nlines,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (!V8_IS_HEAPOBJECT(addr) || read_typebyte(&type, addr) != 0) {
+ mdb_warn("%p is not a heap object\n", addr);
+ return (DCMD_ERR);
+ }
+
+ typename = enum_lookup_str(v8_types, type, "");
+ if (strcmp(typename, "JSFunction") != 0) {
+ mdb_warn("%p is not a JSFunction\n", addr);
+ return (DCMD_ERR);
+ }
+
+ if (read_heap_ptr(&funcinfop, addr, V8_OFF_JSFUNCTION_SHARED) != 0 ||
+ read_heap_ptr(&scriptp, funcinfop,
+ V8_OFF_SHAREDFUNCTIONINFO_SCRIPT) != 0 ||
+ read_heap_ptr(&funcnamep, scriptp, V8_OFF_SCRIPT_NAME) != 0) {
+ mdb_warn("%p: failed to find script for function\n", addr);
+ return (DCMD_ERR);
+ }
+
+ if (read_heap_maybesmi(&tokpos, funcinfop,
+ V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION) != 0 ||
+ read_heap_maybesmi(&endpos, funcinfop,
+ V8_OFF_SHAREDFUNCTIONINFO_END_POSITION) != 0) {
+ mdb_warn("%p: failed to find function's boundaries\n", addr);
+ }
+
+ if (jsstr_print(funcnamep, JSSTR_NUDE, &bufp, &len) == 0)
+ mdb_printf("file: %s\n", buf);
+
+ if (tokpos != endpos)
+ jsfunc_lines(scriptp, tokpos, endpos, nlines, "%5d ");
+ mdb_printf("\n");
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+dcmd_jsfunctions(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ findjsobjects_state_t *fjs = &findjsobjects_state;
+ findjsobjects_func_t *func;
+ uintptr_t funcinfo;
+ boolean_t showrange = B_FALSE;
+ const char *name = NULL, *filename = NULL;
+ uintptr_t instr = 0;
+
+ if (mdb_getopts(argc, argv,
+ 'x', MDB_OPT_UINTPTR, &instr,
+ 'X', MDB_OPT_SETBITS, B_TRUE, &showrange,
+ 'n', MDB_OPT_STR, &name,
+ 's', MDB_OPT_STR, &filename,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (findjsobjects_run(fjs) != 0)
+ return (DCMD_ERR);
+
+ if (!showrange)
+ mdb_printf("%?s %8s %-40s %s\n", "FUNC", "#FUNCS", "NAME",
+ "FROM");
+ else
+ mdb_printf("%?s %8s %?s %?s %-40s %s\n", "FUNC", "#FUNCS",
+ "START", "END", "NAME", "FROM");
+
+ for (func = fjs->fjs_funcs; func != NULL; func = func->fjsf_next) {
+ uintptr_t code, ilen;
+
+ funcinfo = func->fjsf_shared;
+
+ if (func->fjsf_location[0] == '\0') {
+ uintptr_t tokpos, script, lends;
+ ptrdiff_t tokposoff =
+ V8_OFF_SHAREDFUNCTIONINFO_FUNCTION_TOKEN_POSITION;
+
+ /*
+ * We don't want to actually decode the token position
+ * as an SMI here, so we re-encode it when we pass it to
+ * jsfunc_lineno() below.
+ */
+ if (read_heap_maybesmi(&tokpos, funcinfo,
+ tokposoff) != 0 ||
+ read_heap_ptr(&script, funcinfo,
+ V8_OFF_SHAREDFUNCTIONINFO_SCRIPT) != 0 ||
+ read_heap_ptr(&lends, script,
+ V8_OFF_SCRIPT_LINE_ENDS) != 0 ||
+ jsfunc_lineno(lends, V8_VALUE_SMI(tokpos),
+ func->fjsf_location,
+ sizeof (func->fjsf_location), NULL) != 0) {
+ func->fjsf_location[0] = '\0';
+ }
+ }
+
+ if (name != NULL && strstr(func->fjsf_funcname, name) == NULL)
+ continue;
+
+ if (filename != NULL &&
+ strstr(func->fjsf_scriptname, filename) == NULL)
+ continue;
+
+ code = 0;
+ ilen = 0;
+ if ((showrange || instr != 0) &&
+ (read_heap_ptr(&code, funcinfo,
+ V8_OFF_SHAREDFUNCTIONINFO_CODE) != 0 ||
+ read_heap_ptr(&ilen, code,
+ V8_OFF_CODE_INSTRUCTION_SIZE) != 0)) {
+ code = 0;
+ ilen = 0;
+ }
+
+ if ((instr != 0 && ilen != 0) &&
+ (instr < code + V8_OFF_CODE_INSTRUCTION_START ||
+ instr >= code + V8_OFF_CODE_INSTRUCTION_START + ilen))
+ continue;
+
+ if (!showrange) {
+ mdb_printf("%?p %8d %-40s %s %s\n",
+ func->fjsf_instances.fjsi_addr,
+ func->fjsf_ninstances, func->fjsf_funcname,
+ func->fjsf_scriptname, func->fjsf_location);
+ } else {
+ uintptr_t code, ilen;
+
+ if (read_heap_ptr(&code, funcinfo,
+ V8_OFF_SHAREDFUNCTIONINFO_CODE) != 0 ||
+ read_heap_ptr(&ilen, code,
+ V8_OFF_CODE_INSTRUCTION_SIZE) != 0) {
+ mdb_printf("%?p %8d %?s %?s %-40s %s %s\n",
+ func->fjsf_instances.fjsi_addr,
+ func->fjsf_ninstances, "?", "?",
+ func->fjsf_funcname, func->fjsf_scriptname,
+ func->fjsf_location);
+ } else {
+ mdb_printf("%?p %8d %?p %?p %-40s %s %s\n",
+ func->fjsf_instances.fjsi_addr,
+ func->fjsf_ninstances,
+ code + V8_OFF_CODE_INSTRUCTION_START,
+ code + V8_OFF_CODE_INSTRUCTION_START + ilen,
+ func->fjsf_funcname, func->fjsf_scriptname,
+ func->fjsf_location);
+ }
+ }
+ }
+
return (DCMD_OK);
}
+static void
+dcmd_jsfunctions_help(void)
+{
+ mdb_printf("%s\n\n",
+"Lists JavaScript functions, optionally filtered by a substring of the\n"
+"function name or script filename or by the instruction address. This uses\n"
+"the cache created by ::findjsobjects. If ::findjsobjects has not already\n"
+"been run, this command runs it automatically without printing the output.\n"
+"This can take anywhere from a second to several minutes, depending on the\n"
+"size of the core dump.\n"
+"\n"
+"It's important to keep in mind that each time you create a function in\n"
+"JavaScript (even from a function definition that has already been used),\n"
+"the VM must create a new object to represent it. For example, if your\n"
+"program has a function A that returns a closure B, the VM will create new\n"
+"instances of the closure function (B) each time the surrounding function (A)\n"
+"is called. To show this, the output of this command consists of one line \n"
+"per function definition that appears in the JavaScript source, and the\n"
+"\"#FUNCS\" column shows how many different functions were created by VM from\n"
+"this definition.");
+
+ mdb_dec_indent(2);
+ mdb_printf("%<b>OPTIONS%</b>\n");
+ mdb_inc_indent(2);
+
+ mdb_printf("%s\n",
+" -f file List functions that were defined in a file whose name contains\n"
+" this substring.\n"
+" -n func List functions whose name contains this substring\n"
+" -x instr List functions whose compiled instructions include this address\n"
+" -X Show where the function's instructions are stored in memory\n");
+}
+
/* ARGSUSED */
static int
dcmd_v8field(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
@@ -4234,15 +5311,18 @@ dcmd_v8array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
static int
dcmd_jsstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
- uintptr_t raddr, opt_n = 5;
- boolean_t opt_v = B_FALSE;
- char *opt_f = NULL, *opt_p = NULL;
+ uintptr_t raddr;
+ jsframe_t jsf;
+
+ bzero(&jsf, sizeof (jsf));
+ jsf.jsf_nlines = 5;
if (mdb_getopts(argc, argv,
- 'v', MDB_OPT_SETBITS, B_TRUE, &opt_v,
- 'f', MDB_OPT_STR, &opt_f,
- 'n', MDB_OPT_UINTPTR, &opt_n,
- 'p', MDB_OPT_STR, &opt_p,
+ 'a', MDB_OPT_SETBITS, B_TRUE, &jsf.jsf_showall,
+ 'v', MDB_OPT_SETBITS, B_TRUE, &jsf.jsf_verbose,
+ 'f', MDB_OPT_STR, &jsf.jsf_func,
+ 'n', MDB_OPT_UINTPTR, &jsf.jsf_nlines,
+ 'p', MDB_OPT_STR, &jsf.jsf_prop,
NULL) != argc)
return (DCMD_USAGE);
@@ -4253,13 +5333,14 @@ dcmd_jsstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
*/
if (!(flags & DCMD_ADDRSPEC)) {
if (load_current_context(&addr, &raddr) != 0 ||
- do_jsframe(addr, raddr, opt_v, opt_f, opt_p, opt_n) != 0)
+ do_jsframe(addr, raddr, &jsf) != 0)
return (DCMD_ERR);
}
if (mdb_pwalk_dcmd("jsframe", "jsframe", argc, argv, addr) == -1)
return (DCMD_ERR);
+ jsframe_print_skipped(&jsf);
return (DCMD_OK);
}
@@ -4435,7 +5516,7 @@ walk_jsprop_init(mdb_walk_state_t *wsp)
jspw = mdb_zalloc(sizeof (jsprop_walk_data_t), UM_SLEEP | UM_GC);
- if (jsobj_properties(addr, walk_jsprop_nprops, jspw) == -1) {
+ if (jsobj_properties(addr, walk_jsprop_nprops, jspw, NULL) == -1) {
mdb_warn("couldn't iterate over properties for %p\n", addr);
return (WALK_ERR);
}
@@ -4443,7 +5524,7 @@ walk_jsprop_init(mdb_walk_state_t *wsp)
jspw->jspw_props = mdb_zalloc(jspw->jspw_nprops *
sizeof (uintptr_t), UM_SLEEP | UM_GC);
- if (jsobj_properties(addr, walk_jsprop_props, jspw) == -1) {
+ if (jsobj_properties(addr, walk_jsprop_props, jspw, NULL) == -1) {
mdb_warn("couldn't iterate over properties for %p\n", addr);
return (WALK_ERR);
}
@@ -4476,16 +5557,31 @@ walk_jsprop_step(mdb_walk_state_t *wsp)
static const mdb_dcmd_t v8_mdb_dcmds[] = {
/*
+ * Commands to inspect Node-level state
+ */
+ { "nodebuffer", ":[-a]",
+ "print details about the given Node Buffer", dcmd_nodebuffer },
+
+ /*
* Commands to inspect JavaScript-level state
*/
- { "jsframe", ":[-iv] [-f function] [-p property] [-n numlines]",
+ { "jsconstructor", ":[-v]",
+ "print the constructor for a JavaScript object",
+ dcmd_jsconstructor },
+ { "jsframe", ":[-aiv] [-f function] [-p property] [-n numlines]",
"summarize a JavaScript stack frame", dcmd_jsframe },
{ "jsprint", ":[-ab] [-d depth] [member]", "print a JavaScript object",
dcmd_jsprint },
- { "jsstack", "[-v] [-f function] [-p property] [-n numlines]",
+ { "jssource", ":[-n numlines]",
+ "print the source code for a JavaScript function",
+ dcmd_jssource },
+ { "jsstack", "[-av] [-f function] [-p property] [-n numlines]",
"print a JavaScript stacktrace", dcmd_jsstack },
{ "findjsobjects", "?[-vb] [-r | -c cons | -p prop]", "find JavaScript "
"objects", dcmd_findjsobjects, dcmd_findjsobjects_help },
+ { "jsfunctions", "[-X] [-s file_filter] [-n name_filter] "
+ "[-x instr_filter]", "list JavaScript functions",
+ dcmd_jsfunctions, dcmd_jsfunctions_help },
/*
* Commands to inspect V8-level state
@@ -4500,6 +5596,8 @@ static const mdb_dcmd_t v8_mdb_dcmds[] = {
"manually add a field to a given class", dcmd_v8field },
{ "v8function", ":[-d]", "print JSFunction object details",
dcmd_v8function },
+ { "v8internal", ":[fieldidx]", "print v8 object internal fields",
+ dcmd_v8internal },
{ "v8load", "version", "load canned config for a specific V8 version",
dcmd_v8load, dcmd_v8load_help },
{ "v8frametypes", NULL, "list known V8 frame types",
@@ -4534,19 +5632,24 @@ configure(void)
char *success;
v8_cfg_t *cfgp = NULL;
GElf_Sym sym;
+ int major, minor, build, patch;
- if (mdb_readsym(&v8_major, sizeof (v8_major),
+ if (mdb_readsym(&major, sizeof (major),
"_ZN2v88internal7Version6major_E") == -1 ||
- mdb_readsym(&v8_minor, sizeof (v8_minor),
+ mdb_readsym(&minor, sizeof (minor),
"_ZN2v88internal7Version6minor_E") == -1 ||
- mdb_readsym(&v8_build, sizeof (v8_build),
+ mdb_readsym(&build, sizeof (build),
"_ZN2v88internal7Version6build_E") == -1 ||
- mdb_readsym(&v8_patch, sizeof (v8_patch),
+ mdb_readsym(&patch, sizeof (patch),
"_ZN2v88internal7Version6patch_E") == -1) {
mdb_warn("failed to determine V8 version");
return;
}
+ v8_major = major;
+ v8_minor = minor;
+ v8_build = build;
+ v8_patch = patch;
mdb_printf("V8 version: %d.%d.%d.%d\n",
v8_major, v8_minor, v8_build, v8_patch);
diff --git a/usr/src/cmd/mdb/common/modules/v8/v8dbg.h b/usr/src/cmd/mdb/common/modules/v8/v8dbg.h
index 36a30a79ef..b17f241fac 100644
--- a/usr/src/cmd/mdb/common/modules/v8/v8dbg.h
+++ b/usr/src/cmd/mdb/common/modules/v8/v8dbg.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
*/
/*
@@ -42,7 +42,10 @@
* 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_FAILURE(ptr) (V8_FailureTagMask != -1 && \
+ V8_FailureTagMask != -1 && \
+ ((ptr) & V8_FailureTagMask) == V8_FailureTag)
+
#define V8_IS_HEAPOBJECT(ptr) \
(((ptr) & V8_HeapObjectTagMask) == V8_HeapObjectTag)
@@ -51,6 +54,8 @@
* using the upper 31 bits.
*/
#define V8_SMI_VALUE(smi) ((smi) >> (V8_SmiValueShift + V8_SmiShiftSize))
+#define V8_VALUE_SMI(value) \
+ ((value) << (V8_SmiValueShift + V8_SmiShiftSize))
/*
* Determine the encoding and representation of a V8 string.
@@ -80,4 +85,7 @@
#define V8_DESC_ISFIELD(x) \
((V8_SMI_VALUE(x) & V8_PROP_TYPE_MASK) == V8_PROP_TYPE_FIELD)
+#define V8_PROP_FIELDINDEX(value) \
+ ((V8_SMI_VALUE(value) & V8_FIELDINDEX_MASK) >> V8_FIELDINDEX_SHIFT)
+
#endif /* _V8DBG_H */
diff --git a/usr/src/cmd/mdb/common/modules/zfs/zfs.c b/usr/src/cmd/mdb/common/modules/zfs/zfs.c
index 225cf3dee1..21a8c956c3 100644
--- a/usr/src/cmd/mdb/common/modules/zfs/zfs.c
+++ b/usr/src/cmd/mdb/common/modules/zfs/zfs.c
@@ -449,6 +449,7 @@ blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
typedef struct mdb_dmu_buf_impl {
struct {
uint64_t db_object;
+ uintptr_t db_data;
} db;
uintptr_t db_objset;
uint64_t db_level;
@@ -1691,8 +1692,12 @@ typedef struct mdb_spa {
uintptr_t spa_root_vdev;
} mdb_spa_t;
+typedef struct mdb_dsl_pool {
+ uintptr_t dp_root_dir;
+} mdb_dsl_pool_t;
+
typedef struct mdb_dsl_dir {
- uintptr_t dd_phys;
+ uintptr_t dd_dbuf;
int64_t dd_space_towrite[TXG_SIZE];
} mdb_dsl_dir_t;
@@ -1772,11 +1777,10 @@ static int
spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
mdb_spa_t spa;
- uintptr_t dp_root_dir;
+ mdb_dsl_pool_t dp;
mdb_dsl_dir_t dd;
+ mdb_dmu_buf_impl_t db;
mdb_dsl_dir_phys_t dsp;
- uint64_t children;
- uintptr_t childaddr;
space_data_t sd;
int shift = 20;
char *suffix = "M";
@@ -1793,21 +1797,16 @@ spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
suffix = "";
}
- if (GETMEMB(addr, "spa", spa_dsl_pool, spa.spa_dsl_pool) ||
- GETMEMB(addr, "spa", spa_root_vdev, spa.spa_root_vdev) ||
- GETMEMB(spa.spa_root_vdev, "vdev", vdev_children, children) ||
- GETMEMB(spa.spa_root_vdev, "vdev", vdev_child, childaddr) ||
- GETMEMB(spa.spa_dsl_pool, "dsl_pool",
- dp_root_dir, dp_root_dir) ||
- GETMEMB(dp_root_dir, "dsl_dir", dd_phys, dd.dd_phys) ||
- GETMEMB(dp_root_dir, "dsl_dir",
- dd_space_towrite, dd.dd_space_towrite) ||
- GETMEMB(dd.dd_phys, "dsl_dir_phys",
- dd_used_bytes, dsp.dd_used_bytes) ||
- GETMEMB(dd.dd_phys, "dsl_dir_phys",
- dd_compressed_bytes, dsp.dd_compressed_bytes) ||
- GETMEMB(dd.dd_phys, "dsl_dir_phys",
- dd_uncompressed_bytes, dsp.dd_uncompressed_bytes)) {
+ if (mdb_ctf_vread(&spa, ZFS_STRUCT "spa", "mdb_spa_t",
+ addr, 0) == -1 ||
+ mdb_ctf_vread(&dp, ZFS_STRUCT "dsl_pool", "mdb_dsl_pool_t",
+ spa.spa_dsl_pool, 0) == -1 ||
+ mdb_ctf_vread(&dd, ZFS_STRUCT "dsl_dir", "mdb_dsl_dir_t",
+ dp.dp_root_dir, 0) == -1 ||
+ mdb_ctf_vread(&db, ZFS_STRUCT "dmu_buf_impl", "mdb_dmu_buf_impl_t",
+ dd.dd_dbuf, 0) == -1 ||
+ mdb_ctf_vread(&dsp, ZFS_STRUCT "dsl_dir_phys",
+ "mdb_dsl_dir_phys_t", db.db.db_data, 0) == -1) {
return (DCMD_ERR);
}
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
index 5f41df26f3..2465146a38 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c
@@ -208,7 +208,7 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
int err;
int i;
- struct {
+ struct fr {
uintptr_t fr_savfp;
uintptr_t fr_savpc;
} fr;
@@ -225,6 +225,8 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
mdb_syminfo_t sip;
mdb_ctf_funcinfo_t mfp;
int xpv_panic = 0;
+ int advance_tortoise = 1;
+ uintptr_t tortoise_fp = 0;
#ifndef _KMDB
int xp;
@@ -237,19 +239,38 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
while (fp != 0) {
int args_style = 0;
- /*
- * Ensure progress (increasing fp), and prevent
- * endless loop with the same FP.
- */
- if (fp <= lastfp) {
- err = EMDB_STKFRAME;
- goto badfp;
- }
if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) {
err = EMDB_NOMAP;
goto badfp;
}
+ if (tortoise_fp == 0) {
+ tortoise_fp = fp;
+ } else {
+ /*
+ * Advance tortoise_fp every other frame, so we detect
+ * cycles with Floyd's tortoise/hare.
+ */
+ if (advance_tortoise != 0) {
+ struct fr tfr;
+
+ if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
+ tortoise_fp) != sizeof (tfr)) {
+ err = EMDB_NOMAP;
+ goto badfp;
+ }
+
+ tortoise_fp = tfr.fr_savfp;
+ }
+
+ if (fp == tortoise_fp) {
+ err = EMDB_STKFRAME;
+ goto badfp;
+ }
+ }
+
+ advance_tortoise = !advance_tortoise;
+
if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
NULL, 0, &s, &sip) == 0) &&
(mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
index 80ce1c7ad2..d6db4811b2 100644
--- a/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_ia32util.c
@@ -197,7 +197,7 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
int got_pc = (gsp->kregs[KREG_EIP] != 0);
int err;
- struct {
+ struct fr {
uintptr_t fr_savfp;
uintptr_t fr_savpc;
long fr_argv[32];
@@ -210,6 +210,8 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
ssize_t size;
uint_t argc;
int detect_exception_frames = 0;
+ int advance_tortoise = 1;
+ uintptr_t tortoise_fp = 0;
#ifndef _KMDB
int xp;
@@ -220,15 +222,6 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
bcopy(gsp, &gregs, sizeof (gregs));
while (fp != 0) {
-
- /*
- * Ensure progress (increasing fp), and prevent
- * endless loop with the same FP.
- */
- if (fp <= lastfp) {
- err = EMDB_STKFRAME;
- goto badfp;
- }
if (fp & (STACK_ALIGN - 1)) {
err = EMDB_STKALIGN;
goto badfp;
@@ -242,6 +235,33 @@ mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
goto badfp;
}
+ if (tortoise_fp == 0) {
+ tortoise_fp = fp;
+ } else {
+ /*
+ * Advance tortoise_fp every other frame, so we detect
+ * cycles with Floyd's tortoise/hare.
+ */
+ if (advance_tortoise != 0) {
+ struct fr tfr;
+
+ if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
+ tortoise_fp) != sizeof (tfr)) {
+ err = EMDB_NOMAP;
+ goto badfp;
+ }
+
+ tortoise_fp = tfr.fr_savfp;
+ }
+
+ if (fp == tortoise_fp) {
+ err = EMDB_STKFRAME;
+ goto badfp;
+ }
+ }
+
+ advance_tortoise = !advance_tortoise;
+
if (got_pc && func(arg, pc, argc, fr.fr_argv, &gregs) != 0)
break;
diff --git a/usr/src/cmd/perl/Makefile.perl b/usr/src/cmd/perl/Makefile.perl
index 3ee32fef0f..25fdc53f50 100644
--- a/usr/src/cmd/perl/Makefile.perl
+++ b/usr/src/cmd/perl/Makefile.perl
@@ -10,17 +10,15 @@
#
#
# Copyright (c) 2014 Racktop Systems.
+# Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
#
include $(SRC)/lib/Makefile.lib
-# PERL_VERSION used to be set here,
-# but as it is also needed in usr/src/pkg/Makefile,
+# PERL_VERSION and PERL_ARCH used to be set here,
+# but as they were also needed in usr/src/pkg/Makefile,
# the definition was moved to usr/src/Makefile.master
-PERL_ARCH = i86pc-solaris-64int
-$(SPARC_BLD)PERL_ARCH = sun4-solaris-64int
-
PERLDIR = $(ADJUNCT_PROTO)/usr/perl5/$(PERL_VERSION)
PERLLIBDIR = $(PERLDIR)/lib/$(PERL_ARCH)
PERLINCDIR = $(PERLLIBDIR)/CORE
diff --git a/usr/src/cmd/perl/Makefile.targ b/usr/src/cmd/perl/Makefile.targ
index a3211dff7f..b3f5ec9bd3 100644
--- a/usr/src/cmd/perl/Makefile.targ
+++ b/usr/src/cmd/perl/Makefile.targ
@@ -10,7 +10,7 @@
#
#
# Copyright (c) 2014 Racktop Systems.
-# Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
#
# Link against libc as perl solaris specs
@@ -23,8 +23,8 @@ $(ROOTPERLEXT) := FILEMODE = 0555
$(ROOTPERLMOD) := FILEMODE = 0444
# CFLAGS for perl, specifically.
-PCFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DPERL_USE_SAFE_PUTENV \
- -D_TS_ERRNO
+PCFLAGS= -DPERL_EUPXS_ALWAYS_EXPORT -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \
+ -DPERL_USE_SAFE_PUTENV -D_TS_ERRNO
$(MACH):
$(INS.dir)
diff --git a/usr/src/cmd/ptools/pflags/pflags.c b/usr/src/cmd/ptools/pflags/pflags.c
index 8054a80d3c..f19a945d95 100644
--- a/usr/src/cmd/ptools/pflags/pflags.c
+++ b/usr/src/cmd/ptools/pflags/pflags.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#include <stdio.h>
@@ -469,6 +469,9 @@ prwhy(int why)
case PR_SUSPENDED:
str = "PR_SUSPENDED";
break;
+ case PR_BRAND:
+ str = "PR_BRAND";
+ break;
default:
str = buf;
(void) sprintf(str, "%d", why);
diff --git a/usr/src/cmd/rpcsvc/net_files/rpc b/usr/src/cmd/rpcsvc/net_files/rpc
index 9d1b728ab8..a50557dab8 100644
--- a/usr/src/cmd/rpcsvc/net_files/rpc
+++ b/usr/src/cmd/rpcsvc/net_files/rpc
@@ -1,7 +1,4 @@
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
@@ -21,9 +18,14 @@
#
# CDDL HEADER END
#
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
# rpc
#
-rpcbind 100000 portmap sunrpc rpcbind
+rpcbind 100000 portmap sunrpc
rstatd 100001 rstat rup perfmeter
rusersd 100002 rusers
nfs 100003 nfsprog
@@ -47,9 +49,9 @@ nlockmgr 100021
x25.inr 100022
statmon 100023
status 100024
+bootparam 100026
ypupdated 100028 ypupdate
keyserv 100029 keyserver
-bootparam 100026
sunlink_mapper 100033
tfsd 100037
nsed 100038
@@ -76,14 +78,16 @@ iproutes 100120 na.iproutes
layers 100121 na.layers
snmp 100122 na.snmp snmp-cmc snmp-synoptics snmp-unisys snmp-utk
traffic 100123 na.traffic
+nsm_addr 100133
ktkt_warnd 100134
+smserverd 100155
+fmd_adm 100169
+idmap 100172
nfs_acl 100227
+metad 100229
+metamhd 100230
sadmind 100232
+ufsd 100233
gssd 100234
-ufsd 100233 ufsd
+metamedd 100242
pcnfsd 150001
-metad 100229 metad
-metamhd 100230 metamhd
-metamedd 100242 metamedd
-smserverd 100155 smserverd
-idmap 100172 idmap
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index 6688c34255..f303ba6053 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1654,3 +1654,4 @@ Bugid Risk Synopsis
4270 ld(1) argument error reporting is still pretty bad
4383 libelf can't write extended sections when ELF_F_LAYOUT
4959 completely discarded merged string sections will corrupt output objects
+4996 rtld _init race leads to incorrect symbol values
diff --git a/usr/src/cmd/sgs/rtld/common/util.c b/usr/src/cmd/sgs/rtld/common/util.c
index bd80f05a37..09cabeb31b 100644
--- a/usr/src/cmd/sgs/rtld/common/util.c
+++ b/usr/src/cmd/sgs/rtld/common/util.c
@@ -628,17 +628,17 @@ is_dep_init(Rt_map *dlmp, Rt_map *clmp)
if ((dlmp == clmp) || (rtld_flags & RT_FL_INITFIRST))
return;
- rt_mutex_lock(&dlmp->rt_lock);
+ (void) rt_mutex_lock(&dlmp->rt_lock);
while (dlmp->rt_init_thread != rt_thr_self() && (FLAGS(dlmp) &
(FLG_RT_RELOCED | FLG_RT_INITCALL | FLG_RT_INITDONE)) ==
(FLG_RT_RELOCED | FLG_RT_INITCALL)) {
leave(LIST(dlmp), 0);
(void) _lwp_cond_wait(&dlmp->rt_cv, (mutex_t *)&dlmp->rt_lock);
- rt_mutex_unlock(&dlmp->rt_lock);
+ (void) rt_mutex_unlock(&dlmp->rt_lock);
(void) enter(0);
- rt_mutex_lock(&dlmp->rt_lock);
+ (void) rt_mutex_lock(&dlmp->rt_lock);
}
- rt_mutex_unlock(&dlmp->rt_lock);
+ (void) rt_mutex_unlock(&dlmp->rt_lock);
if ((FLAGS(dlmp) & (FLG_RT_RELOCED | FLG_RT_INITDONE)) ==
(FLG_RT_RELOCED | FLG_RT_INITDONE))
@@ -760,11 +760,11 @@ call_init(Rt_map **tobj, int flag)
* signifies that a .fini must be called should it exist.
* Clear the sort field for use in later .fini processing.
*/
- rt_mutex_lock(&lmp->rt_lock);
+ (void) rt_mutex_lock(&lmp->rt_lock);
FLAGS(lmp) |= FLG_RT_INITDONE;
lmp->rt_init_thread = (thread_t)0;
- _lwp_cond_broadcast(&lmp->rt_cv);
- rt_mutex_unlock(&lmp->rt_lock);
+ (void) _lwp_cond_broadcast(&lmp->rt_cv);
+ (void) rt_mutex_unlock(&lmp->rt_lock);
SORTVAL(lmp) = -1;
/*
diff --git a/usr/src/cmd/tar/Makefile b/usr/src/cmd/tar/Makefile
index 5da69ec0f9..93a02e58e0 100644
--- a/usr/src/cmd/tar/Makefile
+++ b/usr/src/cmd/tar/Makefile
@@ -37,8 +37,6 @@ LINTFLAGS += -u
LDLIBS += -lsec -lcmdutils -lnvpair -ltsol
CFLAGS += $(CCVERBOSE)
-CERRWARN += -_gcc=-Wno-unused-variable
-CERRWARN += -_gcc=-Wno-parentheses
CERRWARN += -_gcc=-Wno-uninitialized
CPPFLAGS += -DEUC
diff --git a/usr/src/cmd/tar/tar.c b/usr/src/cmd/tar/tar.c
index 9e2aef3bee..7b48e927e1 100644
--- a/usr/src/cmd/tar/tar.c
+++ b/usr/src/cmd/tar/tar.c
@@ -565,7 +565,7 @@ static char *myname;
static char *xtract_chdir = NULL;
static int checkflag = 0;
static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
-static int rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
+static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag;
static int uflag;
static int errflag;
static int oflag;
@@ -643,6 +643,8 @@ static int charset_type = 0;
static u_longlong_t xhdr_flgs; /* Bits set determine which items */
/* need to be in extended header. */
+static pid_t comp_pid = 0;
+
#define _X_DEVMAJOR 0x1
#define _X_DEVMINOR 0x2
#define _X_GID 0x4
@@ -725,8 +727,6 @@ main(int argc, char *argv[])
char *cp;
char *tmpdirp;
pid_t thispid;
- pid_t pid;
- int wstat;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
@@ -1114,10 +1114,8 @@ main(int argc, char *argv[])
if (Aflag && vflag)
(void) printf(
gettext("Suppressing absolute pathnames\n"));
- if (cflag && compress_opt != NULL) {
- pid = compress_file();
- wait_pid(pid);
- }
+ if (cflag && compress_opt != NULL)
+ comp_pid = compress_file();
dorep(argv);
if (rflag && !cflag && (compress_opt != NULL))
compress_back();
@@ -1168,10 +1166,8 @@ main(int argc, char *argv[])
if (strcmp(usefile, "-") != 0) {
check_compression();
- if (compress_opt != NULL) {
- pid = uncompress_file();
- wait_pid(pid);
- }
+ if (compress_opt != NULL)
+ comp_pid = uncompress_file();
}
if (xflag) {
if (xtract_chdir != NULL) {
@@ -4876,6 +4872,13 @@ done(int n)
exit(2);
}
}
+ /*
+ * If we have a compression child, we should have a child process that
+ * we're waiting for to finish compressing or uncompressing the tar
+ * stream.
+ */
+ if (n == 0 && comp_pid != 0)
+ wait_pid(comp_pid);
exit(n);
}
@@ -6109,7 +6112,6 @@ check_prefix(char **namep, char **dirp, char **compp)
if ((tflag || xflag) && !Pflag) {
if (is_absolute(fullname) || has_dot_dot(fullname)) {
char *stripped_prefix;
- size_t prefix_len = 0;
(void) strcpy(savename, fullname);
strcpy(fullname,
@@ -7891,7 +7893,7 @@ xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
return;
}
- while (dp = readdir(dirp)) {
+ while ((dp = readdir(dirp)) != NULL) {
if (strcmp(dp->d_name, "..") == 0) {
continue;
} else if (strcmp(dp->d_name, ".") == 0) {
@@ -9191,9 +9193,6 @@ static void
compress_back()
{
pid_t pid;
- int status;
- int wret;
- struct stat statb;
if (vflag) {
(void) fprintf(vfile,
@@ -9299,9 +9298,6 @@ void
decompress_file(void)
{
pid_t pid;
- int status;
- char cmdstr[PATH_MAX];
- char fname[PATH_MAX];
char *added_suffix;
@@ -9344,7 +9340,7 @@ compress_file(void)
if (pipe(fd) < 0) {
vperror(1, gettext("Could not create pipe"));
}
- if (pid = fork() > 0) {
+ if ((pid = fork()) > 0) {
mt = fd[1];
(void) close(fd[0]);
return (pid);
@@ -9373,7 +9369,7 @@ uncompress_file(void)
if (pipe(fd) < 0) {
vperror(1, gettext("Could not create pipe"));
}
- if (pid = fork() > 0) {
+ if ((pid = fork()) > 0) {
mt = fd[0];
(void) close(fd[1]);
return (pid);
diff --git a/usr/src/cmd/zlogin/zlogin.c b/usr/src/cmd/zlogin/zlogin.c
index 5f3972db17..909bdfda18 100644
--- a/usr/src/cmd/zlogin/zlogin.c
+++ b/usr/src/cmd/zlogin/zlogin.c
@@ -1821,6 +1821,35 @@ get_username()
return (nptr->pw_name);
}
+static boolean_t
+zlog_mode_logging(char *zonename)
+{
+ boolean_t lm = B_FALSE;
+ zone_dochandle_t handle;
+ struct zone_attrtab attr;
+
+ if ((handle = zonecfg_init_handle()) == NULL)
+ return (lm);
+
+ if (zonecfg_get_handle(zonename, handle) != Z_OK)
+ goto done;
+
+ if (zonecfg_setattrent(handle) != Z_OK)
+ goto done;
+ while (zonecfg_getattrent(handle, &attr) == Z_OK) {
+ if (strcmp("zlog-mode", attr.zone_attr_name) == 0) {
+ if (strncmp("log", attr.zone_attr_value, 3) == 0)
+ lm = B_TRUE;
+ break;
+ }
+ }
+ (void) zonecfg_endattrent(handle);
+
+done:
+ zonecfg_fini_handle(handle);
+ return (lm);
+}
+
int
main(int argc, char **argv)
{
@@ -2056,6 +2085,10 @@ main(int argc, char **argv)
*/
if (console) {
int gz_stderr_fd = -1;
+ boolean_t set_raw = B_TRUE;
+
+ if (imode && zlog_mode_logging(zonename))
+ set_raw = B_FALSE;
/*
* Ensure that zoneadmd for this zone is running.
@@ -2082,7 +2115,7 @@ main(int argc, char **argv)
"console]\n"), zonename);
}
- if (set_tty_rawmode(STDIN_FILENO) == -1) {
+ if (set_raw && set_tty_rawmode(STDIN_FILENO) == -1) {
reset_tty();
zperror(gettext("failed to set stdin pty to raw mode"));
return (1);
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 5a86b1cf50..522de5b779 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014, Joyent Inc. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
*/
/*
@@ -163,6 +163,19 @@ static priv_set_t *zprivs = NULL;
static const char *DFLT_FS_ALLOWED = "hsfs,smbfs,nfs,nfs3,nfs4,nfsdyn";
+typedef struct zone_proj_rctl_map {
+ char *zpr_zone_rctl;
+ char *zpr_project_rctl;
+} zone_proj_rctl_map_t;
+
+static zone_proj_rctl_map_t zone_proj_rctl_map[] = {
+ {"zone.max-msg-ids", "project.max-msg-ids"},
+ {"zone.max-sem-ids", "project.max-sem-ids"},
+ {"zone.max-shm-ids", "project.max-shm-ids"},
+ {"zone.max-shm-memory", "project.max-shm-memory"},
+ {NULL, NULL}
+};
+
/* from libsocket, not in any header file */
extern int getnetmaskbyaddr(struct in_addr, struct in_addr *);
@@ -3245,6 +3258,19 @@ get_privset(zlog_t *zlogp, priv_set_t *privs, zone_mnt_t mount_cmd)
return (error);
}
+static char *
+zone_proj_rctl(const char *name)
+{
+ int i;
+
+ for (i = 0; zone_proj_rctl_map[i].zpr_zone_rctl != NULL; i++) {
+ if (strcmp(name, zone_proj_rctl_map[i].zpr_zone_rctl) == 0) {
+ return (zone_proj_rctl_map[i].zpr_project_rctl);
+ }
+ }
+ return (NULL);
+}
+
static int
get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
{
@@ -3298,6 +3324,7 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
struct zone_rctlvaltab *rctlval;
uint_t i, count;
const char *name = rctltab.zone_rctl_name;
+ char *proj_nm;
/* zoneadm should have already warned about unknown rctls. */
if (!zonecfg_is_rctl(name)) {
@@ -3364,6 +3391,26 @@ get_rctls(zlog_t *zlogp, char **bufp, size_t *bufsizep)
}
zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
rctltab.zone_rctl_valptr = NULL;
+
+ /*
+ * With no action on our part we will start zsched with the
+ * project rctl values for our (zoneadmd) current project. For
+ * brands running a variant of Illumos, that's not a problem
+ * since they will setup their own projects, but for a
+ * non-native brand like lx, where there are no projects, we
+ * want to start things up with the same project rctls as the
+ * corresponding zone rctls, since nothing within the zone will
+ * ever change the project rctls.
+ */
+ if ((proj_nm = zone_proj_rctl(name)) != NULL) {
+ if (nvlist_add_nvlist_array(nvl, proj_nm, nvlv, count)
+ != 0) {
+ zerror(zlogp, B_FALSE,
+ "nvlist_add_nvlist_arrays failed");
+ goto out;
+ }
+ }
+
if (nvlist_add_nvlist_array(nvl, (char *)name, nvlv, count)
!= 0) {
zerror(zlogp, B_FALSE, "%s failed",