2 * Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <TargetConditionals.h>
25 #include <mach/vm_types.h>
28 #include <mach-o/dyld_priv.h>
31 #include <uuid/uuid.h>
34 extern void _thread_stack_pcs(vm_address_t
*buffer
, unsigned max
,
35 unsigned *nb
, unsigned skip
, void *startfp
);
37 int backtrace(void** buffer
, int size
) {
38 unsigned int num_frames
;
39 _thread_stack_pcs((vm_address_t
*)buffer
, size
, &num_frames
, 1, NULL
);
40 while (num_frames
>= 1 && buffer
[num_frames
-1] == NULL
) num_frames
-= 1;
45 backtrace_from_fp(void *startfp
, void **buffer
, int size
)
47 unsigned int num_frames
;
48 _thread_stack_pcs((vm_address_t
*)buffer
, size
, &num_frames
, 1, startfp
);
49 while (num_frames
>= 1 && buffer
[num_frames
-1] == NULL
) num_frames
-= 1;
53 #if !TARGET_OS_DRIVERKIT
58 #include "stack_logging.h"
61 #define _BACKTRACE_FORMAT "%-4d%-35s 0x%016lx %s + %lu"
62 #define _BACKTRACE_FORMAT_SIZE 83 /* %lu can take up to 20, does not include %s, includes NUL */
63 #define _BACKTRACE_ADDRESS_LEN 18 /* 0x + 16 (no NUL) */
65 #define _BACKTRACE_FORMAT "%-4d%-35s 0x%08lx %s + %lu"
66 #define _BACKTRACE_FORMAT_SIZE 65 /* %lu can take up to 10, does not include %s, includes NUL */
67 #define _BACKTRACE_ADDRESS_LEN 10 /* 0x + 8 (no NUL) */
69 #define _BACKTRACE_IMAGE_LEN 35
70 #define _BACKTRACE_UUID_LEN 36
72 static int _backtrace_snprintf(char* buf
, size_t size
, int frame
, const void* addr
, const Dl_info
* info
) {
73 char addrbuf
[_BACKTRACE_ADDRESS_LEN
+ 1];
74 char imagebuf
[_BACKTRACE_IMAGE_LEN
+ 1];
75 uuid_string_t uuidbuf
;
76 const char* image
= "???";
77 const char* symbol
= "0x0";
78 uintptr_t symbol_offset
= 0;
80 if (info
->dli_fname
) {
81 const char *tmp
= strrchr(info
->dli_fname
, '/');
83 strlcpy(imagebuf
, info
->dli_fname
, sizeof(imagebuf
));
85 strlcpy(imagebuf
, tmp
+ 1, sizeof(imagebuf
));
90 if (info
->dli_sname
) {
92 if (strcmp(info
->dli_sname
, "<redacted>") == 0 &&
93 _dyld_get_image_uuid(info
->dli_fbase
, uuid
)) {
95 * dyld returns <redacted> when the symbol name has been elided in
96 * the shared cache. To enable symbolication later, we provide the
97 * UUID and UUID-offset instead.
99 uuid_unparse(uuid
, uuidbuf
);
101 symbol_offset
= (uintptr_t)addr
- (uintptr_t)info
->dli_fbase
;
103 symbol
= info
->dli_sname
;
104 symbol_offset
= (uintptr_t)addr
- (uintptr_t)info
->dli_saddr
;
106 } else if (info
->dli_fname
) {
108 symbol_offset
= (uintptr_t)addr
- (uintptr_t)info
->dli_fbase
;
109 } else if (0 < snprintf(addrbuf
, sizeof(addrbuf
), "0x%lx",
110 (uintptr_t)info
->dli_saddr
)) {
112 symbol_offset
= (uintptr_t)addr
- (uintptr_t)info
->dli_saddr
;
114 symbol_offset
= (uintptr_t)addr
;
117 return snprintf(buf
, size
, _BACKTRACE_FORMAT
, frame
, image
,
118 (uintptr_t)addr
, symbol
, symbol_offset
);
121 static size_t symbol_length(Dl_info
*info
)
123 if (info
->dli_sname
) {
124 if (strcmp(info
->dli_sname
, "<redacted>") == 0) {
125 return _BACKTRACE_UUID_LEN
;
127 return strlen(info
->dli_sname
);
129 } else if (info
->dli_fname
) {
130 const char *tmp
= strrchr(info
->dli_fname
, '/');
132 return strlen(info
->dli_fname
);
134 return strlen(tmp
+ 1);
137 return _BACKTRACE_ADDRESS_LEN
;
141 char** backtrace_symbols(void* const* buffer
, int size
) {
147 Dl_info
* info
= calloc(size
, sizeof (Dl_info
));
149 if (info
== NULL
) return NULL
;
151 // Compute the total size for the block that is returned.
152 // The block will contain size number of pointers to the
153 // symbol descriptions.
155 total_bytes
= sizeof(char*) * size
;
157 // Plus each symbol description
158 for (i
= 0 ; i
< size
; ++i
) {
159 dladdr(buffer
[i
], &info
[i
]);
160 total_bytes
+= _BACKTRACE_FORMAT_SIZE
;
161 total_bytes
+= symbol_length(&info
[i
]);
164 result
= (char**)malloc(total_bytes
);
165 if (result
== NULL
) {
168 end
= (intptr_t)result
+ total_bytes
;
170 // Fill in the array of pointers and append the strings for
171 // each symbol description.
174 strs
= ((intptr_t)result
) + sizeof(char*) * size
;
176 for (i
= 0; i
< size
; ++i
) {
177 int chk
= _backtrace_snprintf((char*)strs
, end
- (intptr_t)strs
, i
, buffer
[i
], &info
[i
]);
182 ptrs
[i
] = (char*)strs
;
183 strs
+= chk
+ 1; // Step over the '\0'
195 void backtrace_symbols_fd(void* const* buffer
, int size
, int fd
) {
201 iov
[0].iov_base
= buf
;
203 iov
[1].iov_base
= "\n";
206 for (i
= 0; i
< size
; ++i
) {
207 memset(&info
, 0, sizeof(info
));
208 dladdr(buffer
[i
], &info
);
210 iov
[0].iov_len
= _backtrace_snprintf(buf
, sizeof(buf
), i
, buffer
[i
], &info
);
216 #endif // !TARGET_OS_DRIVERKIT
219 backtrace_image_offsets(void* const* buffer
, struct image_offset
*imgoffs
, int size
)
221 struct dyld_image_uuid_offset infos
[size
];
222 _dyld_images_for_addresses(size
, (const void **)buffer
, infos
);
224 for (int i
= 0; i
< size
; i
++) {
225 uuid_copy(imgoffs
[i
].uuid
, infos
[i
].uuid
);
226 imgoffs
[i
].offset
= infos
[i
].offsetInImage
;