diff options
Diffstat (limited to 'usr/src/uts')
| -rw-r--r-- | usr/src/uts/common/io/dump.c | 22 | ||||
| -rw-r--r-- | usr/src/uts/common/io/sysevent.c | 119 | ||||
| -rw-r--r-- | usr/src/uts/common/os/dumpsubr.c | 101 | ||||
| -rw-r--r-- | usr/src/uts/common/os/evchannels.c | 81 | ||||
| -rw-r--r-- | usr/src/uts/common/os/fm.c | 14 | ||||
| -rw-r--r-- | usr/src/uts/common/os/log_sysevent.c | 45 | ||||
| -rw-r--r-- | usr/src/uts/common/os/panic.c | 3 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/dumpadm.h | 12 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/dumphdr.h | 10 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/fm/protocol.h | 31 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/fm/util.h | 6 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/nvpair.h | 5 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/panic.h | 20 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/sysevent.h | 5 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/sysevent_impl.h | 77 | ||||
| -rw-r--r-- | usr/src/uts/intel/ia32/os/archdep.c | 80 | ||||
| -rw-r--r-- | usr/src/uts/sparc/os/archdep.c | 65 |
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'; } } |
