utility.c revision 13e715b491e876865e752a3a69dd6f347049a488
1/* system/debuggerd/utility.c 2** 3** Copyright 2008, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include <signal.h> 19#include <string.h> 20#include <cutils/logd.h> 21#include <sys/ptrace.h> 22#include <errno.h> 23#include <corkscrew/demangle.h> 24 25#include "utility.h" 26 27#define STACK_DEPTH 32 28#define STACK_WORDS 16 29 30void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...) { 31 char buf[512]; 32 33 va_list ap; 34 va_start(ap, fmt); 35 36 if (tfd >= 0) { 37 int len; 38 vsnprintf(buf, sizeof(buf), fmt, ap); 39 len = strlen(buf); 40 if(tfd >= 0) write(tfd, buf, len); 41 } 42 43 if (!in_tombstone_only) 44 __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap); 45 va_end(ap); 46} 47 48bool signal_has_address(int sig) { 49 switch (sig) { 50 case SIGILL: 51 case SIGFPE: 52 case SIGSEGV: 53 case SIGBUS: 54 return true; 55 default: 56 return false; 57 } 58} 59 60static void dump_backtrace(ptrace_context_t* context __attribute((unused)), 61 int tfd, int pid __attribute((unused)), bool at_fault, 62 const backtrace_frame_t* backtrace, size_t frames) { 63 _LOG(tfd, !at_fault, "\nbacktrace:\n"); 64 65 backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; 66 get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); 67 for (size_t i = 0; i < frames; i++) { 68 const backtrace_symbol_t* symbol = &backtrace_symbols[i]; 69 const char* map_name = symbol->map_info ? symbol->map_info->name : "<unknown>"; 70 const char* symbol_name = symbol->demangled_name ? symbol->demangled_name : symbol->name; 71 if (symbol_name) { 72 _LOG(tfd, !at_fault, " #%02d pc %08x %s (%s)\n", 73 (int)i, symbol->relative_pc, map_name, symbol_name); 74 } else { 75 _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 76 (int)i, symbol->relative_pc, map_name); 77 } 78 } 79 free_backtrace_symbols(backtrace_symbols, frames); 80} 81 82static void dump_stack_segment(ptrace_context_t* context, int tfd, int pid, 83 bool only_in_tombstone, uintptr_t* sp, size_t words, int label) { 84 for (size_t i = 0; i < words; i++) { 85 uint32_t stack_content; 86 if (!try_get_word(pid, *sp, &stack_content)) { 87 break; 88 } 89 90 const map_info_t* mi; 91 const symbol_t* symbol; 92 find_symbol_ptrace(context, stack_content, &mi, &symbol); 93 94 if (symbol) { 95 char* demangled_name = demangle_symbol_name(symbol->name); 96 const char* symbol_name = demangled_name ? demangled_name : symbol->name; 97 if (!i && label >= 0) { 98 _LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s (%s)\n", 99 label, *sp, stack_content, mi ? mi->name : "", symbol_name); 100 } else { 101 _LOG(tfd, only_in_tombstone, " %08x %08x %s (%s)\n", 102 *sp, stack_content, mi ? mi->name : "", symbol_name); 103 } 104 free(demangled_name); 105 } else { 106 if (!i && label >= 0) { 107 _LOG(tfd, only_in_tombstone, " #%02d %08x %08x %s\n", 108 label, *sp, stack_content, mi ? mi->name : ""); 109 } else { 110 _LOG(tfd, only_in_tombstone, " %08x %08x %s\n", 111 *sp, stack_content, mi ? mi->name : ""); 112 } 113 } 114 115 *sp += sizeof(uint32_t); 116 } 117} 118 119static void dump_stack(ptrace_context_t* context, int tfd, int pid, bool at_fault, 120 const backtrace_frame_t* backtrace, size_t frames) { 121 bool have_first = false; 122 size_t first, last; 123 for (size_t i = 0; i < frames; i++) { 124 if (backtrace[i].stack_top) { 125 if (!have_first) { 126 have_first = true; 127 first = i; 128 } 129 last = i; 130 } 131 } 132 if (!have_first) { 133 return; 134 } 135 136 _LOG(tfd, !at_fault, "\nstack:\n"); 137 138 // Dump a few words before the first frame. 139 bool only_in_tombstone = !at_fault; 140 uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t); 141 dump_stack_segment(context, tfd, pid, only_in_tombstone, &sp, STACK_WORDS, -1); 142 143 // Dump a few words from all successive frames. 144 // Only log the first 3 frames, put the rest in the tombstone. 145 for (size_t i = first; i <= last; i++) { 146 const backtrace_frame_t* frame = &backtrace[i]; 147 if (sp != frame->stack_top) { 148 _LOG(tfd, only_in_tombstone, " ........ ........\n"); 149 sp = frame->stack_top; 150 } 151 if (i - first == 3) { 152 only_in_tombstone = true; 153 } 154 if (i == last) { 155 dump_stack_segment(context, tfd, pid, only_in_tombstone, &sp, STACK_WORDS, i); 156 if (sp < frame->stack_top + frame->stack_size) { 157 _LOG(tfd, only_in_tombstone, " ........ ........\n"); 158 } 159 } else { 160 size_t words = frame->stack_size / sizeof(uint32_t); 161 if (words == 0) { 162 words = 1; 163 } else if (words > STACK_WORDS) { 164 words = STACK_WORDS; 165 } 166 dump_stack_segment(context, tfd, pid, only_in_tombstone, &sp, words, i); 167 } 168 } 169} 170 171void dump_backtrace_and_stack(ptrace_context_t* context, int tfd, pid_t tid, bool at_fault) { 172 backtrace_frame_t backtrace[STACK_DEPTH]; 173 ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH); 174 if (frames > 0) { 175 dump_backtrace(context, tfd, tid, at_fault, backtrace, frames); 176 dump_stack(context, tfd, tid, at_fault, backtrace, frames); 177 } 178} 179 180void dump_memory(int tfd, pid_t tid, uintptr_t addr, bool at_fault) { 181 char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ 182 char ascii_buffer[32]; /* actual 16 + 1 == 17 */ 183 uintptr_t p, end; 184 185 p = addr & ~3; 186 p -= 32; 187 if (p > addr) { 188 /* catch underflow */ 189 p = 0; 190 } 191 end = p + 80; 192 /* catch overflow; 'end - p' has to be multiples of 16 */ 193 while (end < p) 194 end -= 16; 195 196 /* Dump the code around PC as: 197 * addr contents ascii 198 * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q 199 * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... 200 */ 201 while (p < end) { 202 char* asc_out = ascii_buffer; 203 204 sprintf(code_buffer, "%08x ", p); 205 206 int i; 207 for (i = 0; i < 4; i++) { 208 /* 209 * If we see (data == -1 && errno != 0), we know that the ptrace 210 * call failed, probably because we're dumping memory in an 211 * unmapped or inaccessible page. I don't know if there's 212 * value in making that explicit in the output -- it likely 213 * just complicates parsing and clarifies nothing for the 214 * enlightened reader. 215 */ 216 long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL); 217 sprintf(code_buffer + strlen(code_buffer), "%08lx ", data); 218 219 int j; 220 for (j = 0; j < 4; j++) { 221 /* 222 * Our isprint() allows high-ASCII characters that display 223 * differently (often badly) in different viewers, so we 224 * just use a simpler test. 225 */ 226 char val = (data >> (j*8)) & 0xff; 227 if (val >= 0x20 && val < 0x7f) { 228 *asc_out++ = val; 229 } else { 230 *asc_out++ = '.'; 231 } 232 } 233 p += 4; 234 } 235 *asc_out = '\0'; 236 _LOG(tfd, !at_fault, " %s %s\n", code_buffer, ascii_buffer); 237 } 238} 239 240void dump_nearby_maps(ptrace_context_t* context, int tfd, pid_t tid) { 241 siginfo_t si; 242 memset(&si, 0, sizeof(si)); 243 if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { 244 _LOG(tfd, false, "cannot get siginfo for %d: %s\n", 245 tid, strerror(errno)); 246 return; 247 } 248 if (!signal_has_address(si.si_signo)) { 249 return; 250 } 251 252 uintptr_t addr = (uintptr_t) si.si_addr; 253 addr &= ~0xfff; /* round to 4K page boundary */ 254 if (addr == 0) { /* null-pointer deref */ 255 return; 256 } 257 258 _LOG(tfd, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr); 259 260 /* 261 * Search for a match, or for a hole where the match would be. The list 262 * is backward from the file content, so it starts at high addresses. 263 */ 264 bool found = false; 265 map_info_t* map = context->map_info_list; 266 map_info_t *next = NULL; 267 map_info_t *prev = NULL; 268 while (map != NULL) { 269 if (addr >= map->start && addr < map->end) { 270 found = true; 271 next = map->next; 272 break; 273 } else if (addr >= map->end) { 274 /* map would be between "prev" and this entry */ 275 next = map; 276 map = NULL; 277 break; 278 } 279 280 prev = map; 281 map = map->next; 282 } 283 284 /* 285 * Show "next" then "match" then "prev" so that the addresses appear in 286 * ascending order (like /proc/pid/maps). 287 */ 288 if (next != NULL) { 289 _LOG(tfd, false, " %08x-%08x %s\n", next->start, next->end, next->name); 290 } else { 291 _LOG(tfd, false, " (no map below)\n"); 292 } 293 if (map != NULL) { 294 _LOG(tfd, false, " %08x-%08x %s\n", map->start, map->end, map->name); 295 } else { 296 _LOG(tfd, false, " (no map for address)\n"); 297 } 298 if (prev != NULL) { 299 _LOG(tfd, false, " %08x-%08x %s\n", prev->start, prev->end, prev->name); 300 } else { 301 _LOG(tfd, false, " (no map above)\n"); 302 } 303} 304