]> git.saurik.com Git - apple/xnu.git/blob - libkern/gen/OSDebug.cpp
xnu-792.24.17.tar.gz
[apple/xnu.git] / libkern / gen / OSDebug.cpp
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 // NOTE: This file is only c++ so I can get static initialisers going
24 #include <libkern/OSDebug.h>
25
26 #include <sys/cdefs.h>
27
28 #include <stdarg.h>
29 #include <mach/mach_types.h>
30 #include <mach/kmod.h>
31 #include <kern/lock.h>
32
33 #include <libkern/libkern.h> // From bsd's libkern directory
34
35 __BEGIN_DECLS
36 // From osmfk/kern/thread.h but considered to be private
37 extern vm_offset_t min_valid_stack_address(void);
38 extern vm_offset_t max_valid_stack_address(void);
39
40 // From osfmk/kmod.c
41 extern void kmod_dump_log(vm_offset_t *addr, unsigned int cnt);
42 __END_DECLS
43
44 static mutex_t *sOSReportLock = mutex_alloc(0);
45
46 /* Report a message with a 4 entry backtrace - very slow */
47 void
48 OSReportWithBacktrace(const char *str, ...)
49 {
50 char buf[128];
51 void *bt[9];
52 const unsigned cnt = sizeof(bt) / sizeof(bt[0]);
53 va_list listp;
54
55 // Ignore the our and our callers stackframes, skipping frames 0 & 1
56 (void) OSBacktrace(bt, cnt);
57
58 va_start(listp, str);
59 vsnprintf(buf, sizeof(buf), str, listp);
60 va_end(listp);
61
62 mutex_lock(sOSReportLock);
63 {
64 printf("%s\nBacktrace %p %p %p %p %p %p %p\n",
65 buf, bt[2], bt[3], bt[4], bt[5], bt[6], bt[7], bt[8]);
66 kmod_dump_log((vm_offset_t *) &bt[2], cnt - 2);
67 }
68 mutex_unlock(sOSReportLock);
69 }
70
71 static vm_offset_t minstackaddr = min_valid_stack_address();
72 static vm_offset_t maxstackaddr = max_valid_stack_address();
73
74 unsigned OSBacktrace(void **bt, unsigned maxAddrs)
75 {
76 unsigned frame;
77
78 #if __ppc__
79 vm_offset_t stackptr, stackptr_prev;
80 const vm_offset_t * const mem = (vm_offset_t *) 0;
81 unsigned i = 0;
82
83 __asm__ volatile("mflr %0" : "=r" (stackptr));
84 bt[i++] = (void *) stackptr;
85
86 __asm__ volatile("mr %0,r1" : "=r" (stackptr));
87 for ( ; i < maxAddrs; i++) {
88 // Validate we have a reasonable stackptr
89 if ( !(minstackaddr <= stackptr && stackptr < maxstackaddr)
90 || (stackptr & 3))
91 break;
92
93 stackptr_prev = stackptr;
94 stackptr = mem[stackptr_prev >> 2];
95 if ((stackptr_prev ^ stackptr) > 8 * 1024) // Sanity check
96 break;
97
98 vm_offset_t addr = mem[(stackptr >> 2) + 2];
99 if ((addr & 3) || (addr < 0x8000)) // More sanity checks
100 break;
101 bt[i] = (void *) addr;
102 }
103 frame = i;
104
105 for ( ; i < maxAddrs; i++)
106 bt[i] = (void *) 0;
107 #elif 0 && __i386__ // Note that this should be ported for i386
108 // This function is not safe, we should get this code ported appropriately
109 if (maxAddrs > 16) {
110 for (frame = 16; frame < maxAddrs; frame++)
111 bt[frame] = __builtin_return_address(frame);
112 maxAddrs = 16;
113 }
114
115 switch(maxAddrs) {
116 case 15+1: bt[15] = __builtin_return_address(15);
117 case 14+1: bt[14] = __builtin_return_address(14);
118 case 13+1: bt[13] = __builtin_return_address(13);
119 case 12+1: bt[12] = __builtin_return_address(12);
120 case 11+1: bt[11] = __builtin_return_address(11);
121 case 10+1: bt[10] = __builtin_return_address(10);
122 case 9+1: bt[ 9] = __builtin_return_address( 9);
123 case 8+1: bt[ 8] = __builtin_return_address( 8);
124 case 7+1: bt[ 7] = __builtin_return_address( 7);
125 case 6+1: bt[ 6] = __builtin_return_address( 6);
126 case 5+1: bt[ 5] = __builtin_return_address( 5);
127 case 4+1: bt[ 4] = __builtin_return_address( 4);
128 case 3+1: bt[ 3] = __builtin_return_address( 3);
129 case 2+1: bt[ 2] = __builtin_return_address( 2);
130 case 1+1: bt[ 1] = __builtin_return_address( 1);
131 case 0+1: bt[ 0] = __builtin_return_address( 0);
132 case 0: default: break;
133 }
134
135 frame = maxAddrs;
136 #else
137 // This function is not safe, we should get this code ported appropriately
138 if (maxAddrs > 16) {
139 for (frame = 16; frame < maxAddrs; frame++)
140 bt[frame] = 0;
141 maxAddrs = 16;
142 }
143
144 switch (maxAddrs) {
145 case 15+1: bt[15] = __builtin_return_address(15);
146 case 14+1: bt[14] = __builtin_return_address(14);
147 case 13+1: bt[13] = __builtin_return_address(13);
148 case 12+1: bt[12] = __builtin_return_address(12);
149 case 11+1: bt[11] = __builtin_return_address(11);
150 case 10+1: bt[10] = __builtin_return_address(10);
151 case 9+1: bt[ 9] = __builtin_return_address( 9);
152 case 8+1: bt[ 8] = __builtin_return_address( 8);
153 case 7+1: bt[ 7] = __builtin_return_address( 7);
154 case 6+1: bt[ 6] = __builtin_return_address( 6);
155 case 5+1: bt[ 5] = __builtin_return_address( 5);
156 case 4+1: bt[ 4] = __builtin_return_address( 4);
157 case 3+1: bt[ 3] = __builtin_return_address( 3);
158 case 2+1: bt[ 2] = __builtin_return_address( 2);
159 case 1+1: bt[ 1] = __builtin_return_address( 1);
160 case 0+1: bt[ 0] = __builtin_return_address( 0);
161 case 0:
162 default :
163 break;
164 }
165
166 frame = maxAddrs;
167 #endif
168
169 return frame;
170 }