]> git.saurik.com Git - apple/libc.git/blob - gen/backtrace.c
2aaee08f3d4b8473ddb610f8a8abac5fcdf99799
[apple/libc.git] / gen / backtrace.c
1 /*
2 * Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <mach/vm_types.h>
25 #include <sys/uio.h>
26
27 #include <dlfcn.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "stack_logging.h"
34 #include "execinfo.h"
35
36 int backtrace(void** buffer, int size) {
37 extern void _thread_stack_pcs(vm_address_t *buffer, unsigned max, unsigned *nb, unsigned skip);
38 unsigned int num_frames;
39 _thread_stack_pcs((vm_address_t*)buffer, size, &num_frames, 1);
40 while (num_frames >= 1 && buffer[num_frames-1] == NULL) num_frames -= 1;
41 return num_frames;
42 }
43
44 #if __LP64__
45 #define _BACKTRACE_FORMAT "%-4d%-35s 0x%016lx %s + %lu"
46 #define _BACKTRACE_FORMAT_SIZE 82
47 #else
48 #define _BACKTRACE_FORMAT "%-4d%-35s 0x%08lx %s + %lu"
49 #define _BACKTRACE_FORMAT_SIZE 65
50 #endif
51
52
53 static int _backtrace_snprintf(char* buf, size_t size, int frame, const void* addr, const Dl_info* info) {
54 char symbuf[19];
55 const char* image = "???";
56 const char* symbol = symbuf;
57
58 if (info->dli_fname) {
59 image = strrchr(info->dli_fname, '/') + 1;
60 if (image == NULL) image = info->dli_fname;
61 }
62
63 if (info->dli_sname) {
64 symbol = info->dli_sname;
65 } else {
66 snprintf(symbuf, sizeof(symbuf), "0x%lx", (uintptr_t)info->dli_saddr);
67 }
68
69 return snprintf(buf, size,
70 _BACKTRACE_FORMAT,
71 frame,
72 image,
73 (uintptr_t)addr,
74 symbol,
75 (uintptr_t)addr - (uintptr_t)info->dli_saddr) + 1;
76 }
77
78 char** backtrace_symbols(void* const* buffer, int size) {
79 int i;
80 size_t total_bytes;
81 char** result;
82 char** ptrs;
83 intptr_t strs;
84 Dl_info* info = calloc(size, sizeof (Dl_info));
85
86 if (info == NULL) return NULL;
87
88 // Compute the total size for the block that is returned.
89 // The block will contain size number of pointers to the
90 // symbol descriptions.
91
92 total_bytes = sizeof(char*) * size;
93
94 // Plus each symbol description
95 for (i = 0 ; i < size; ++i) {
96 dladdr(buffer[i], &info[i]);
97 total_bytes += _BACKTRACE_FORMAT_SIZE + 1;
98 if (info[i].dli_sname) total_bytes += strlen(info[i].dli_sname);
99 }
100
101 result = (char**)malloc(total_bytes);
102 if (result == NULL) {
103 free(info);
104 return NULL;
105 }
106
107 // Fill in the array of pointers and append the strings for
108 // each symbol description.
109
110 ptrs = result;
111 strs = ((intptr_t)result) + sizeof(char*) * size;
112
113 for (i = 0; i < size; ++i) {
114 ptrs[i] = (char*)strs;
115 strs += _backtrace_snprintf((char*)strs, total_bytes, i, buffer[i], &info[i]);
116 }
117
118 free(info);
119
120 return result;
121 }
122
123 void backtrace_symbols_fd(void* const* buffer, int size, int fd) {
124 int i;
125 char buf[BUFSIZ];
126 Dl_info info;
127 struct iovec iov[2];
128
129 iov[0].iov_base = buf;
130
131 iov[1].iov_base = "\n";
132 iov[1].iov_len = 1;
133
134 for (i = 0; i < size; ++i) {
135 memset(&info, 0, sizeof(info));
136 dladdr(buffer[i], &info);
137
138 iov[0].iov_len = _backtrace_snprintf(buf, sizeof(buf), i, buffer[i], &info);
139
140 writev(fd, iov, 2);
141 }
142 }