summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Ferris2017-08-03 14:08:34 -0500
committerGerrit Code Review2017-08-03 14:08:34 -0500
commit172b1d000844536bb4b268c2450211c97031d49d (patch)
tree5953d4f6b2318f210a422969313e2cce2310a71a
parent472808a5701515a7ce7180c625f4f5bcef0e792e (diff)
parent6f3981c181677830c33093411b51ad6b0bf2e337 (diff)
downloadplatform-system-core-172b1d000844536bb4b268c2450211c97031d49d.tar.gz
platform-system-core-172b1d000844536bb4b268c2450211c97031d49d.tar.xz
platform-system-core-172b1d000844536bb4b268c2450211c97031d49d.zip
Merge "Add support for the new unwind method."
-rw-r--r--libbacktrace/Android.bp9
-rw-r--r--libbacktrace/UnwindStack.cpp220
-rw-r--r--libbacktrace/UnwindStack.h56
-rw-r--r--libbacktrace/UnwindStackMap.cpp94
-rw-r--r--libbacktrace/UnwindStackMap.h41
-rw-r--r--libbacktrace/include/backtrace/Backtrace.h2
-rw-r--r--libbacktrace/include/backtrace/BacktraceMap.h2
-rw-r--r--libunwindstack/Android.bp1
-rw-r--r--libunwindstack/include/unwindstack/MapInfo.h1
9 files changed, 426 insertions, 0 deletions
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index e02aaf216..c58d77733 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -53,6 +53,8 @@ libbacktrace_sources = [
53 "UnwindCurrent.cpp", 53 "UnwindCurrent.cpp",
54 "UnwindMap.cpp", 54 "UnwindMap.cpp",
55 "UnwindPtrace.cpp", 55 "UnwindPtrace.cpp",
56 "UnwindStack.cpp",
57 "UnwindStackMap.cpp",
56] 58]
57 59
58cc_library_headers { 60cc_library_headers {
@@ -84,6 +86,7 @@ cc_library {
84 "libbase", 86 "libbase",
85 "liblog", 87 "liblog",
86 "libunwind", 88 "libunwind",
89 "libunwindstack",
87 ], 90 ],
88 91
89 static_libs: ["libcutils"], 92 static_libs: ["libcutils"],
@@ -97,6 +100,7 @@ cc_library {
97 "libbase", 100 "libbase",
98 "liblog", 101 "liblog",
99 "libunwind", 102 "libunwind",
103 "libunwindstack",
100 ], 104 ],
101 105
102 static_libs: ["libcutils"], 106 static_libs: ["libcutils"],
@@ -108,6 +112,7 @@ cc_library {
108 "libbase", 112 "libbase",
109 "liblog", 113 "liblog",
110 "libunwind", 114 "libunwind",
115 "libunwindstack",
111 ], 116 ],
112 117
113 static_libs: ["libasync_safe", "libcutils"], 118 static_libs: ["libasync_safe", "libcutils"],
@@ -130,11 +135,13 @@ cc_library_shared {
130 linux: { 135 linux: {
131 shared_libs: [ 136 shared_libs: [
132 "libunwind", 137 "libunwind",
138 "libunwindstack",
133 ], 139 ],
134 }, 140 },
135 android: { 141 android: {
136 shared_libs: [ 142 shared_libs: [
137 "libunwind", 143 "libunwind",
144 "libunwindstack",
138 ], 145 ],
139 }, 146 },
140 } 147 }
@@ -161,6 +168,7 @@ cc_library_static {
161 shared_libs = [ 168 shared_libs = [
162 "libbase", 169 "libbase",
163 "libunwind", 170 "libunwind",
171 "libunwindstack",
164 "libziparchive", 172 "libziparchive",
165 ], 173 ],
166} 174}
@@ -192,6 +200,7 @@ cc_test {
192 "libcutils", 200 "libcutils",
193 "liblog", 201 "liblog",
194 "libunwind", 202 "libunwind",
203 "libunwindstack",
195 ], 204 ],
196 205
197 group_static_libs: true, 206 group_static_libs: true,
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
new file mode 100644
index 000000000..baf0ada28
--- /dev/null
+++ b/libbacktrace/UnwindStack.cpp
@@ -0,0 +1,220 @@
1/*
2 * Copyright (C) 2017 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 _GNU_SOURCE 1
18#include <assert.h>
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <ucontext.h>
23
24#include <memory>
25#include <string>
26
27#if !defined(__ANDROID__)
28#include <cutils/threads.h>
29#endif
30
31#include <backtrace/Backtrace.h>
32#include <unwindstack/Elf.h>
33#include <unwindstack/MapInfo.h>
34#include <unwindstack/Maps.h>
35#include <unwindstack/Memory.h>
36#include <unwindstack/Regs.h>
37#include <unwindstack/RegsGetLocal.h>
38
39#include "BacktraceLog.h"
40#include "UnwindStack.h"
41#include "UnwindStackMap.h"
42
43static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t pc,
44 uintptr_t* offset) {
45 *offset = 0;
46 unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
47
48 // Get the map for this
49 unwindstack::MapInfo* map_info = maps->Find(pc);
50 if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
51 return "";
52 }
53
54 unwindstack::Elf* elf = map_info->GetElf(pid, true);
55
56 std::string name;
57 uint64_t func_offset;
58 if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
59 return "";
60 }
61 *offset = func_offset;
62 return name;
63}
64
65static bool IsUnwindLibrary(const std::string& map_name) {
66 const std::string library(basename(map_name.c_str()));
67 return library == "libunwindstack.so" || library == "libbacktrace.so";
68}
69
70static bool Unwind(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs,
71 BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames,
72 size_t num_ignore_frames) {
73 unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
74 bool adjust_rel_pc = false;
75 size_t num_frames = 0;
76 frames->clear();
77 while (num_frames < MAX_BACKTRACE_FRAMES) {
78 if (regs->pc() == 0) {
79 break;
80 }
81 unwindstack::MapInfo* map_info = maps->Find(regs->pc());
82 if (map_info == nullptr) {
83 break;
84 }
85
86 unwindstack::Elf* elf = map_info->GetElf(pid, true);
87 uint64_t rel_pc = regs->pc();
88 if (map_info != nullptr) {
89 rel_pc = elf->GetRelPc(regs->pc(), map_info);
90 }
91
92 bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name);
93 if (num_ignore_frames == 0 && !skip_frame) {
94 uint64_t adjusted_rel_pc = rel_pc;
95 if (map_info != nullptr && adjust_rel_pc) {
96 adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
97 }
98 frames->resize(num_frames + 1);
99 backtrace_frame_data_t* frame = &frames->at(num_frames);
100 frame->num = num_frames;
101 if (map_info != nullptr) {
102 // This will point to the adjusted absolute pc. regs->pc() is
103 // unaltered.
104 frame->pc = map_info->start + adjusted_rel_pc;
105 } else {
106 frame->pc = rel_pc;
107 }
108 frame->sp = regs->sp();
109 frame->rel_pc = adjusted_rel_pc;
110 frame->stack_size = 0;
111
112 frame->map.start = map_info->start;
113 frame->map.end = map_info->end;
114 frame->map.offset = map_info->offset;
115 frame->map.load_bias = elf->GetLoadBias();
116 frame->map.flags = map_info->flags;
117 frame->map.name = map_info->name;
118
119 uint64_t func_offset = 0;
120 if (!elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
121 frame->func_name = "";
122 }
123 frame->func_offset = func_offset;
124 if (num_frames > 0) {
125 // Set the stack size for the previous frame.
126 backtrace_frame_data_t* prev = &frames->at(num_frames - 1);
127 prev->stack_size = frame->sp - prev->sp;
128 }
129 num_frames++;
130 } else if (!skip_frame && num_ignore_frames > 0) {
131 num_ignore_frames--;
132 }
133 adjust_rel_pc = true;
134
135 // Do not unwind through a device map.
136 if (map_info->flags & PROT_DEVICE_MAP) {
137 break;
138 }
139 unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
140 if (sp_info->flags & PROT_DEVICE_MAP) {
141 break;
142 }
143
144 if (!elf->Step(rel_pc + map_info->elf_offset, regs, memory)) {
145 break;
146 }
147 }
148
149 return true;
150}
151
152UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
153 : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {}
154
155std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
156 return ::GetFunctionName(Pid(), GetMap(), pc, offset);
157}
158
159bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
160 std::unique_ptr<unwindstack::Regs> regs;
161 if (ucontext == nullptr) {
162 regs.reset(unwindstack::Regs::CreateFromLocal());
163 // Fill in the registers from this function. Do it here to avoid
164 // one extra function call appearing in the unwind.
165 unwindstack::RegsGetLocal(regs.get());
166 } else {
167 regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), ucontext));
168 }
169
170 error_ = BACKTRACE_UNWIND_NO_ERROR;
171 return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
172}
173
174UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
175 : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {}
176
177std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
178 return ::GetFunctionName(Pid(), GetMap(), pc, offset);
179}
180
181bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
182 std::unique_ptr<unwindstack::Regs> regs;
183 if (context == nullptr) {
184 uint32_t machine_type;
185 regs.reset(unwindstack::Regs::RemoteGet(Tid(), &machine_type));
186 } else {
187 regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), context));
188 }
189
190 error_ = BACKTRACE_UNWIND_NO_ERROR;
191 return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
192}
193
194Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
195 if (pid == BACKTRACE_CURRENT_PROCESS) {
196 pid = getpid();
197 if (tid == BACKTRACE_CURRENT_THREAD) {
198 tid = gettid();
199 }
200 } else if (tid == BACKTRACE_CURRENT_THREAD) {
201 tid = pid;
202 }
203
204 if (map == nullptr) {
205// This would cause the wrong type of map object to be created, so disallow.
206#if defined(__ANDROID__)
207 __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
208 "Backtrace::CreateNew() must be called with a real map pointer.");
209#else
210 BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
211 abort();
212#endif
213 }
214
215 if (pid == getpid()) {
216 return new UnwindStackCurrent(pid, tid, map);
217 } else {
218 return new UnwindStackPtrace(pid, tid, map);
219 }
220}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
new file mode 100644
index 000000000..32d1f51ab
--- /dev/null
+++ b/libbacktrace/UnwindStack.h
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2017 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#ifndef _LIBBACKTRACE_UNWIND_STACK_H
18#define _LIBBACKTRACE_UNWIND_STACK_H
19
20#include <stdint.h>
21
22#include <string>
23
24#include <backtrace/BacktraceMap.h>
25#include <unwindstack/Memory.h>
26
27#include "BacktraceCurrent.h"
28#include "BacktracePtrace.h"
29
30class UnwindStackCurrent : public BacktraceCurrent {
31 public:
32 UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
33 virtual ~UnwindStackCurrent() = default;
34
35 std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
36
37 bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
38
39 private:
40 std::unique_ptr<unwindstack::Memory> memory_;
41};
42
43class UnwindStackPtrace : public BacktracePtrace {
44 public:
45 UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
46 virtual ~UnwindStackPtrace() = default;
47
48 bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
49
50 std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
51
52 private:
53 std::unique_ptr<unwindstack::Memory> memory_;
54};
55
56#endif // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
new file mode 100644
index 000000000..ba9fd87d7
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -0,0 +1,94 @@
1/*
2 * Copyright (C) 2017 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#include <stdint.h>
18#include <stdlib.h>
19#include <sys/types.h>
20
21#include <backtrace/BacktraceMap.h>
22#include <unwindstack/Elf.h>
23#include <unwindstack/MapInfo.h>
24#include <unwindstack/Maps.h>
25
26#include "UnwindStackMap.h"
27
28//-------------------------------------------------------------------------
29UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
30
31bool UnwindStackMap::Build() {
32 if (pid_ == 0) {
33 pid_ = getpid();
34 stack_maps_.reset(new unwindstack::LocalMaps);
35 } else {
36 stack_maps_.reset(new unwindstack::RemoteMaps(pid_));
37 }
38
39 if (!stack_maps_->Parse()) {
40 return false;
41 }
42
43 // Iterate through the maps and fill in the backtrace_map_t structure.
44 for (auto& map_info : *stack_maps_) {
45 backtrace_map_t map;
46 map.start = map_info.start;
47 map.end = map_info.end;
48 map.offset = map_info.offset;
49 // Set to -1 so that it is demand loaded.
50 map.load_bias = static_cast<uintptr_t>(-1);
51 map.flags = map_info.flags;
52 map.name = map_info.name;
53
54 maps_.push_back(map);
55 }
56
57 return true;
58}
59
60void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
61 BacktraceMap::FillIn(addr, map);
62 if (map->load_bias != static_cast<uintptr_t>(-1)) {
63 return;
64 }
65
66 // Fill in the load_bias.
67 unwindstack::MapInfo* map_info = stack_maps_->Find(addr);
68 if (map_info == nullptr) {
69 return;
70 }
71 unwindstack::Elf* elf = map_info->GetElf(pid_, true);
72 map->load_bias = elf->GetLoadBias();
73}
74
75//-------------------------------------------------------------------------
76// BacktraceMap create function.
77//-------------------------------------------------------------------------
78BacktraceMap* BacktraceMap::CreateNew(pid_t pid, bool uncached) {
79 BacktraceMap* map;
80
81 if (uncached) {
82 // Force use of the base class to parse the maps when this call is made.
83 map = new BacktraceMap(pid);
84 } else if (pid == getpid()) {
85 map = new UnwindStackMap(0);
86 } else {
87 map = new UnwindStackMap(pid);
88 }
89 if (!map->Build()) {
90 delete map;
91 return nullptr;
92 }
93 return map;
94}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
new file mode 100644
index 000000000..7885b7428
--- /dev/null
+++ b/libbacktrace/UnwindStackMap.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2017 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#ifndef _LIBBACKTRACE_UNWINDSTACK_MAP_H
18#define _LIBBACKTRACE_UNWINDSTACK_MAP_H
19
20#include <stdint.h>
21#include <sys/types.h>
22
23#include <backtrace/BacktraceMap.h>
24#include <unwindstack/Maps.h>
25
26class UnwindStackMap : public BacktraceMap {
27 public:
28 explicit UnwindStackMap(pid_t pid);
29 ~UnwindStackMap() = default;
30
31 bool Build() override;
32
33 void FillIn(uintptr_t addr, backtrace_map_t* map) override;
34
35 unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
36
37 protected:
38 std::unique_ptr<unwindstack::Maps> stack_maps_;
39};
40
41#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index b919e81c6..d67ea50c9 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -90,6 +90,8 @@ public:
90 // If map is NULL, then create the map and manage it internally. 90 // If map is NULL, then create the map and manage it internally.
91 // If map is not NULL, the map is still owned by the caller. 91 // If map is not NULL, the map is still owned by the caller.
92 static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL); 92 static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
93 // Same as above, but uses a different underlying unwinder.
94 static Backtrace* CreateNew(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
93 95
94 // Create an offline Backtrace object that can be used to do an unwind without a process 96 // Create an offline Backtrace object that can be used to do an unwind without a process
95 // that is still running. If cache_file is set to true, then elf information will be cached 97 // that is still running. If cache_file is set to true, then elf information will be cached
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 02a50f738..963c34b64 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -52,6 +52,8 @@ public:
52 // Passing a map created with uncached set to true to Backtrace::Create() 52 // Passing a map created with uncached set to true to Backtrace::Create()
53 // is unsupported. 53 // is unsupported.
54 static BacktraceMap* Create(pid_t pid, bool uncached = false); 54 static BacktraceMap* Create(pid_t pid, bool uncached = false);
55 // Same as above, but is compatible with the new unwinder.
56 static BacktraceMap* CreateNew(pid_t pid, bool uncached = false);
55 57
56 static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps); 58 static BacktraceMap* Create(pid_t pid, const std::vector<backtrace_map_t>& maps);
57 59
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 78ae40988..b971a9eda 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -34,6 +34,7 @@ cc_defaults {
34 34
35cc_library { 35cc_library {
36 name: "libunwindstack", 36 name: "libunwindstack",
37 vendor_available: true,
37 defaults: ["libunwindstack_flags"], 38 defaults: ["libunwindstack_flags"],
38 export_include_dirs: ["include"], 39 export_include_dirs: ["include"],
39 40
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 2a97dde09..185476799 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -41,6 +41,7 @@ struct MapInfo {
41 uint64_t elf_offset; 41 uint64_t elf_offset;
42 42
43 Memory* CreateMemory(pid_t pid); 43 Memory* CreateMemory(pid_t pid);
44 // This function guarantees it will never return nullptr.
44 Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false); 45 Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
45}; 46};
46 47