]> git.saurik.com Git - apple/xnu.git/blob - libkern/gen/OSDebug.cpp
xnu-792.18.15.tar.gz
[apple/xnu.git] / libkern / gen / OSDebug.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 // NOTE: This file is only c++ so I can get static initialisers going
30 #include <libkern/OSDebug.h>
31
32 #include <sys/cdefs.h>
33
34 #include <stdarg.h>
35 #include <mach/mach_types.h>
36 #include <mach/kmod.h>
37 #include <kern/lock.h>
38
39 #include <libkern/libkern.h> // From bsd's libkern directory
40 #include <mach/vm_param.h>
41
42 __BEGIN_DECLS
43 // From osmfk/kern/thread.h but considered to be private
44 extern vm_offset_t min_valid_stack_address(void);
45 extern vm_offset_t max_valid_stack_address(void);
46
47 // From osfmk/kmod.c
48 extern void kmod_dump_log(vm_offset_t *addr, unsigned int cnt);
49
50 extern addr64_t kvtophys(vm_offset_t va);
51 __END_DECLS
52
53 static mutex_t *sOSReportLock = mutex_alloc(0);
54
55 /* Report a message with a 4 entry backtrace - very slow */
56 void
57 OSReportWithBacktrace(const char *str, ...)
58 {
59 char buf[128];
60 void *bt[9];
61 const unsigned cnt = sizeof(bt) / sizeof(bt[0]);
62 va_list listp;
63
64 // Ignore the our and our callers stackframes, skipping frames 0 & 1
65 (void) OSBacktrace(bt, cnt);
66
67 va_start(listp, str);
68 vsnprintf(buf, sizeof(buf), str, listp);
69 va_end(listp);
70
71 mutex_lock(sOSReportLock);
72 {
73 printf("%s\nBacktrace %p %p %p %p %p %p %p\n",
74 buf, bt[2], bt[3], bt[4], bt[5], bt[6], bt[7], bt[8]);
75 kmod_dump_log((vm_offset_t *) &bt[2], cnt - 2);
76 }
77 mutex_unlock(sOSReportLock);
78 }
79
80 static vm_offset_t minstackaddr = min_valid_stack_address();
81 static vm_offset_t maxstackaddr = max_valid_stack_address();
82
83 #if __i386__
84 #define i386_RETURN_OFFSET 4
85
86 static unsigned int
87 i386_validate_stackptr(vm_offset_t stackptr)
88 {
89 /* Existence and alignment check
90 */
91 if (!stackptr || (stackptr & 0x3))
92 return 0;
93
94 /* Is a virtual->physical translation present?
95 */
96 if (!kvtophys(stackptr))
97 return 0;
98
99 /* Check if the return address lies on the same page;
100 * If not, verify that a translation exists.
101 */
102 if (((PAGE_SIZE - (stackptr & PAGE_MASK)) < i386_RETURN_OFFSET) &&
103 !kvtophys(stackptr + i386_RETURN_OFFSET))
104 return 0;
105 return 1;
106 }
107
108 static unsigned int
109 i386_validate_raddr(vm_offset_t raddr)
110 {
111 return ((raddr > VM_MIN_KERNEL_ADDRESS) &&
112 (raddr < VM_MAX_KERNEL_ADDRESS));
113 }
114 #endif
115
116 unsigned OSBacktrace(void **bt, unsigned maxAddrs)
117 {
118 unsigned frame;
119
120 #if __ppc__
121 vm_offset_t stackptr, stackptr_prev;
122 const vm_offset_t * const mem = (vm_offset_t *) 0;
123 unsigned i = 0;
124
125 __asm__ volatile("mflr %0" : "=r" (stackptr));
126 bt[i++] = (void *) stackptr;
127
128 __asm__ volatile("mr %0,r1" : "=r" (stackptr));
129 for ( ; i < maxAddrs; i++) {
130 // Validate we have a reasonable stackptr
131 if ( !(minstackaddr <= stackptr && stackptr < maxstackaddr)
132 || (stackptr & 3))
133 break;
134
135 stackptr_prev = stackptr;
136 stackptr = mem[stackptr_prev >> 2];
137 if ((stackptr_prev ^ stackptr) > 8 * 1024) // Sanity check
138 break;
139
140 vm_offset_t addr = mem[(stackptr >> 2) + 2];
141 if ((addr & 3) || (addr < 0x8000)) // More sanity checks
142 break;
143 bt[i] = (void *) addr;
144 }
145 frame = i;
146
147 for ( ; i < maxAddrs; i++)
148 bt[i] = (void *) 0;
149 #elif __i386__
150 #define SANE_i386_FRAME_SIZE 8*1024
151 vm_offset_t stackptr, stackptr_prev, raddr;
152 unsigned frame_index = 0;
153 /* Obtain current frame pointer */
154 __asm__ volatile("movl %%ebp, %0" : "=m" (stackptr));
155
156 if (!i386_validate_stackptr(stackptr))
157 goto pad;
158
159 raddr = *((vm_offset_t *) (stackptr + i386_RETURN_OFFSET));
160
161 if (!i386_validate_raddr(raddr))
162 goto pad;
163
164 bt[frame_index++] = (void *) raddr;
165
166 for ( ; frame_index < maxAddrs; frame_index++) {
167 stackptr_prev = stackptr;
168 stackptr = *((vm_offset_t *) stackptr_prev);
169
170 if (!i386_validate_stackptr(stackptr))
171 break;
172 /* Stack grows downwards */
173 if (stackptr < stackptr_prev)
174 break;
175
176 if ((stackptr_prev ^ stackptr) > SANE_i386_FRAME_SIZE)
177 break;
178
179 raddr = *((vm_offset_t *) (stackptr + i386_RETURN_OFFSET));
180
181 if (!i386_validate_raddr(raddr))
182 break;
183
184 bt[frame_index] = (void *) raddr;
185 }
186 pad:
187 frame = frame_index;
188
189 for ( ; frame_index < maxAddrs; frame_index++)
190 bt[frame_index] = (void *) 0;
191 #else
192 #error arch
193 #endif
194 return frame;
195 }