/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*/
#include <mach_assert.h>
-#include <mach_kdb.h>
-#include <mach_kgdb.h>
#include <mach_kdp.h>
#include <kern/cpu_number.h>
#include <kern/sched_prim.h>
#include <kern/misc_protos.h>
#include <kern/clock.h>
+#include <kern/telemetry.h>
#include <vm/vm_kern.h>
#include <vm/pmap.h>
#include <stdarg.h>
unsigned int return_on_panic = 0;
unsigned long panic_caller;
-#if CONFIG_EMBEDDED
-#define DEBUG_BUF_SIZE (PAGE_SIZE)
-#else
#define DEBUG_BUF_SIZE (3 * PAGE_SIZE)
-#endif
char debug_buf[DEBUG_BUF_SIZE];
char *debug_buf_ptr = debug_buf;
unsigned int debug_buf_size = sizeof(debug_buf);
static char model_name[64];
-/* uuid_string_t */ char kernel_uuid[37];
+unsigned char *kernel_uuid;
+/* uuid_string_t */ char kernel_uuid_string[37];
+
+static spl_t panic_prologue(const char *str);
+static void panic_epilogue(spl_t s);
struct pasc {
unsigned a: 7;
}
saved_return_on_panic = return_on_panic;
- return_on_panic = 1;
+
+ /*
+ * If we don't have a debugger configured, returning from an
+ * assert is a bad, bad idea; there is no guarantee that we
+ * didn't simply assert before we were able to restart the
+ * platform.
+ */
+ if (current_debugger != NO_CUR_DB)
+ return_on_panic = 1;
panic_plain("%s:%d Assertion failed: %s", file, line, expression);
simple_unlock(&panic_lock); \
MACRO_END
-
void
panic_init(void)
{
uuid = getuuidfromheader(&_mh_execute_header, &uuidlen);
if ((uuid != NULL) && (uuidlen == sizeof(uuid_t))) {
- uuid_unparse_upper(*(uuid_t *)uuid, kernel_uuid);
+ kernel_uuid = uuid;
+ uuid_unparse_upper(*(uuid_t *)uuid, kernel_uuid_string);
}
simple_lock_init(&panic_lock, 0);
panic("panic");
}
-void
-panic(const char *str, ...)
+static spl_t
+panic_prologue(const char *str)
{
- va_list listp;
spl_t s;
- thread_t thread;
- wait_queue_t wq;
+
+ if (kdebug_enable) {
+ if (get_preemption_level() == 0 && !ml_at_interrupt_context()) {
+ ml_set_interrupts_enabled(TRUE);
+ kdbg_dump_trace_to_file("/var/tmp/panic.trace");
+ }
+ }
+
+ s = splhigh();
+ disable_preemption();
#if defined(__i386__) || defined(__x86_64__)
/* Attempt to display the unparsed panic string */
kprintf("%c", *tstr++);
kprintf("\n");
#endif
- if (kdebug_enable)
- kdbg_dump_trace_to_file("/var/tmp/panic.trace");
-
- s = splhigh();
- disable_preemption();
panic_safe();
- thread = current_thread(); /* Get failing thread */
- wq = thread->wait_queue; /* Save the old value */
- thread->wait_queue = NULL; /* Clear the wait so we do not get double panics when we try locks */
-
if( logPanicDataToScreen )
disable_debug_output = FALSE;
debug_mode = TRUE;
- /* panic_caller is initialized to 0. If set, don't change it */
- if ( ! panic_caller )
- panic_caller = (unsigned long)(char *)__builtin_return_address(0);
-
restart:
PANIC_LOCK();
+
if (panicstr) {
if (cpu_number() != paniccpu) {
PANIC_UNLOCK();
panicwait = 1;
PANIC_UNLOCK();
- kdb_printf("panic(cpu %d caller 0x%lx): ", (unsigned) paniccpu, panic_caller);
- if (str) {
- va_start(listp, str);
- _doprnt(str, &listp, consdebug_putc, 0);
- va_end(listp);
- }
- kdb_printf("\n");
+ return(s);
+}
- /*
- * Release panicwait indicator so that other cpus may call Debugger().
- */
- panicwait = 0;
- Debugger("panic");
+
+static void
+panic_epilogue(spl_t s)
+{
/*
* Release panicstr so that we can handle normally other panics.
*/
PANIC_LOCK();
panicstr = (char *)0;
PANIC_UNLOCK();
- thread->wait_queue = wq; /* Restore the wait queue */
if (return_on_panic) {
panic_normal();
splx(s);
return;
}
-
kdb_printf("panic: We are hanging here...\n");
panic_stop();
/* NOTREACHED */
}
+void
+panic(const char *str, ...)
+{
+ va_list listp;
+ spl_t s;
+
+
+ /* panic_caller is initialized to 0. If set, don't change it */
+ if ( ! panic_caller )
+ panic_caller = (unsigned long)(char *)__builtin_return_address(0);
+
+ s = panic_prologue(str);
+ kdb_printf("panic(cpu %d caller 0x%lx): ", (unsigned) paniccpu, panic_caller);
+ if (str) {
+ va_start(listp, str);
+ _doprnt(str, &listp, consdebug_putc, 0);
+ va_end(listp);
+ }
+ kdb_printf("\n");
+
+ /*
+ * Release panicwait indicator so that other cpus may call Debugger().
+ */
+ panicwait = 0;
+ Debugger("panic");
+ panic_epilogue(s);
+}
+
+void
+panic_context(unsigned int reason, void *ctx, const char *str, ...)
+{
+ va_list listp;
+ spl_t s;
+
+
+ /* panic_caller is initialized to 0. If set, don't change it */
+ if ( ! panic_caller )
+ panic_caller = (unsigned long)(char *)__builtin_return_address(0);
+
+ s = panic_prologue(str);
+ kdb_printf("panic(cpu %d caller 0x%lx): ", (unsigned) paniccpu, panic_caller);
+ if (str) {
+ va_start(listp, str);
+ _doprnt(str, &listp, consdebug_putc, 0);
+ va_end(listp);
+ }
+ kdb_printf("\n");
+
+ /*
+ * Release panicwait indicator so that other cpus may call Debugger().
+ */
+ panicwait = 0;
+ DebuggerWithContext(reason, ctx, "panic");
+ panic_epilogue(s);
+}
+
void
log(__unused int level, char *fmt, ...)
{
}
static void panic_display_kernel_uuid(void) {
- char tmp_kernel_uuid[sizeof(kernel_uuid)];
+ char tmp_kernel_uuid[sizeof(kernel_uuid_string)];
- if (ml_nofault_copy((vm_offset_t) &kernel_uuid, (vm_offset_t) &tmp_kernel_uuid, sizeof(kernel_uuid)) != sizeof(kernel_uuid))
+ if (ml_nofault_copy((vm_offset_t) &kernel_uuid_string, (vm_offset_t) &tmp_kernel_uuid, sizeof(kernel_uuid_string)) != sizeof(kernel_uuid_string))
return;
if (tmp_kernel_uuid[0] != '\0')
kdb_printf("Kernel UUID: %s\n", tmp_kernel_uuid);
}
+void panic_display_kernel_aslr(void) {
+ if (vm_kernel_slide) {
+ kdb_printf("Kernel slide: 0x%016lx\n", (unsigned long) vm_kernel_slide);
+ kdb_printf("Kernel text base: %p\n", (void *) vm_kernel_stext);
+ }
+}
+
static void panic_display_uptime(void) {
uint64_t uptime;
absolutetime_to_nanoseconds(mach_absolute_time(), &uptime);
(osversion[0] != 0) ? osversion : "Not yet set");
kdb_printf("\nKernel version:\n%s\n",version);
panic_display_kernel_uuid();
+ panic_display_kernel_aslr();
panic_display_pal_info();
panic_display_model_name();
panic_display_uptime();
#endif /* CONFIG_ZLEAKS */
#if !MACH_KDP
-static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}};
+static struct kdp_ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}};
/* XXX ugly forward declares to stop warnings */
void *kdp_get_interface(void);
-void kdp_set_ip_and_mac_addresses(struct in_addr *, struct ether_addr *);
+void kdp_set_ip_and_mac_addresses(struct kdp_in_addr *, struct kdp_ether_addr *);
void kdp_set_gateway_mac(void *);
void kdp_set_interface(void *);
void kdp_register_send_receive(void *, void *);
kdp_get_ip_address(void )
{ return 0; }
-struct ether_addr
+struct kdp_ether_addr
kdp_get_mac_addr(void)
{
return kdp_current_mac_address;
void
kdp_set_ip_and_mac_addresses(
- __unused struct in_addr *ipaddr,
- __unused struct ether_addr *macaddr)
+ __unused struct kdp_in_addr *ipaddr,
+ __unused struct kdp_ether_addr *macaddr)
{}
void
}
#endif
+
+#if !CONFIG_TELEMETRY
+int telemetry_gather(user_addr_t buffer __unused, uint32_t *length __unused, boolean_t mark __unused)
+{
+ return KERN_NOT_SUPPORTED;
+}
+#endif