blob: d467d8a2d0ea23cf25cce1dd77d6928416724838 [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 <string.h>
20
21#include <cutils/log.h>
22#include <backtrace/backtrace.h>
23
24#define UNW_LOCAL_ONLY
25#include <libunwind.h>
26#include <libunwind-ptrace.h>
27
28#include "common.h"
29#include "demangle.h"
30
31static bool local_get_frames(backtrace_t* backtrace) {
32 unw_context_t* context = (unw_context_t*)backtrace->private_data;
33 unw_cursor_t cursor;
34
35 int ret = unw_getcontext(context);
36 if (ret < 0) {
37 ALOGW("local_get_frames: unw_getcontext failed %d\n", ret);
38 return false;
39 }
40
41 ret = unw_init_local(&cursor, context);
42 if (ret < 0) {
43 ALOGW("local_get_frames: unw_init_local failed %d\n", ret);
44 return false;
45 }
46
47 backtrace_frame_data_t* frame;
48 bool returnValue = true;
49 backtrace->num_frames = 0;
50 uintptr_t map_start;
Christopher Ferrisa16a4e12013-10-01 17:54:11 -070051 unw_word_t value;
Christopher Ferris7fb22872013-09-27 12:43:15 -070052 do {
53 frame = &backtrace->frames[backtrace->num_frames];
54 frame->stack_size = 0;
55 frame->map_name = NULL;
56 frame->map_offset = 0;
57 frame->proc_name = NULL;
58 frame->proc_offset = 0;
59
Christopher Ferrisa16a4e12013-10-01 17:54:11 -070060 ret = unw_get_reg(&cursor, UNW_REG_IP, &value);
Christopher Ferris7fb22872013-09-27 12:43:15 -070061 if (ret < 0) {
62 ALOGW("get_frames: Failed to read IP %d\n", ret);
63 returnValue = false;
64 break;
65 }
Christopher Ferrisa16a4e12013-10-01 17:54:11 -070066 frame->pc = (uintptr_t)value;
67 ret = unw_get_reg(&cursor, UNW_REG_SP, &value);
Christopher Ferris7fb22872013-09-27 12:43:15 -070068 if (ret < 0) {
69 ALOGW("get_frames: Failed to read IP %d\n", ret);
70 returnValue = false;
71 break;
72 }
Christopher Ferrisa16a4e12013-10-01 17:54:11 -070073 frame->sp = (uintptr_t)value;
74
Christopher Ferris7fb22872013-09-27 12:43:15 -070075 if (backtrace->num_frames) {
76 backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
77 prev->stack_size = frame->sp - prev->sp;
78 }
79
80 frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
81
82 frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
83 if (frame->map_name) {
84 frame->map_offset = frame->pc - map_start;
85 }
86
87 backtrace->num_frames++;
88 ret = unw_step (&cursor);
89 } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
90
91 return returnValue;
92}
93
94bool local_get_data(backtrace_t* backtrace) {
95 unw_context_t *context = (unw_context_t*)malloc(sizeof(unw_context_t));
96 backtrace->private_data = context;
97
98 if (!local_get_frames(backtrace)) {
99 backtrace_free_data(backtrace);
100 return false;
101 }
102
103 return true;
104}
105
106void local_free_data(backtrace_t* backtrace) {
107 if (backtrace->private_data) {
108 free(backtrace->private_data);
109 backtrace->private_data = NULL;
110 }
111}
112
113char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
114 uintptr_t* offset) {
115 unw_context_t* context = (unw_context_t*)backtrace->private_data;
116 char buf[512];
117
Christopher Ferrisa16a4e12013-10-01 17:54:11 -0700118 *offset = 0;
119 unw_word_t value;
Christopher Ferris7fb22872013-09-27 12:43:15 -0700120 if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
Christopher Ferrisa16a4e12013-10-01 17:54:11 -0700121 &value, context) >= 0 && buf[0] != '\0') {
122 *offset = (uintptr_t)value;
Christopher Ferris7fb22872013-09-27 12:43:15 -0700123 char* symbol = demangle_symbol_name(buf);
124 if (!symbol) {
125 symbol = strdup(buf);
126 }
127 return symbol;
128 }
129 return NULL;
130}