blob: ebbde2e021d29fc50ab8cf7fb70832d64c8df002 [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 <sys/ptrace.h>
20#include <string.h>
21
22#include <cutils/log.h>
23#include <backtrace/backtrace.h>
24
25#include <libunwind.h>
26#include <libunwind-ptrace.h>
27
28#include "common.h"
29#include "demangle.h"
30
31typedef struct {
32 unw_addr_space_t addr_space;
33 struct UPT_info* upt_info;
34} backtrace_private_t;
35
36static bool remote_get_frames(backtrace_t* backtrace) {
37 backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
38 unw_cursor_t cursor;
39 int ret = unw_init_remote(&cursor, data->addr_space, data->upt_info);
40 if (ret < 0) {
41 ALOGW("remote_get_frames: unw_init_remote failed %d\n", ret);
42 return false;
43 }
44
45 backtrace_frame_data_t* frame;
46 bool returnValue = true;
47 backtrace->num_frames = 0;
48 uintptr_t map_start;
49 do {
50 frame = &backtrace->frames[backtrace->num_frames];
51 frame->stack_size = 0;
52 frame->map_name = NULL;
53 frame->map_offset = 0;
54 frame->proc_name = NULL;
55 frame->proc_offset = 0;
56
57 ret = unw_get_reg(&cursor, UNW_REG_IP, &frame->pc);
58 if (ret < 0) {
59 ALOGW("remote_get_frames: Failed to read IP %d\n", ret);
60 returnValue = false;
61 break;
62 }
63 ret = unw_get_reg(&cursor, UNW_REG_SP, &frame->sp);
64 if (ret < 0) {
65 ALOGW("remote_get_frames: Failed to read SP %d\n", ret);
66 returnValue = false;
67 break;
68 }
69 if (backtrace->num_frames) {
70 backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
71 prev->stack_size = frame->sp - prev->sp;
72 }
73
74 frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
75
76 frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
77 if (frame->map_name) {
78 frame->map_offset = frame->pc - map_start;
79 }
80
81 backtrace->num_frames++;
82 ret = unw_step (&cursor);
83 } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
84
85 return returnValue;
86}
87
88bool remote_get_data(backtrace_t* backtrace) {
89 backtrace_private_t* data = (backtrace_private_t*)malloc(sizeof(backtrace_private_t));
90 if (!data) {
91 ALOGW("remote_get_data: Failed to allocate memory.\n");
92 backtrace_free_data(backtrace);
93 return false;
94 }
95 data->addr_space = NULL;
96 data->upt_info = NULL;
97
98 backtrace->private_data = data;
99 data->addr_space = unw_create_addr_space(&_UPT_accessors, 0);
100 if (!data->addr_space) {
101 ALOGW("remote_get_data: Failed to create unw address space.\n");
102 backtrace_free_data(backtrace);
103 return false;
104 }
105
106 data->upt_info = _UPT_create(backtrace->tid);
107 if (!data->upt_info) {
108 ALOGW("remote_get_data: Failed to create upt info.\n");
109 backtrace_free_data(backtrace);
110 return false;
111 }
112
113 if (!remote_get_frames(backtrace)) {
114 backtrace_free_data(backtrace);
115 return false;
116 }
117
118 return true;
119}
120
121void remote_free_data(backtrace_t* backtrace) {
122 if (backtrace->private_data) {
123 backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
124 if (data->upt_info) {
125 _UPT_destroy(data->upt_info);
126 data->upt_info = NULL;
127 }
128 if (data->addr_space) {
129 unw_destroy_addr_space(data->addr_space);
130 }
131
132 free(backtrace->private_data);
133 backtrace->private_data = NULL;
134 }
135}
136
137char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
138 uintptr_t* offset) {
139 backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
140 char buf[512];
141
142 if (unw_get_proc_name_by_ip(data->addr_space, pc, buf, sizeof(buf), offset,
143 data->upt_info) >= 0 && buf[0] != '\0') {
144 char* symbol = demangle_symbol_name(buf);
145 if (!symbol) {
146 symbol = strdup(buf);
147 }
148 return symbol;
149 }
150 return NULL;
151}