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