unwind.c revision 236ef4607a5f85a089f5c2d2dc82e53a8ce82375
1/* 2 * 3 * honggfuzz - architecture dependent code (LINUX/UNWIND) 4 * ----------------------------------------- 5 * 6 * Author: Robert Swiecki <swiecki@google.com> 7 * 8 * Copyright 2010-2015 by Google Inc. All Rights Reserved. 9 * 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may 11 * not use this file except in compliance with the License. You may obtain 12 * a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software 17 * distributed under the License is distributed on an "AS IS" BASIS, 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 * implied. See the License for the specific language governing 20 * permissions and limitations under the License. 21 * 22 */ 23 24#include "common.h" 25#include "linux/unwind.h" 26 27#include <libunwind-ptrace.h> 28 29#include "log.h" 30 31#if defined(__ANDROID__) 32#include <sys/endian.h> /* For __BYTE_ORDER */ 33#endif 34 35/* 36 * WARNING: Ensure that _UPT-info structs are not shared between threads 37 * http://www.nongnu.org/libunwind/man/libunwind-ptrace(3).html 38 */ 39 40/* 41 * TODO: Subtract from load map to have relative PC stored in report file. 42 * link_map seems to be the easiest road for that. 43 */ 44 45// libunwind error codes used for debugging 46static const char *UNW_ER[] = { 47 "UNW_ESUCCESS", /* no error */ 48 "UNW_EUNSPEC", /* unspecified (general) error */ 49 "UNW_ENOMEM", /* out of memory */ 50 "UNW_EBADREG", /* bad register number */ 51 "UNW_EREADONLYREG", /* attempt to write read-only register */ 52 "UNW_ESTOPUNWIND", /* stop unwinding */ 53 "UNW_EINVALIDIP", /* invalid IP */ 54 "UNW_EBADFRAME", /* bad frame */ 55 "UNW_EINVAL", /* unsupported operation or bad value */ 56 "UNW_EBADVERSION", /* unwind info has unsupported version */ 57 "UNW_ENOINFO" /* no unwind info found */ 58}; 59 60#ifndef __ANDROID__ 61size_t arch_unwindStack(pid_t pid, funcs_t *funcs) 62{ 63 size_t num_frames = 0; 64 void *ui = NULL; 65 66 unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER); 67 if (!as) { 68 LOGMSG(l_ERROR, "[pid='%d'] unw_create_addr_space failed", pid); 69 goto out; 70 } 71 72 ui = _UPT_create(pid); 73 if (ui == NULL) { 74 LOGMSG(l_ERROR, "[pid='%d'] _UPT_create failed", pid); 75 goto out; 76 } 77 78 unw_cursor_t c; 79 int ret = unw_init_remote(&c, as, ui); 80 if (ret < 0) { 81 LOGMSG(l_ERROR, "[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]); 82 goto out; 83 } 84 85 for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) { 86 unw_word_t ip; 87 ret = unw_get_reg(&c, UNW_REG_IP, &ip); 88 if (ret < 0) { 89 LOGMSG(l_ERROR, "[pid='%d'] [%d] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]); 90 funcs[num_frames].pc = 0; 91 } 92 else 93 funcs[num_frames].pc = (void *)ip; 94 } 95 96 out: 97 ui ? _UPT_destroy(ui) : 0; 98 as ? unw_destroy_addr_space(as) : 0; 99 return num_frames; 100} 101 102#else /* !defined(__ANDROID__) */ 103size_t arch_unwindStack(pid_t pid, funcs_t *funcs) 104{ 105 size_t num_frames = 0; 106 struct UPT_info *ui = NULL; 107 unw_addr_space_t as = NULL; 108 109 as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER); 110 if (!as) { 111 LOGMSG(l_ERROR, "[pid='%d'] unw_create_addr_space failed", pid); 112 goto out; 113 } 114 115 ui = (struct UPT_info*)_UPT_create(pid); 116 if (ui == NULL) { 117 LOGMSG(l_ERROR, "[pid='%d'] _UPT_create failed", pid); 118 goto out; 119 } 120 121 unw_cursor_t cursor; 122 int ret = unw_init_remote(&cursor, as, ui); 123 if (ret < 0) { 124 LOGMSG(l_ERROR, "[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]); 125 goto out; 126 } 127 128 do { 129 unw_word_t pc = 0, offset = 0; 130 char buf[_HF_FUNC_NAME_SZ] = { 0 }; 131 132 unw_proc_info_t frameInfo; 133 ret = unw_get_proc_info(&cursor, &frameInfo); 134 if (ret < 0) { 135 LOGMSG(l_DEBUG, "[pid='%d'] [%d] unw_get_proc_info (%s)", 136 pid, num_frames, UNW_ER[-ret]); 137 // Not safe to keep reading 138 goto out; 139 } 140 141 ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); 142 if (ret < 0) { 143 LOGMSG(l_ERROR, "[pid='%d'] [%d] failed to read IP (%s)", 144 pid, num_frames, UNW_ER[-ret]); 145 // We don't want to try to extract info from an arbitrary IP 146 // TODO: Maybe abort completely (goto out)) 147 goto skip_frame_info; 148 } 149 150 ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset); 151 if (ret < 0) { 152 LOGMSG(l_DEBUG, "[pid='%d'] [%d] unw_get_proc_name() failed (%s)", 153 pid, num_frames, UNW_ER[-ret]); 154 buf[0] = '\0'; 155 } 156 157skip_frame_info: 158 // Compared to bfd, line var plays the role of offset from func_name 159 // Reports format is adjusted accordingly to reflect in saved file 160 funcs[num_frames].line = offset; 161 funcs[num_frames].pc = (void *)pc; 162 memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func)); 163 164 num_frames++; 165 166 ret = unw_step(&cursor); 167 } while (ret > 0 && num_frames < _HF_MAX_FUNCS); 168 169 out: 170 ui ? _UPT_destroy(ui) : NULL; 171 as ? unw_destroy_addr_space(as) : NULL; 172 173 ui = NULL; 174 as = NULL; 175 176 return num_frames; 177} 178#endif /* defined(__ANDROID__) */ 179