blob: 20786f4d25e555b7068569e5fc757cc8cda181cd [file] [log] [blame]
Christopher Ferris7fb22872013-09-27 12:43:15 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "libbacktrace"
18
19#include <errno.h>
20#include <stdlib.h>
21#include <sys/ptrace.h>
22#include <inttypes.h>
23
24#include <cutils/log.h>
25#include <backtrace/backtrace.h>
26
27#include "common.h"
28
29bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
30 uint32_t* out_value) {
31 if (ptr & 3) {
32 ALOGW("backtrace_read_word: invalid pointer %p", (void*)ptr);
33 *out_value = (uint32_t)-1;
34 return false;
35 }
36
37 // Check if reading from the current process, or a different process.
38 if (backtrace->tid < 0) {
39 const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, ptr);
40 if (map_info && map_info->is_readable) {
41 *out_value = *(uint32_t*)ptr;
42 return true;
43 } else {
44 ALOGW("backtrace_read_word: pointer %p not in a readbale map", (void*)ptr);
45 *out_value = (uint32_t)-1;
46 return false;
47 }
48 } else {
49#if defined(__APPLE__)
50 ALOGW("read_word: MacOS does not support reading from another pid.\n");
51 return false;
52#else
53 // ptrace() returns -1 and sets errno when the operation fails.
54 // To disambiguate -1 from a valid result, we clear errno beforehand.
55 errno = 0;
56 *out_value = ptrace(PTRACE_PEEKTEXT, backtrace->tid, (void*)ptr, NULL);
57 if (*out_value == (uint32_t)-1 && errno) {
58 ALOGW("try_get_word: invalid pointer 0x%08x reading from tid %d, "
59 "ptrace() errno=%d", ptr, backtrace->tid, errno);
60 return false;
61 }
62 return true;
63 }
64#endif
65}
66
67const char *backtrace_get_map_info(
68 const backtrace_t* backtrace, uintptr_t pc, uintptr_t* start_pc) {
69 const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
70 if (map_info) {
71 if (start_pc) {
72 *start_pc = map_info->start;
73 }
74 return map_info->name;
75 }
76 return NULL;
77}
78
79void backtrace_format_frame_data(
80 const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
81 uintptr_t relative_pc;
82 const char* map_name;
83 if (frame->map_name) {
84 map_name = frame->map_name;
85 } else {
86 map_name = "<unknown>";
87 }
88 if (frame->map_offset) {
89 relative_pc = frame->map_offset;
90 } else {
91 relative_pc = frame->pc;
92 }
93 if (frame->proc_name && frame->proc_offset) {
94 snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
95 frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
96 frame->proc_name, frame->proc_offset);
97 } else if (frame->proc_name) {
98 snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR " %s (%s)", frame_num,
99 (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->proc_name);
100 } else {
101 snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR " %s", frame_num,
102 (int)sizeof(uintptr_t)*2, relative_pc, map_name);
103 }
104}
105
106void free_frame_data(backtrace_t* backtrace) {
107 for (size_t i = 0; i < backtrace->num_frames; i++) {
108 if (backtrace->frames[i].proc_name) {
109 free(backtrace->frames[i].proc_name);
110 }
111 }
112 backtrace->num_frames = 0;
113}