summaryrefslogtreecommitdiff
path: root/usr/src/uts
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts')
-rw-r--r--usr/src/uts/common/io/dump.c22
-rw-r--r--usr/src/uts/common/io/sysevent.c119
-rw-r--r--usr/src/uts/common/os/dumpsubr.c101
-rw-r--r--usr/src/uts/common/os/evchannels.c81
-rw-r--r--usr/src/uts/common/os/fm.c14
-rw-r--r--usr/src/uts/common/os/log_sysevent.c45
-rw-r--r--usr/src/uts/common/os/panic.c3
-rw-r--r--usr/src/uts/common/sys/dumpadm.h12
-rw-r--r--usr/src/uts/common/sys/dumphdr.h10
-rw-r--r--usr/src/uts/common/sys/fm/protocol.h31
-rw-r--r--usr/src/uts/common/sys/fm/util.h6
-rw-r--r--usr/src/uts/common/sys/nvpair.h5
-rw-r--r--usr/src/uts/common/sys/panic.h20
-rw-r--r--usr/src/uts/common/sys/sysevent.h5
-rw-r--r--usr/src/uts/common/sys/sysevent_impl.h77
-rw-r--r--usr/src/uts/intel/ia32/os/archdep.c80
-rw-r--r--usr/src/uts/sparc/os/archdep.c65
17 files changed, 601 insertions, 95 deletions
diff --git a/usr/src/uts/common/io/dump.c b/usr/src/uts/common/io/dump.c
index 18c3c1a3d1..70a61bf9b8 100644
--- a/usr/src/uts/common/io/dump.c
+++ b/usr/src/uts/common/io/dump.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -95,6 +94,8 @@ dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
uint64_t dumpsize_in_pages;
int error = 0;
char *pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ char uuidbuf[36 + 1];
+ size_t len;
vnode_t *vp;
switch (cmd) {
@@ -190,6 +191,23 @@ dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
mutex_exit(&dump_lock);
break;
+ case DIOCSETUUID:
+ if ((error = copyinstr((char *)arg, uuidbuf, sizeof (uuidbuf),
+ &len)) != 0)
+ break;
+
+ if (len != 37) {
+ error = EINVAL;
+ break;
+ }
+
+ error = dump_set_uuid(uuidbuf);
+ break;
+
+ case DIOCGETUUID:
+ error = copyoutstr(dump_get_uuid(), (void *)arg, 37, NULL);
+ break;
+
default:
error = ENXIO;
}
diff --git a/usr/src/uts/common/io/sysevent.c b/usr/src/uts/common/io/sysevent.c
index f2cead970e..69065b9506 100644
--- a/usr/src/uts/common/io/sysevent.c
+++ b/usr/src/uts/common/io/sysevent.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -471,6 +470,116 @@ sysevent_chandata(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
return (rc);
}
+/* ARGSUSED */
+static int
+sysevent_setpropnvl(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
+{
+ sev_propnvl_args_t uargs;
+ nvlist_t *nvl = NULL;
+ evchan_ctl_t *ctl;
+ size_t bufsz;
+ char *buf;
+
+ ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
+ if (ctl == NULL || ctl->chp == NULL)
+ return (ENXIO);
+
+ if (copyin(arg, &uargs, sizeof (uargs)) != 0)
+ return (EFAULT);
+
+ if (uargs.packednvl.name != 0) {
+ bufsz = uargs.packednvl.len;
+
+ if (bufsz == 0)
+ return (EINVAL);
+
+ if (bufsz > EVCH_MAX_DATA_SIZE)
+ return (EOVERFLOW);
+
+ buf = kmem_alloc(bufsz, KM_SLEEP);
+
+ if (copyin((void *)(uintptr_t)uargs.packednvl.name, buf,
+ bufsz) != 0 ||
+ nvlist_unpack(buf, bufsz, &nvl, KM_SLEEP) != 0) {
+ kmem_free(buf, bufsz);
+ return (EFAULT);
+ }
+
+ kmem_free(buf, bufsz);
+
+ if (nvl == NULL)
+ return (EINVAL);
+ }
+
+ evch_usrsetpropnvl(ctl->chp, nvl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+sysevent_getpropnvl(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
+{
+ sev_propnvl_args_t uargs;
+ size_t reqsz, avlsz;
+ evchan_ctl_t *ctl;
+ nvlist_t *nvl;
+ int64_t gen;
+ int rc;
+
+ ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
+
+ if (ctl == NULL || ctl->chp == NULL)
+ return (ENXIO);
+
+ if (copyin(arg, &uargs, sizeof (uargs)) != 0)
+ return (EFAULT);
+
+ if ((rc = evch_usrgetpropnvl(ctl->chp, &nvl, &gen)) != 0)
+ return (rc);
+
+ if (nvl != NULL) {
+ avlsz = uargs.packednvl.len;
+
+ if (nvlist_size(nvl, &reqsz, NV_ENCODE_NATIVE) != 0) {
+ nvlist_free(nvl);
+ return (EINVAL);
+ }
+
+ if (reqsz > EVCH_MAX_DATA_SIZE) {
+ nvlist_free(nvl);
+ return (E2BIG);
+ }
+
+ if (reqsz <= avlsz) {
+ char *buf = kmem_alloc(reqsz, KM_SLEEP);
+
+ if (nvlist_pack(nvl, &buf, &reqsz,
+ NV_ENCODE_NATIVE, 0) != 0 || copyout(buf,
+ (void *)(uintptr_t)uargs.packednvl.name,
+ reqsz) != 0) {
+ kmem_free(buf, reqsz);
+ nvlist_free(nvl);
+ return (EFAULT);
+ }
+ kmem_free(buf, reqsz);
+ rc = 0;
+ } else {
+ rc = EOVERFLOW;
+ }
+ uargs.packednvl.len = (uint32_t)reqsz;
+ nvlist_free(nvl);
+ } else {
+ uargs.packednvl.len = 0;
+ rc = 0;
+ }
+
+ uargs.generation = gen;
+ if (copyout((void *)&uargs, arg, sizeof (uargs)) != 0)
+ rc = EFAULT;
+
+ return (rc);
+}
+
/*ARGSUSED*/
static int
sysevent_ioctl(dev_t dev, int cmd, intptr_t arg,
@@ -500,6 +609,12 @@ sysevent_ioctl(dev_t dev, int cmd, intptr_t arg,
case SEV_CHANDATA:
rc = sysevent_chandata(dev, rvalp, (void *)arg, flag, cr);
break;
+ case SEV_SETPROPNVL:
+ rc = sysevent_setpropnvl(dev, rvalp, (void *)arg, flag, cr);
+ break;
+ case SEV_GETPROPNVL:
+ rc = sysevent_getpropnvl(dev, rvalp, (void *)arg, flag, cr);
+ break;
default:
rc = EINVAL;
}
diff --git a/usr/src/uts/common/os/dumpsubr.c b/usr/src/uts/common/os/dumpsubr.c
index 1c766842de..0ae9c3d390 100644
--- a/usr/src/uts/common/os/dumpsubr.c
+++ b/usr/src/uts/common/os/dumpsubr.c
@@ -107,6 +107,7 @@ int dump_timeout = 120; /* timeout for dumping pages */
int dump_timeleft; /* portion of dump_timeout remaining */
int dump_ioerr; /* dump i/o error */
int dump_check_used; /* enable check for used pages */
+char *dump_stack_scratch; /* scratch area for saving stack summary */
/*
* Tunables for dump compression and parallelism. These can be set via
@@ -258,6 +259,12 @@ struct cbuf {
int off; /* byte offset to first pfn */
};
+static char dump_osimage_uuid[36 + 1];
+
+#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
+#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
+ ((ch) >= 'A' && (ch) <= 'F'))
+
/*
* cqueue_t queues: a uni-directional channel for communication
* from the master to helper tasks or vice-versa using put and
@@ -1103,6 +1110,9 @@ dumphdr_init(void)
dumpcfg.pids = kmem_alloc(v.v_proc * sizeof (pid_t), KM_SLEEP);
dumpcfg.helpermap = kmem_zalloc(BT_SIZEOFMAP(NCPU), KM_SLEEP);
LOCK_INIT_HELD(&dumpcfg.helper_lock);
+ dump_stack_scratch = kmem_alloc(STACK_BUF_SIZE, KM_SLEEP);
+ (void) strncpy(dumphdr->dump_uuid, dump_get_uuid(),
+ sizeof (dumphdr->dump_uuid));
}
npages = num_phys_pages();
@@ -1436,6 +1446,48 @@ dump_process(pid_t pid)
return (0);
}
+/*
+ * The following functions (dump_summary(), dump_ereports(), and
+ * dump_messages()), write data to an uncompressed area within the
+ * crashdump. The layout of these is
+ *
+ * +------------------------------------------------------------+
+ * | compressed pages | summary | ereports | messages |
+ * +------------------------------------------------------------+
+ *
+ * With the advent of saving a compressed crash dump by default, we
+ * need to save a little more data to describe the failure mode in
+ * an uncompressed buffer available before savecore uncompresses
+ * the dump. Initially this is a copy of the stack trace. Additional
+ * summary information should be added here.
+ */
+
+void
+dump_summary(void)
+{
+ u_offset_t dumpvp_start;
+ summary_dump_t sd;
+
+ if (dumpvp == NULL || dumphdr == NULL)
+ return;
+
+ dumpbuf.cur = dumpbuf.start;
+
+ dumpbuf.vp_limit = dumpvp_size - (DUMP_OFFSET + DUMP_LOGSIZE +
+ DUMP_ERPTSIZE);
+ dumpvp_start = dumpbuf.vp_limit - DUMP_SUMMARYSIZE;
+ dumpbuf.vp_off = dumpvp_start;
+
+ sd.sd_magic = SUMMARY_MAGIC;
+ sd.sd_ssum = checksum32(dump_stack_scratch, STACK_BUF_SIZE);
+ dumpvp_write(&sd, sizeof (sd));
+ dumpvp_write(dump_stack_scratch, STACK_BUF_SIZE);
+
+ sd.sd_magic = 0; /* indicate end of summary */
+ dumpvp_write(&sd, sizeof (sd));
+ (void) dumpvp_flush();
+}
+
void
dump_ereports(void)
{
@@ -2859,6 +2911,10 @@ dumpsys(void)
size -= datahdr.dump_metrics;
}
+ /* record in the header whether this is a fault-management panic */
+ if (panicstr)
+ dumphdr->dump_fm_panic = is_fm_panic();
+
/* compression info in data header */
datahdr.dump_datahdr_magic = DUMP_DATAHDR_MAGIC;
datahdr.dump_datahdr_version = DUMP_DATAHDR_VERSION;
@@ -2905,6 +2961,7 @@ dumpsys(void)
* thing we do because the dump process itself emits messages.
*/
if (panicstr) {
+ dump_summary();
dump_ereports();
dump_messages();
}
@@ -2967,3 +3024,47 @@ dumpvp_resize()
mutex_exit(&dump_lock);
return (0);
}
+
+int
+dump_set_uuid(const char *uuidstr)
+{
+ const char *ptr;
+ int i;
+
+ if (uuidstr == NULL || strnlen(uuidstr, 36 + 1) != 36)
+ return (EINVAL);
+
+ /* uuid_parse is not common code so check manually */
+ for (i = 0, ptr = uuidstr; i < 36; i++, ptr++) {
+ switch (i) {
+ case 8:
+ case 13:
+ case 18:
+ case 23:
+ if (*ptr != '-')
+ return (EINVAL);
+ break;
+
+ default:
+ if (!isxdigit(*ptr))
+ return (EINVAL);
+ break;
+ }
+ }
+
+ if (dump_osimage_uuid[0] != '\0')
+ return (EALREADY);
+
+ (void) strncpy(dump_osimage_uuid, uuidstr, 36 + 1);
+
+ cmn_err(CE_CONT, "?This Solaris instance has UUID %s",
+ dump_osimage_uuid);
+
+ return (0);
+}
+
+const char *
+dump_get_uuid(void)
+{
+ return (dump_osimage_uuid[0] != '\0' ? dump_osimage_uuid : "");
+}
diff --git a/usr/src/uts/common/os/evchannels.c b/usr/src/uts/common/os/evchannels.c
index 9ae0565244..e34af700ca 100644
--- a/usr/src/uts/common/os/evchannels.c
+++ b/usr/src/uts/common/os/evchannels.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -1165,6 +1164,8 @@ evch_chunbind(evch_bind_t *bp)
mutex_exit(&chp->ch_mutex);
evch_dl_del(&eg->evch_list, &chp->ch_link);
evch_evq_destroy(chp->ch_queue);
+ if (chp->ch_propnvl)
+ nvlist_free(chp->ch_propnvl);
mutex_destroy(&chp->ch_mutex);
mutex_destroy(&chp->ch_pubmx);
cv_destroy(&chp->ch_pubcv);
@@ -1564,6 +1565,47 @@ evch_chgetchdata(char *chname, void *buf, size_t size)
return (chdlen + buflen);
}
+static void
+evch_chsetpropnvl(evch_bind_t *bp, nvlist_t *nvl)
+{
+ evch_chan_t *chp = bp->bd_channel;
+
+ mutex_enter(&chp->ch_mutex);
+
+ if (chp->ch_propnvl)
+ nvlist_free(chp->ch_propnvl);
+
+ chp->ch_propnvl = nvl;
+ chp->ch_propnvlgen++;
+
+ mutex_exit(&chp->ch_mutex);
+}
+
+static int
+evch_chgetpropnvl(evch_bind_t *bp, nvlist_t **nvlp, int64_t *genp)
+{
+ evch_chan_t *chp = bp->bd_channel;
+ int rc = 0;
+
+ mutex_enter(&chp->ch_mutex);
+
+ if (chp->ch_propnvl != NULL)
+ rc = (nvlist_dup(chp->ch_propnvl, nvlp, 0) == 0) ? 0 : ENOMEM;
+ else
+ *nvlp = NULL; /* rc still 0 */
+
+ if (genp)
+ *genp = chp->ch_propnvlgen;
+
+ mutex_exit(&chp->ch_mutex);
+
+ if (rc != 0)
+ *nvlp = NULL;
+
+ return (rc);
+
+}
+
/*
* Init iteration of all events of a channel. This function creates a new
* event queue and puts all events from the channel into that queue.
@@ -1718,6 +1760,8 @@ evch_chgetnextev(evchanq_t *snp)
* sysevent_evc_unsubscribe - Unsubscribe from an event class
* sysevent_evc_publish - Publish an event to an event channel
* sysevent_evc_control - Various control operation on event channel
+ * sysevent_evc_setpropnvl - Set channel property nvlist
+ * sysevent_evc_getpropnvl - Get channel property nvlist
*
* The function below are for evaluating a sysevent:
*
@@ -1971,6 +2015,25 @@ sysevent_evc_control(evchan_t *scp, int cmd, ...)
return (rc);
}
+int
+sysevent_evc_setpropnvl(evchan_t *scp, nvlist_t *nvl)
+{
+ nvlist_t *nvlcp = nvl;
+
+ if (nvl != NULL && nvlist_dup(nvl, &nvlcp, 0) != 0)
+ return (ENOMEM);
+
+ evch_chsetpropnvl((evch_bind_t *)scp, nvlcp);
+
+ return (0);
+}
+
+int
+sysevent_evc_getpropnvl(evchan_t *scp, nvlist_t **nvlp)
+{
+ return (evch_chgetpropnvl((evch_bind_t *)scp, nvlp, NULL));
+}
+
/*
* Project private interface to take a snapshot of all events of the
* specified event channel. Argument subscr may be a subscriber id, the empty
@@ -2130,6 +2193,8 @@ sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
* evch_usrcontrol_get - Get channel properties
* evch_usrgetchnames - Get list of channel names
* evch_usrgetchdata - Get data of an event channel
+ * evch_usrsetpropnvl - Set channel properties nvlist
+ * evch_usrgetpropnvl - Get channel properties nvlist
*/
evchan_t *
evch_usrchanopen(const char *name, uint32_t flags, int *err)
@@ -2267,3 +2332,15 @@ evch_usrgetchdata(char *chname, void *buf, size_t size)
{
return (evch_chgetchdata(chname, buf, size));
}
+
+void
+evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl)
+{
+ evch_chsetpropnvl((evch_bind_t *)bp, nvl);
+}
+
+int
+evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp)
+{
+ return (evch_chgetpropnvl((evch_bind_t *)bp, nvlp, genp));
+}
diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c
index 4d1754970b..4efcff4f46 100644
--- a/usr/src/uts/common/os/fm.c
+++ b/usr/src/uts/common/os/fm.c
@@ -384,6 +384,20 @@ fm_panic(const char *format, ...)
}
/*
+ * Simply tell the caller if fm_panicstr is set, ie. an fma event has
+ * caused the panic. If so, something other than the default panic
+ * diagnosis method will diagnose the cause of the panic.
+ */
+int
+is_fm_panic()
+{
+ if (fm_panicstr)
+ return (1);
+ else
+ return (0);
+}
+
+/*
* Print any appropriate FMA banner message before the panic message. This
* function is called by panicsys() and prints the message for fm_panic().
* We print the message here so that it comes after the system is quiesced.
diff --git a/usr/src/uts/common/os/log_sysevent.c b/usr/src/uts/common/os/log_sysevent.c
index 4f40a30530..8923136f98 100644
--- a/usr/src/uts/common/os/log_sysevent.c
+++ b/usr/src/uts/common/os/log_sysevent.c
@@ -19,12 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/stropts.h>
@@ -280,11 +277,11 @@ log_event_upcall(log_event_upcall_arg_t *arg)
}
if (retry > 4) {
LOG_DEBUG((CE_CONT,
- "log_event_upcall: ebadf\n"));
+ "log_event_upcall: ebadf\n"));
return (EBADF);
}
LOG_DEBUG((CE_CONT, "log_event_upcall: "
- "retrying upcall after lookup\n"));
+ "retrying upcall after lookup\n"));
darg = save_arg;
break;
default:
@@ -297,14 +294,14 @@ log_event_upcall(log_event_upcall_arg_t *arg)
if (neagain > 0 || neintr > 0) {
LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n",
- neagain, neintr, nticks));
+ neagain, neintr, nticks));
}
LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t"
- "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n",
- error, (void *)arg, (void *)darg.rbuf,
- (void *)darg.data_ptr,
- *((int *)(darg.rbuf)), *((int *)(darg.data_ptr))));
+ "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n",
+ error, (void *)arg, (void *)darg.rbuf,
+ (void *)darg.data_ptr,
+ *((int *)(darg.rbuf)), *((int *)(darg.data_ptr))));
if (!error) {
/*
@@ -334,7 +331,7 @@ log_event_deliver()
callb_cpr_t cprinfo;
CALLB_CPR_INIT(&cprinfo, &eventq_head_mutex, callb_generic_cpr,
- "logevent");
+ "logevent");
/*
* eventq_head_mutex is exited (released) when there are no more
@@ -440,7 +437,7 @@ log_event_deliver()
break;
default:
LOG_DEBUG((CE_CONT, "log_event_deliver: "
- "upcall err %d\n", upcall_err));
+ "upcall err %d\n", upcall_err));
sysevent_upcall_status = upcall_err;
/*
* Signal everyone waiting that transport is down
@@ -521,8 +518,8 @@ sysevent_alloc(char *class, char *subclass, char *pub, int flag)
aligned_pub_sz = SE_ALIGN(pub_sz);
payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
- (aligned_subclass_sz - sizeof (uint64_t)) +
- (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t);
+ (aligned_subclass_sz - sizeof (uint64_t)) +
+ (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t);
/*
* Allocate event buffer plus additional sysevent queue
@@ -1611,7 +1608,7 @@ log_sysevent_filename(char *file)
/* Unbind old event door */
if (logevent_door_upcall_filename) {
kmem_free(logevent_door_upcall_filename,
- logevent_door_upcall_filename_size);
+ logevent_door_upcall_filename_size);
if (event_door) {
door_ki_rele(event_door);
event_door = NULL;
@@ -1619,7 +1616,7 @@ log_sysevent_filename(char *file)
}
logevent_door_upcall_filename_size = strlen(file) + 1;
logevent_door_upcall_filename = kmem_alloc(
- logevent_door_upcall_filename_size, KM_SLEEP);
+ logevent_door_upcall_filename_size, KM_SLEEP);
(void) strcpy(logevent_door_upcall_filename, file);
/*
@@ -1698,7 +1695,7 @@ restart:
/* Time stamp and assign ID */
SE_SEQ(ev) = eid->eid_seq = atomic_add_64_nv(&kernel_event_id,
- (uint64_t)1);
+ (uint64_t)1);
SE_TIME(ev) = eid->eid_ts = gethrtime();
LOG_DEBUG1((CE_CONT, "log_sysevent: class=%d type=%d id=0x%llx\n",
@@ -1756,7 +1753,7 @@ log_sysevent(sysevent_t *ev, int flag, sysevent_id_t *eid)
}
rval = queue_sysevent(ev_copy, eid, flag);
ASSERT(rval == 0 || rval == SE_ENOMEM || rval == SE_EQSIZE ||
- rval == SE_NO_TRANSPORT);
+ rval == SE_NO_TRANSPORT);
ASSERT(!(flag == SE_SLEEP && (rval == SE_EQSIZE || rval == SE_ENOMEM)));
return (rval);
}
@@ -1775,7 +1772,7 @@ log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid)
log_eventq_t *qcopy;
copy_sz = ev_size + offsetof(log_eventq_t, arg) +
- offsetof(log_event_upcall_arg_t, buf);
+ offsetof(log_event_upcall_arg_t, buf);
qcopy = kmem_zalloc(copy_sz, KM_SLEEP);
ev_copy = (sysevent_t *)&qcopy->arg.buf;
@@ -1825,8 +1822,8 @@ ddi_log_sysevent(
if (sleep_flag == DDI_SLEEP && servicing_interrupt()) {
cmn_err(CE_NOTE, "!ddi_log_syevent: driver %s%d - cannot queue "
- "event from interrupt context with sleep semantics\n",
- ddi_driver_name(dip), ddi_get_instance(dip));
+ "event from interrupt context with sleep semantics\n",
+ ddi_driver_name(dip), ddi_get_instance(dip));
return (DDI_ECONTEXT);
}
@@ -1836,7 +1833,7 @@ ddi_log_sysevent(
publisher = pubstr;
} else {
publisher = kmem_alloc(n,
- (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
+ (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
if (publisher == NULL) {
return (DDI_ENOMEM);
}
@@ -1880,7 +1877,7 @@ ddi_log_sysevent(
}
uint64_t
-log_sysevent_new_id()
+log_sysevent_new_id(void)
{
return (atomic_add_64_nv(&kernel_event_id, (uint64_t)1));
}
diff --git a/usr/src/uts/common/os/panic.c b/usr/src/uts/common/os/panic.c
index 469d9362ba..3985353ff7 100644
--- a/usr/src/uts/common/os/panic.c
+++ b/usr/src/uts/common/os/panic.c
@@ -256,6 +256,9 @@ panicsys(const char *format, va_list alist, struct regs *rp, int on_panic_stack)
pdp->pd_version = PANICBUFVERS;
pdp->pd_msgoff = sizeof (panic_data_t) - sizeof (panic_nv_t);
+ (void) strncpy(pdp->pd_uuid, dump_get_uuid(),
+ sizeof (pdp->pd_uuid));
+
if (t->t_panic_trap != NULL)
panic_savetrap(pdp, t->t_panic_trap);
else
diff --git a/usr/src/uts/common/sys/dumpadm.h b/usr/src/uts/common/sys/dumpadm.h
index 679ca04005..4e3704985d 100644
--- a/usr/src/uts/common/sys/dumpadm.h
+++ b/usr/src/uts/common/sys/dumpadm.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,15 +19,12 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1998-2000 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_DUMPADM_H
#define _SYS_DUMPADM_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -44,6 +40,8 @@ extern "C" {
#define DIOCSETDEV (DDIOC | 0x14)
#define DIOCTRYDEV (DDIOC | 0x15)
#define DIOCDUMP (DDIOC | 0x16)
+#define DIOCSETUUID (DDIOC | 0x17)
+#define DIOCGETUUID (DDIOC | 0x18)
/*
* Kernel-controlled dump state flags for dump_conflags
diff --git a/usr/src/uts/common/sys/dumphdr.h b/usr/src/uts/common/sys/dumphdr.h
index 5fc27bf44e..e0f2b1aebd 100644
--- a/usr/src/uts/common/sys/dumphdr.h
+++ b/usr/src/uts/common/sys/dumphdr.h
@@ -43,7 +43,7 @@ extern "C" {
* overwritten by swap activity. See dumpadm(1M) for dump configuration.
*/
#define DUMP_MAGIC 0xdefec8edU /* dump magic number */
-#define DUMP_VERSION 9 /* version of this dumphdr */
+#define DUMP_VERSION 10 /* version of this dumphdr */
#define DUMP_WORDSIZE (sizeof (long) * NBBY) /* word size (32 or 64) */
#define DUMP_PANICSIZE 200 /* Max panic string copied */
#define DUMP_COMPRESS_RATIO 2 /* conservative; usually 2.5+ */
@@ -54,6 +54,10 @@ extern "C" {
(ERPT_EVCH_MAX + \
ERPT_MAX_ERRS * ERPT_HIWAT), \
DUMP_OFFSET)) /* ereport save area */
+#define DUMP_SUMMARYSIZE (P2ROUNDUP( \
+ (STACK_BUF_SIZE + \
+ sizeof (summary_dump_t) + 1024), \
+ DUMP_OFFSET)) /* summary save area */
typedef struct dumphdr {
uint32_t dump_magic; /* magic number */
@@ -76,6 +80,8 @@ typedef struct dumphdr {
pgcnt_t dump_npages; /* number of data pages */
size_t dump_ksyms_size; /* kernel symbol table size */
size_t dump_ksyms_csize; /* compressed symbol table size */
+ uint32_t dump_fm_panic; /* initiated from fm subsystems */
+ char dump_uuid[36 + 1]; /* os image uuid */
} dumphdr_t;
/*
@@ -190,6 +196,8 @@ extern int dumpvp_resize(void);
extern int dump_plat_addr(void);
extern void dump_plat_pfn(void);
extern int dump_plat_data(void *);
+extern int dump_set_uuid(const char *);
+extern const char *dump_get_uuid(void);
/*
* Define a CPU count threshold that determines when to employ
diff --git a/usr/src/uts/common/sys/fm/protocol.h b/usr/src/uts/common/sys/fm/protocol.h
index c4103c48a4..5eca760dad 100644
--- a/usr/src/uts/common/sys/fm/protocol.h
+++ b/usr/src/uts/common/sys/fm/protocol.h
@@ -43,12 +43,13 @@ extern "C" {
#define FM_CLASS "class"
#define FM_VERSION "version"
-/* FM event class values */
+/* FM protocol category 1 class names */
#define FM_EREPORT_CLASS "ereport"
#define FM_FAULT_CLASS "fault"
#define FM_DEFECT_CLASS "defect"
#define FM_RSRC_CLASS "resource"
#define FM_LIST_EVENT "list"
+#define FM_IREPORT_CLASS "ireport"
/* FM list.* event class values */
#define FM_LIST_SUSPECT_CLASS FM_LIST_EVENT ".suspect"
@@ -72,6 +73,12 @@ extern "C" {
/* list.* event payload member names */
#define FM_LIST_EVENT_SIZE "list-sz"
+/* ireport.* event payload member names */
+#define FM_IREPORT_DETECTOR "detector"
+#define FM_IREPORT_UUID "uuid"
+#define FM_IREPORT_PRIORITY "pri"
+#define FM_IREPORT_ATTRIBUTES "attr"
+
/*
* list.suspect, isolated, updated, repaired and resolved
* versions/payload member names.
@@ -192,6 +199,7 @@ extern "C" {
#define FM_FMRI_SCHEME_PKG "pkg"
#define FM_FMRI_SCHEME_LEGACY "legacy-hc"
#define FM_FMRI_SCHEME_ZFS "zfs"
+#define FM_FMRI_SCHEME_SW "sw"
/* Scheme versions */
#define FMD_SCHEME_VERSION0 0
@@ -215,6 +223,8 @@ extern "C" {
#define FM_SVC_SCHEME_VERSION SVC_SCHEME_VERSION0
#define ZFS_SCHEME_VERSION0 0
#define FM_ZFS_SCHEME_VERSION ZFS_SCHEME_VERSION0
+#define SW_SCHEME_VERSION0 0
+#define FM_SW_SCHEME_VERSION SW_SCHEME_VERSION0
/* hc scheme member names */
#define FM_FMRI_HC_SERIAL_ID "serial"
@@ -299,6 +309,25 @@ extern "C" {
#define FM_FMRI_ZFS_POOL "pool"
#define FM_FMRI_ZFS_VDEV "vdev"
+/* sw scheme member names - extra indentation for members of an nvlist */
+#define FM_FMRI_SW_OBJ "object"
+#define FM_FMRI_SW_OBJ_PATH "path"
+#define FM_FMRI_SW_OBJ_ROOT "root"
+#define FM_FMRI_SW_OBJ_PKG "pkg"
+#define FM_FMRI_SW_SITE "site"
+#define FM_FMRI_SW_SITE_TOKEN "token"
+#define FM_FMRI_SW_SITE_MODULE "module"
+#define FM_FMRI_SW_SITE_FILE "file"
+#define FM_FMRI_SW_SITE_LINE "line"
+#define FM_FMRI_SW_SITE_FUNC "func"
+#define FM_FMRI_SW_CTXT "context"
+#define FM_FMRI_SW_CTXT_ORIGIN "origin"
+#define FM_FMRI_SW_CTXT_EXECNAME "execname"
+#define FM_FMRI_SW_CTXT_PID "pid"
+#define FM_FMRI_SW_CTXT_ZONE "zone"
+#define FM_FMRI_SW_CTXT_CTID "ctid"
+#define FM_FMRI_SW_CTXT_STACK "stack"
+
extern nv_alloc_t *fm_nva_xcreate(char *, size_t);
extern void fm_nva_xdestroy(nv_alloc_t *);
diff --git a/usr/src/uts/common/sys/fm/util.h b/usr/src/uts/common/sys/fm/util.h
index 4934814d86..37334101b3 100644
--- a/usr/src/uts/common/sys/fm/util.h
+++ b/usr/src/uts/common/sys/fm/util.h
@@ -20,15 +20,12 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_FM_UTIL_H
#define _SYS_FM_UTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -96,6 +93,7 @@ extern void fm_ereport_post(nvlist_t *, int);
extern void fm_payload_stack_add(nvlist_t *, const pc_t *, int);
+extern int is_fm_panic();
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/nvpair.h b/usr/src/uts/common/sys/nvpair.h
index 58037b0653..30ff4e0667 100644
--- a/usr/src/uts/common/sys/nvpair.h
+++ b/usr/src/uts/common/sys/nvpair.h
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_NVPAIR_H
@@ -158,6 +157,8 @@ int nvlist_unpack(char *, size_t, nvlist_t **, int);
int nvlist_dup(nvlist_t *, nvlist_t **, int);
int nvlist_merge(nvlist_t *, nvlist_t *, int);
+uint_t nvlist_nvflag(nvlist_t *);
+
int nvlist_xalloc(nvlist_t **, uint_t, nv_alloc_t *);
int nvlist_xpack(nvlist_t *, char **, size_t *, int, nv_alloc_t *);
int nvlist_xunpack(char *, size_t, nvlist_t **, nv_alloc_t *);
diff --git a/usr/src/uts/common/sys/panic.h b/usr/src/uts/common/sys/panic.h
index 9dd04a0626..1fa00f5f5a 100644
--- a/usr/src/uts/common/sys/panic.h
+++ b/usr/src/uts/common/sys/panic.h
@@ -19,15 +19,12 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_PANIC_H
#define _SYS_PANIC_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#if !defined(_ASM)
#include <sys/types.h>
#include <sys/thread.h>
@@ -45,10 +42,13 @@ extern "C" {
#endif
#define PANICBUFSIZE 8192
-#define PANICBUFVERS 1
+#define PANICBUFVERS 2
#define PANICNVNAMELEN 16
+#define STACK_BUF_SIZE 2048
+#define SUMMARY_MAGIC 0xdead0d8a
+
/*
* Panicbuf Format:
*
@@ -80,9 +80,19 @@ typedef struct panic_nv {
typedef struct panic_data {
uint32_t pd_version; /* Version number of panic_data_t */
uint32_t pd_msgoff; /* Message byte offset in panicbuf */
+ char pd_uuid[36 + 1]; /* image uuid */
panic_nv_t pd_nvdata[1]; /* Array of named data */
} panic_data_t;
+typedef struct summary_dump {
+ uint32_t sd_magic; /* magic number */
+ uint32_t sd_ssum; /* checsksum32(stack buffer) */
+ /*
+ * stack buffer and other summary data follow here -- see
+ * dump_summary()
+ */
+} summary_dump_t;
+
#if defined(_KERNEL)
/*
diff --git a/usr/src/uts/common/sys/sysevent.h b/usr/src/uts/common/sys/sysevent.h
index 44b5d069fb..2b26441973 100644
--- a/usr/src/uts/common/sys/sysevent.h
+++ b/usr/src/uts/common/sys/sysevent.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_SYSEVENT_H
@@ -226,6 +225,8 @@ extern int sysevent_evc_unsubscribe(evchan_t *, const char *);
extern int sysevent_evc_publish(evchan_t *, const char *, const char *,
const char *, const char *, nvlist_t *, uint32_t);
extern int sysevent_evc_control(evchan_t *, int, ...);
+extern int sysevent_evc_setpropnvl(evchan_t *, nvlist_t *);
+extern int sysevent_evc_getpropnvl(evchan_t *, nvlist_t **);
#ifndef _KERNEL
diff --git a/usr/src/uts/common/sys/sysevent_impl.h b/usr/src/uts/common/sys/sysevent_impl.h
index 215862fbdd..117452765f 100644
--- a/usr/src/uts/common/sys/sysevent_impl.h
+++ b/usr/src/uts/common/sys/sysevent_impl.h
@@ -18,9 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_SYSEVENT_IMPL_H
@@ -76,7 +76,7 @@ typedef struct sysevent_attr_impl {
/*
* sysevent event header information -
- * contained in every event generated. The header and the event
+ * contained in every event generated. The header and the event
* must remain 64-bit aligned. The header, up to the attribute
* offset, can be contained in a single cache line.
*/
@@ -98,7 +98,7 @@ typedef struct sys_event_impl {
se_data_t se_class_name; /* class string in contig memory */
se_data_t se_subclass_name; /* subclass string in contig memory */
se_data_t se_pub; /* publisher string in contig mem */
- se_data_t se_attr_buf; /* contiguous attribute memory */
+ se_data_t se_attr_buf; /* contiguous attribute memory */
} sysevent_impl_t;
/* Helpful defines */
@@ -237,14 +237,14 @@ typedef struct sysevent_channel_descriptor {
/*
* log_sysevent private interfaces
*/
-void log_event_init(void);
-void log_sysevent_flushq(int cmd, uint_t flag);
-int log_sysevent_filename(char *file);
-int log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid);
-int log_sysevent_copyout_data(sysevent_id_t *eid, size_t ubuflen, caddr_t ubuf);
-int log_sysevent_free_data(sysevent_id_t *eid);
-int log_sysevent_register(char *channel_name, char *data, se_pubsub_t *udata);
-uint64_t log_sysevent_new_id();
+extern void log_event_init(void);
+extern void log_sysevent_flushq(int, uint_t);
+extern int log_sysevent_filename(char *);
+extern int log_usr_sysevent(sysevent_t *, int, sysevent_id_t *);
+extern int log_sysevent_copyout_data(sysevent_id_t *, size_t, caddr_t);
+extern int log_sysevent_free_data(sysevent_id_t *);
+extern int log_sysevent_register(char *, char *, se_pubsub_t *);
+extern uint64_t log_sysevent_new_id(void);
/*
* Structures and definitions for general purpose event channels
@@ -281,8 +281,8 @@ typedef struct evch_qelem {
typedef struct {
evch_qelem_t *sq_head;
evch_qelem_t *sq_tail;
- uint32_t sq_count;
- uint32_t sq_highwm;
+ uint32_t sq_count;
+ uint32_t sq_highwm;
} evch_squeue_t;
/*
@@ -394,6 +394,8 @@ typedef struct {
int ch_maxsubscr; /* Maximum number of subscriptions */
int ch_holdpend; /* Hold pending events mode if != 0 */
time_t ch_ctime; /* Channel creation time */
+ nvlist_t *ch_propnvl; /* Channel properties nvlist */
+ int64_t ch_propnvlgen; /* Properties generation number */
} evch_chan_t;
/*
@@ -413,26 +415,28 @@ typedef struct {
sysevent_impl_t *sn_nxtev; /* Pointer to find next event */
} evchanq_t;
-/* Project privat interfaces */
-evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err);
-void evch_usrchanclose(evchan_t *cbp);
-sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags);
-void evch_usrfreeev(sysevent_impl_t *ev);
-int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags);
-int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
+/* Project private interfaces */
+extern evchan_t *evch_usrchanopen(const char *name, uint32_t flags, int *err);
+extern void evch_usrchanclose(evchan_t *cbp);
+extern sysevent_impl_t *evch_usrallocev(size_t evsize, uint32_t flags);
+extern void evch_usrfreeev(sysevent_impl_t *ev);
+extern int evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags);
+extern int evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
int d, uint32_t flags);
-int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value);
-int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value);
-void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag);
-int evch_usrgetchnames(char *buf, size_t size);
-int evch_usrgetchdata(char *chname, void *buf, size_t size);
-
-void sysevent_evc_init();
-void sysevent_evc_thrinit();
-evchanq_t *sysevent_evc_walk_init(evchan_t *, char *);
-sysevent_t *sysevent_evc_walk_step(evchanq_t *);
-void sysevent_evc_walk_fini(evchanq_t *);
-char *sysevent_evc_event_attr(sysevent_t *, size_t *);
+extern int evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value);
+extern int evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value);
+extern void evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flag);
+extern int evch_usrgetchnames(char *buf, size_t size);
+extern int evch_usrgetchdata(char *chname, void *buf, size_t size);
+extern void evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl);
+extern int evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp);
+
+extern void sysevent_evc_init();
+extern void sysevent_evc_thrinit();
+extern evchanq_t *sysevent_evc_walk_init(evchan_t *, char *);
+extern sysevent_t *sysevent_evc_walk_step(evchanq_t *);
+extern void sysevent_evc_walk_fini(evchanq_t *);
+extern char *sysevent_evc_event_attr(sysevent_t *, size_t *);
#endif /* _KERNEL */
@@ -508,6 +512,8 @@ typedef struct {
#define SEV_UNSUBSCRIBE SEV_BASE | 0x05
#define SEV_CHANNAMES SEV_BASE | 0x06
#define SEV_CHANDATA SEV_BASE | 0x07
+#define SEV_SETPROPNVL SEV_BASE | 0x08
+#define SEV_GETPROPNVL SEV_BASE | 0x09
#define DEVSYSEVENT "/dev/sysevent"
#define DEVICESYSEVENT "/devices/pseudo/sysevent@0:sysevent"
@@ -560,6 +566,11 @@ typedef struct chandata {
sev_box_t out_data;
} sev_chandata_args_t;
+typedef struct propnvl_args {
+ sev_box_t packednvl; /* input and output */
+ int64_t generation; /* output on get operation */
+} sev_propnvl_args_t;
+
#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack()
#endif
diff --git a/usr/src/uts/intel/ia32/os/archdep.c b/usr/src/uts/intel/ia32/os/archdep.c
index c687a3d9da..506fbaf66e 100644
--- a/usr/src/uts/intel/ia32/os/archdep.c
+++ b/usr/src/uts/intel/ia32/os/archdep.c
@@ -1129,10 +1129,17 @@ argcount(uintptr_t eip)
/*
* Print a stack backtrace using the specified frame pointer. We delay two
- * seconds before continuing, unless this is the panic traceback. Note
- * that the frame for the starting stack pointer value is omitted because
+ * seconds before continuing, unless this is the panic traceback.
+ * If we are in the process of panicking, we also attempt to write the
+ * stack backtrace to a staticly assigned buffer, to allow the panic
+ * code to find it and write it in to uncompressed pages within the
+ * system crash dump.
+ * Note that the frame for the starting stack pointer value is omitted because
* the corresponding %eip is not known.
*/
+
+extern char *dump_stack_scratch;
+
#if defined(__amd64)
void
@@ -1143,10 +1150,17 @@ traceback(caddr_t fpreg)
uintptr_t pc, nextpc;
ulong_t off;
char args[TR_ARG_MAX * 2 + 16], *sym;
+ uint_t offset = 0;
+ uint_t next_offset = 0;
+ char stack_buffer[1024];
if (!panicstr)
printf("traceback: %%fp = %p\n", (void *)fp);
+ if (panicstr && !dump_stack_scratch) {
+ printf("Warning - stack not written to the dump buffer\n");
+ }
+
fp = (struct frame *)plat_traceback(fpreg);
if ((uintptr_t)fp < KERNELBASE)
goto out;
@@ -1177,9 +1191,33 @@ traceback(caddr_t fpreg)
if ((sym = kobj_getsymname(pc, &off)) != NULL) {
printf("%016lx %s:%s+%lx (%s)\n", (uintptr_t)fp,
mod_containing_pc((caddr_t)pc), sym, off, args);
+ (void) snprintf(stack_buffer, sizeof (stack_buffer),
+ "%s:%s+%lx (%s) | ",
+ mod_containing_pc((caddr_t)pc), sym, off, args);
} else {
printf("%016lx %lx (%s)\n",
(uintptr_t)fp, pc, args);
+ (void) snprintf(stack_buffer, sizeof (stack_buffer),
+ "%lx (%s) | ", pc, args);
+ }
+
+ if (panicstr && dump_stack_scratch) {
+ next_offset = offset + strlen(stack_buffer);
+ if (next_offset < STACK_BUF_SIZE) {
+ bcopy(stack_buffer, dump_stack_scratch + offset,
+ strlen(stack_buffer));
+ offset = next_offset;
+ } else {
+ /*
+ * In attempting to save the panic stack
+ * to the dumpbuf we have overflowed that area.
+ * Print a warning and continue to printf the
+ * stack to the msgbuf
+ */
+ printf("Warning: stack in the dump buffer"
+ " may be incomplete\n");
+ offset = next_offset;
+ }
}
pc = nextpc;
@@ -1189,6 +1227,8 @@ out:
if (!panicstr) {
printf("end of traceback\n");
DELAY(2 * MICROSEC);
+ } else if (dump_stack_scratch) {
+ dump_stack_scratch[offset] = '\0';
}
}
@@ -1200,6 +1240,9 @@ traceback(caddr_t fpreg)
struct frame *fp = (struct frame *)fpreg;
struct frame *nextfp, *minfp, *stacktop;
uintptr_t pc, nextpc;
+ uint_t offset = 0;
+ uint_t next_offset = 0;
+ char stack_buffer[1024];
cpu_t *cpu;
@@ -1215,6 +1258,10 @@ traceback(caddr_t fpreg)
if (!panicstr)
printf("traceback: %%fp = %p\n", (void *)fp);
+ if (panicstr && !dump_stack_scratch) {
+ printf("Warning - stack not written to the dumpbuf\n");
+ }
+
/*
* If we are panicking, all high-level interrupt information in
* CPU was overwritten. panic_cpu has the correct values.
@@ -1275,9 +1322,35 @@ traceback(caddr_t fpreg)
if ((sym = kobj_getsymname(pc, &off)) != NULL) {
printf("%08lx %s:%s+%lx (%s)\n", (uintptr_t)fp,
mod_containing_pc((caddr_t)pc), sym, off, args);
+ (void) snprintf(stack_buffer, sizeof (stack_buffer),
+ "%s:%s+%lx (%s) | ",
+ mod_containing_pc((caddr_t)pc), sym, off, args);
+
} else {
printf("%08lx %lx (%s)\n",
(uintptr_t)fp, pc, args);
+ (void) snprintf(stack_buffer, sizeof (stack_buffer),
+ "%lx (%s) | ", pc, args);
+
+ }
+
+ if (panicstr && dump_stack_scratch) {
+ next_offset = offset + strlen(stack_buffer);
+ if (next_offset < STACK_BUF_SIZE) {
+ bcopy(stack_buffer, dump_stack_scratch + offset,
+ strlen(stack_buffer));
+ offset = next_offset;
+ } else {
+ /*
+ * In attempting to save the panic stack
+ * to the dumpbuf we have overflowed that area.
+ * Print a warning and continue to printf the
+ * stack to the msgbuf
+ */
+ printf("Warning: stack in the dumpbuf"
+ " may be incomplete\n");
+ offset = next_offset;
+ }
}
minfp = fp;
@@ -1288,7 +1361,10 @@ out:
if (!panicstr) {
printf("end of traceback\n");
DELAY(2 * MICROSEC);
+ } else if (dump_stack_scratch) {
+ dump_stack_scratch[offset] = '\0';
}
+
}
#endif /* __i386 */
diff --git a/usr/src/uts/sparc/os/archdep.c b/usr/src/uts/sparc/os/archdep.c
index a1964308ed..e8979ccb66 100644
--- a/usr/src/uts/sparc/os/archdep.c
+++ b/usr/src/uts/sparc/os/archdep.c
@@ -19,16 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/vmparam.h>
@@ -255,10 +252,18 @@ __ipltospl(int ipl)
/*
* Print a stack backtrace using the specified stack pointer. We delay two
- * seconds before continuing, unless this is the panic traceback. Note
- * that the frame for the starting stack pointer value is omitted because
+ * seconds before continuing, unless this is the panic traceback.
+ * If we are in the process of panicking, we also attempt to write the
+ * stack backtrace to a staticly assigned buffer, to allow the panic
+ * code to find it and write it in to uncompressed pages within the
+ * system crash dump.
+ *
+ * Note that the frame for the starting stack pointer value is omitted because
* the corresponding %pc is not known.
*/
+
+extern char *dump_stack_scratch;
+
void
traceback(caddr_t sp)
{
@@ -268,11 +273,20 @@ traceback(caddr_t sp)
cpu_t *cpu;
+ uint_t offset = 0;
+ uint_t next_offset = 0;
+ char stack_buffer[2048];
+ char local_buffer[1024];
+
flush_windows();
if (!panicstr)
printf("traceback: %%sp = %p\n", (void *)sp);
+ if (panicstr && !dump_stack_scratch) {
+ printf("Warning - stack not written to the dumpbuf\n");
+ }
+
/*
* If we are panicking, the high-level interrupt information in
* CPU was overwritten. panic_cpu has the correct values.
@@ -321,20 +335,53 @@ traceback(caddr_t sp)
nextfp->fr_arg[0], nextfp->fr_arg[1],
nextfp->fr_arg[2], nextfp->fr_arg[3],
nextfp->fr_arg[4], nextfp->fr_arg[5]);
+ (void) snprintf(stack_buffer, sizeof (stack_buffer),
+ "%s:%s+%lx "
+ "(%lx, %lx, %lx, %lx, %lx, %lx) | ",
+ mod_containing_pc((caddr_t)pc), sym, off,
+ nextfp->fr_arg[0], nextfp->fr_arg[1],
+ nextfp->fr_arg[2], nextfp->fr_arg[3],
+ nextfp->fr_arg[4], nextfp->fr_arg[5]);
} else {
- printf("%016lx %p (%lx, %lx, %lx, %lx, %lx, %lx)\n",
+ (void) printf("%016lx %p (%lx, %lx, %lx, "
+ "%lx, %lx, %lx)\n",
(ulong_t)nextfp, (void *)pc,
nextfp->fr_arg[0], nextfp->fr_arg[1],
nextfp->fr_arg[2], nextfp->fr_arg[3],
nextfp->fr_arg[4], nextfp->fr_arg[5]);
+ (void) snprintf(stack_buffer, sizeof (stack_buffer),
+ "%p (%lx, %lx, %lx, %lx, %lx, %lx) | ",
+ (void *)pc,
+ nextfp->fr_arg[0], nextfp->fr_arg[1],
+ nextfp->fr_arg[2], nextfp->fr_arg[3],
+ nextfp->fr_arg[4], nextfp->fr_arg[5]);
}
- printf(" %%l0-3: %016lx %016lx %016lx %016lx\n"
+ (void) snprintf(local_buffer, sizeof (local_buffer),
+ " %%l0-3: %016lx %016lx %016lx %016lx\n"
" %%l4-7: %016lx %016lx %016lx %016lx\n",
nextfp->fr_local[0], nextfp->fr_local[1],
nextfp->fr_local[2], nextfp->fr_local[3],
nextfp->fr_local[4], nextfp->fr_local[5],
nextfp->fr_local[6], nextfp->fr_local[7]);
+ if (panicstr && dump_stack_scratch) {
+ next_offset = offset + strlen(stack_buffer);
+ if (next_offset < STACK_BUF_SIZE) {
+ bcopy(stack_buffer, dump_stack_scratch + offset,
+ strlen(stack_buffer));
+ offset = next_offset;
+ } else {
+ /*
+ * In attempting to save the panic stack
+ * to the dumpbuf we have overflowed that area.
+ * Print a warning and continue to printf the
+ * stack to the msgbuf
+ */
+ printf("Warning: stack in the dump buffer"
+ " may be incomplete\n");
+ }
+ }
+ printf("%s", local_buffer);
fp = nextfp;
minfp = fp;
@@ -343,6 +390,8 @@ traceback(caddr_t sp)
if (!panicstr) {
printf("end of traceback\n");
DELAY(2 * MICROSEC);
+ } else if (dump_stack_scratch) {
+ dump_stack_scratch[offset] = '\0';
}
}