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