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 36int 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 83 /* %lu can take up to 20, does not include %s, includes NUL */ 47#define _BACKTRACE_ADDRESS_LEN 18 /* 0x + 16 (no NUL) */ 48#else 49#define _BACKTRACE_FORMAT "%-4d%-35s 0x%08lx %s + %lu" 50#define _BACKTRACE_FORMAT_SIZE 65 /* %lu can take up to 10, does not include %s, includes NUL */ 51#define _BACKTRACE_ADDRESS_LEN 10 /* 0x + 8 (no NUL) */ 52#endif 53 54static int _backtrace_snprintf(char* buf, size_t size, int frame, const void* addr, const Dl_info* info) { 55 char symbuf[_BACKTRACE_ADDRESS_LEN + 1]; 56 const char* image = "???"; 57 const char* symbol = "0x0"; 58 uintptr_t symbol_offset = 0; 59 60 if (info->dli_fname) { 61 const char *tmp = strrchr(info->dli_fname, '/'); 62 if(tmp == NULL) 63 image = info->dli_fname; 64 else 65 image = tmp + 1; 66 } 67 68 if (info->dli_sname) { 69 symbol = info->dli_sname; 70 symbol_offset = (uintptr_t)addr - (uintptr_t)info->dli_saddr; 71 } else if(info->dli_fname) { 72 symbol = image; 73 symbol_offset = (uintptr_t)addr - (uintptr_t)info->dli_fbase; 74 } else if(0 < snprintf(symbuf, sizeof(symbuf), "0x%lx", (uintptr_t)info->dli_saddr)) { 75 symbol = symbuf; 76 symbol_offset = (uintptr_t)addr - (uintptr_t)info->dli_saddr; 77 } else { 78 symbol_offset = (uintptr_t)addr; 79 } 80 81 return snprintf(buf, size, 82 _BACKTRACE_FORMAT, 83 frame, 84 image, 85 (uintptr_t)addr, 86 symbol, 87 symbol_offset); 88} 89 90char** backtrace_symbols(void* const* buffer, int size) { 91 int i; 92 size_t total_bytes; 93 char** result; 94 char** ptrs; 95 intptr_t strs, end; 96 Dl_info* info = calloc(size, sizeof (Dl_info)); 97 98 if (info == NULL) return NULL; 99 100 // Compute the total size for the block that is returned. 101 // The block will contain size number of pointers to the 102 // symbol descriptions. 103 104 total_bytes = sizeof(char*) * size; 105 106 // Plus each symbol description 107 for (i = 0 ; i < size; ++i) { 108 dladdr(buffer[i], &info[i]); 109 total_bytes += _BACKTRACE_FORMAT_SIZE; 110 if (info[i].dli_sname) { 111 total_bytes += strlen(info[i].dli_sname); 112 } else if(info[i].dli_fname) { 113 const char *tmp = strrchr(info->dli_fname, '/'); 114 if(tmp == NULL) 115 total_bytes += strlen(info->dli_fname); 116 else 117 total_bytes += strlen(tmp + 1); 118 } else { 119 total_bytes += _BACKTRACE_ADDRESS_LEN; 120 } 121 } 122 123 result = (char**)malloc(total_bytes); 124 if (result == NULL) { 125 free(info); 126 return NULL; 127 } 128 end = (intptr_t)result + total_bytes; 129 130 // Fill in the array of pointers and append the strings for 131 // each symbol description. 132 133 ptrs = result; 134 strs = ((intptr_t)result) + sizeof(char*) * size; 135 136 for (i = 0; i < size; ++i) { 137 int chk = _backtrace_snprintf((char*)strs, end - (intptr_t)strs, i, buffer[i], &info[i]); 138 139 if(chk < 0) { 140 free(info); 141 return NULL; 142 } 143 144 ptrs[i] = (char*)strs; 145 strs += chk + 1; // Step over the '\0' 146 } 147 148 free(info); 149 150 return result; 151} 152 153void backtrace_symbols_fd(void* const* buffer, int size, int fd) { 154 int i; 155 char buf[BUFSIZ]; 156 Dl_info info; 157 struct iovec iov[2]; 158 159 iov[0].iov_base = buf; 160 161 iov[1].iov_base = "\n"; 162 iov[1].iov_len = 1; 163 164 for (i = 0; i < size; ++i) { 165 memset(&info, 0, sizeof(info)); 166 dladdr(buffer[i], &info); 167 168 iov[0].iov_len = _backtrace_snprintf(buf, sizeof(buf), i, buffer[i], &info); 169 170 writev(fd, iov, 2); 171 } 172} 173