summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Ferris2018-01-30 21:47:24 -0600
committerChristopher Ferris2018-01-31 16:19:42 -0600
commitd70ea5ea8511ae9b9ae57b17390e4027d20e3390 (patch)
tree958dc628f9a4d173076a54bc7d012d85ecc2473e /libbacktrace
parent01ba1157325a5e6572122f5d46cfd0376b75aa98 (diff)
downloadplatform-system-core-d70ea5ea8511ae9b9ae57b17390e4027d20e3390.tar.gz
platform-system-core-d70ea5ea8511ae9b9ae57b17390e4027d20e3390.tar.xz
platform-system-core-d70ea5ea8511ae9b9ae57b17390e4027d20e3390.zip
Move dex pc frame creation into libunwindstack.
Test: Compiles, all unit tests pass. Test: Ran 137-cfi art test in interpreter and verified interpreter Test: frames still show up. Change-Id: Icea90194986faa733a873e8cf467fc2513eb5573
Diffstat (limited to 'libbacktrace')
-rw-r--r--libbacktrace/Android.bp8
-rw-r--r--libbacktrace/UnwindDexFile.cpp162
-rw-r--r--libbacktrace/UnwindDexFile.h70
-rw-r--r--libbacktrace/UnwindStack.cpp93
-rw-r--r--libbacktrace/UnwindStackMap.cpp32
-rw-r--r--libbacktrace/UnwindStackMap.h14
-rw-r--r--libbacktrace/unwind_dex_test.cpp273
7 files changed, 23 insertions, 629 deletions
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 14ae44564..10a4e4634 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,7 +50,6 @@ libbacktrace_sources = [
50 "BacktracePtrace.cpp", 50 "BacktracePtrace.cpp",
51 "thread_utils.c", 51 "thread_utils.c",
52 "ThreadEntry.cpp", 52 "ThreadEntry.cpp",
53 "UnwindDexFile.cpp",
54 "UnwindStack.cpp", 53 "UnwindStack.cpp",
55 "UnwindStackMap.cpp", 54 "UnwindStackMap.cpp",
56] 55]
@@ -110,10 +109,9 @@ cc_library {
110 static_libs: ["libasync_safe"], 109 static_libs: ["libasync_safe"],
111 }, 110 },
112 vendor: { 111 vendor: {
113 cflags: ["-DNO_LIBDEXFILE"], 112 cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
114 exclude_srcs: ["UnwindDexFile.cpp"],
115 exclude_shared_libs: ["libdexfile"], 113 exclude_shared_libs: ["libdexfile"],
116 }, 114 }
117 }, 115 },
118 whole_static_libs: ["libdemangle"], 116 whole_static_libs: ["libdemangle"],
119} 117}
@@ -145,8 +143,6 @@ cc_test {
145 "backtrace_test.cpp", 143 "backtrace_test.cpp",
146 "GetPss.cpp", 144 "GetPss.cpp",
147 "thread_utils.c", 145 "thread_utils.c",
148
149 "unwind_dex_test.cpp",
150 ], 146 ],
151 147
152 cflags: [ 148 cflags: [
diff --git a/libbacktrace/UnwindDexFile.cpp b/libbacktrace/UnwindDexFile.cpp
deleted file mode 100644
index 5780fbb9c..000000000
--- a/libbacktrace/UnwindDexFile.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
1/*
2 * Copyright (C) 2018 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 <sys/mman.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22
23#include <memory>
24
25#include <android-base/unique_fd.h>
26
27#include <dex/code_item_accessors-no_art-inl.h>
28#include <dex/compact_dex_file.h>
29#include <dex/dex_file-inl.h>
30#include <dex/dex_file_loader.h>
31#include <dex/standard_dex_file.h>
32
33#include <unwindstack/MapInfo.h>
34#include <unwindstack/Memory.h>
35
36#include "UnwindDexFile.h"
37
38UnwindDexFile* UnwindDexFile::Create(uint64_t dex_file_offset_in_memory,
39 unwindstack::Memory* memory, unwindstack::MapInfo* info) {
40 if (!info->name.empty()) {
41 std::unique_ptr<UnwindDexFileFromFile> dex_file(new UnwindDexFileFromFile);
42 if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
43 return dex_file.release();
44 }
45 }
46
47 std::unique_ptr<UnwindDexFileFromMemory> dex_file(new UnwindDexFileFromMemory);
48 if (dex_file->Open(dex_file_offset_in_memory, memory)) {
49 return dex_file.release();
50 }
51 return nullptr;
52}
53
54void UnwindDexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
55 uint64_t* method_offset) {
56 if (dex_file_ == nullptr) {
57 return;
58 }
59
60 for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
61 const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i);
62 const uint8_t* class_data = dex_file_->GetClassData(class_def);
63 if (class_data == nullptr) {
64 continue;
65 }
66 for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) {
67 if (!it.IsAtMethod()) {
68 continue;
69 }
70 const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem();
71 if (code_item == nullptr) {
72 continue;
73 }
74 art::CodeItemInstructionAccessor code(*dex_file_.get(), code_item);
75 if (!code.HasCodeItem()) {
76 continue;
77 }
78
79 uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
80 size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
81 if (offset <= dex_offset && dex_offset < offset + size) {
82 *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
83 *method_offset = dex_offset - offset;
84 return;
85 }
86 }
87 }
88}
89
90UnwindDexFileFromFile::~UnwindDexFileFromFile() {
91 if (size_ != 0) {
92 munmap(mapped_memory_, size_);
93 }
94}
95
96bool UnwindDexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
97 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
98 if (fd == -1) {
99 return false;
100 }
101 struct stat buf;
102 if (fstat(fd, &buf) == -1) {
103 return false;
104 }
105 uint64_t length;
106 if (buf.st_size < 0 ||
107 __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
108 static_cast<uint64_t>(buf.st_size) < length) {
109 return false;
110 }
111
112 mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
113 if (mapped_memory_ == MAP_FAILED) {
114 return false;
115 }
116 size_ = buf.st_size;
117
118 uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);
119
120 art::DexFile::Header* header =
121 reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
122 if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
123 !art::CompactDexFile::IsMagicValid(header->magic_)) {
124 return false;
125 }
126
127 if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
128 static_cast<uint64_t>(buf.st_size) < length) {
129 return false;
130 }
131
132 art::DexFileLoader loader;
133 std::string error_msg;
134 auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
135 false, false, &error_msg);
136 dex_file_.reset(dex.release());
137 return dex_file_ != nullptr;
138}
139
140bool UnwindDexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory) {
141 art::DexFile::Header header;
142 if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
143 return false;
144 }
145
146 if (!art::StandardDexFile::IsMagicValid(header.magic_) &&
147 !art::CompactDexFile::IsMagicValid(header.magic_)) {
148 return false;
149 }
150
151 memory_.resize(header.file_size_);
152 if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) {
153 return false;
154 }
155
156 art::DexFileLoader loader;
157 std::string error_msg;
158 auto dex =
159 loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg);
160 dex_file_.reset(dex.release());
161 return dex_file_ != nullptr;
162}
diff --git a/libbacktrace/UnwindDexFile.h b/libbacktrace/UnwindDexFile.h
deleted file mode 100644
index dd70abafd..000000000
--- a/libbacktrace/UnwindDexFile.h
+++ /dev/null
@@ -1,70 +0,0 @@
1/*
2 * Copyright (C) 2018 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_DEX_FILE_H
18#define _LIBBACKTRACE_UNWIND_DEX_FILE_H
19
20#include <stdint.h>
21
22#include <memory>
23#include <string>
24#include <vector>
25
26#include <dex/dex_file-inl.h>
27
28namespace unwindstack {
29class Memory;
30struct MapInfo;
31} // namespace unwindstack
32
33class UnwindDexFile {
34 public:
35 UnwindDexFile() = default;
36 virtual ~UnwindDexFile() = default;
37
38 void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
39
40 static UnwindDexFile* Create(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory,
41 unwindstack::MapInfo* info);
42
43 protected:
44 std::unique_ptr<const art::DexFile> dex_file_;
45};
46
47class UnwindDexFileFromFile : public UnwindDexFile {
48 public:
49 UnwindDexFileFromFile() = default;
50 virtual ~UnwindDexFileFromFile();
51
52 bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
53
54 private:
55 void* mapped_memory_ = nullptr;
56 size_t size_ = 0;
57};
58
59class UnwindDexFileFromMemory : public UnwindDexFile {
60 public:
61 UnwindDexFileFromMemory() = default;
62 virtual ~UnwindDexFileFromMemory() = default;
63
64 bool Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory);
65
66 private:
67 std::vector<uint8_t> memory_;
68};
69
70#endif // _LIBBACKTRACE_UNWIND_DEX_FILE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 158467ec2..7e2e6d05e 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -36,70 +36,15 @@
36#include <unwindstack/Regs.h> 36#include <unwindstack/Regs.h>
37#include <unwindstack/RegsGetLocal.h> 37#include <unwindstack/RegsGetLocal.h>
38 38
39#if !defined(NO_LIBDEXFILE_SUPPORT)
40#include <unwindstack/DexFiles.h>
41#endif
39#include <unwindstack/Unwinder.h> 42#include <unwindstack/Unwinder.h>
40 43
41#include "BacktraceLog.h" 44#include "BacktraceLog.h"
42#ifndef NO_LIBDEXFILE
43#include "UnwindDexFile.h"
44#endif
45#include "UnwindStack.h" 45#include "UnwindStack.h"
46#include "UnwindStackMap.h" 46#include "UnwindStackMap.h"
47 47
48static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc,
49 backtrace_frame_data_t* frame) {
50 // The DEX PC points into the .dex section within an ELF file.
51 // However, this is a BBS section manually mmaped to a .vdex file,
52 // so we need to get the following map to find the ELF data.
53 unwindstack::Maps* maps = stack_map->stack_maps();
54 auto it = maps->begin();
55 uint64_t rel_dex_pc;
56 unwindstack::MapInfo* info;
57 for (; it != maps->end(); ++it) {
58 auto entry = *it;
59 if (dex_pc >= entry->start && dex_pc < entry->end) {
60 info = entry;
61 rel_dex_pc = dex_pc - entry->start;
62 frame->map.start = entry->start;
63 frame->map.end = entry->end;
64 frame->map.offset = entry->offset;
65 frame->map.load_bias = entry->load_bias;
66 frame->map.flags = entry->flags;
67 frame->map.name = entry->name;
68 frame->rel_pc = rel_dex_pc;
69 break;
70 }
71 }
72 if (it == maps->end() || ++it == maps->end()) {
73 return;
74 }
75
76 auto entry = *it;
77 auto process_memory = stack_map->process_memory();
78 unwindstack::Elf* elf = entry->GetElf(process_memory, true);
79 if (!elf->valid()) {
80 return;
81 }
82
83 // Adjust the relative dex by the offset.
84 rel_dex_pc += entry->elf_offset;
85
86 uint64_t dex_offset;
87 if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) {
88 return;
89 }
90 frame->func_offset = dex_offset;
91 if (frame->func_name != "$dexfile") {
92 return;
93 }
94
95#ifndef NO_LIBDEXFILE
96 UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info);
97 if (dex_file != nullptr) {
98 dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset);
99 }
100#endif
101}
102
103bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, 48bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
104 std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames, 49 std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
105 std::vector<std::string>* skip_names, BacktraceUnwindError* error) { 50 std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
@@ -110,6 +55,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
110 if (stack_map->GetJitDebug() != nullptr) { 55 if (stack_map->GetJitDebug() != nullptr) {
111 unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch()); 56 unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
112 } 57 }
58#if !defined(NO_LIBDEXFILE_SUPPORT)
59 if (stack_map->GetDexFiles() != nullptr) {
60 unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
61 }
62#endif
113 unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore()); 63 unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
114 if (error != nullptr) { 64 if (error != nullptr) {
115 switch (unwinder.LastErrorCode()) { 65 switch (unwinder.LastErrorCode()) {
@@ -150,36 +100,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
150 } 100 }
151 101
152 auto unwinder_frames = unwinder.frames(); 102 auto unwinder_frames = unwinder.frames();
153 // Get the real number of frames we'll need. 103 frames->resize(unwinder.NumFrames() - num_ignore_frames);
154 size_t total_frames = 0;
155 for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) {
156 if (unwinder_frames[i].dex_pc != 0) {
157 total_frames++;
158 }
159 }
160 frames->resize(total_frames);
161 size_t cur_frame = 0; 104 size_t cur_frame = 0;
162 for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) { 105 for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
163 auto frame = &unwinder_frames[i]; 106 auto frame = &unwinder_frames[i];
164 107
165 // Inject extra 'virtual' frame that represents the dex pc data.
166 // The dex pc is magic register defined in the Mterp interpreter,
167 // and thus it will be restored/observed in the frame after it.
168 // Adding the dex frame first here will create something like:
169 // #7 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
170 // #8 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
171 // #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
172 if (frame->dex_pc != 0) {
173 backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
174 dex_frame->num = cur_frame++;
175 dex_frame->pc = frame->dex_pc;
176 dex_frame->rel_pc = frame->dex_pc;
177 dex_frame->sp = frame->sp;
178 dex_frame->stack_size = 0;
179 dex_frame->func_offset = 0;
180 FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
181 }
182
183 backtrace_frame_data_t* back_frame = &frames->at(cur_frame); 108 backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
184 109
185 back_frame->num = cur_frame++; 110 back_frame->num = cur_frame++;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 97f8d782d..1622e30d4 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -26,20 +26,11 @@
26#include <unwindstack/MapInfo.h> 26#include <unwindstack/MapInfo.h>
27#include <unwindstack/Maps.h> 27#include <unwindstack/Maps.h>
28 28
29#include "UnwindDexFile.h"
30#include "UnwindStackMap.h" 29#include "UnwindStackMap.h"
31 30
32//------------------------------------------------------------------------- 31//-------------------------------------------------------------------------
33UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {} 32UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
34 33
35UnwindStackMap::~UnwindStackMap() {
36#ifndef NO_LIBDEXFILE
37 for (auto& entry : dex_files_) {
38 delete entry.second;
39 }
40#endif
41}
42
43bool UnwindStackMap::Build() { 34bool UnwindStackMap::Build() {
44 if (pid_ == 0) { 35 if (pid_ == 0) {
45 pid_ = getpid(); 36 pid_ = getpid();
@@ -54,6 +45,9 @@ bool UnwindStackMap::Build() {
54 // Create a JitDebug object for getting jit unwind information. 45 // Create a JitDebug object for getting jit unwind information.
55 std::vector<std::string> search_libs_{"libart.so", "libartd.so"}; 46 std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
56 jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_)); 47 jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
48#if !defined(NO_LIBDEXFILE_SUPPORT)
49 dex_files_.reset(new unwindstack::DexFiles(process_memory_));
50#endif
57 51
58 if (!stack_maps_->Parse()) { 52 if (!stack_maps_->Parse()) {
59 return false; 53 return false;
@@ -127,26 +121,6 @@ std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() {
127 return process_memory_; 121 return process_memory_;
128} 122}
129 123
130#ifdef NO_LIBDEXFILE
131UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) {
132 return nullptr;
133}
134#else
135UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) {
136 // Lock while we get the data.
137 std::lock_guard<std::mutex> guard(dex_lock_);
138 UnwindDexFile* dex_file;
139 auto entry = dex_files_.find(dex_file_offset);
140 if (entry == dex_files_.end()) {
141 dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info);
142 dex_files_[dex_file_offset] = dex_file;
143 } else {
144 dex_file = entry->second;
145 }
146 return dex_file;
147}
148#endif
149
150UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {} 124UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
151 125
152bool UnwindStackOfflineMap::Build() { 126bool UnwindStackOfflineMap::Build() {
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index be5c59e74..94cbfb2a0 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -27,6 +27,9 @@
27 27
28#include <backtrace/Backtrace.h> 28#include <backtrace/Backtrace.h>
29#include <backtrace/BacktraceMap.h> 29#include <backtrace/BacktraceMap.h>
30#if !defined(NO_LIBDEXFILE_SUPPORT)
31#include <unwindstack/DexFiles.h>
32#endif
30#include <unwindstack/JitDebug.h> 33#include <unwindstack/JitDebug.h>
31#include <unwindstack/Maps.h> 34#include <unwindstack/Maps.h>
32 35
@@ -36,7 +39,7 @@ class UnwindDexFile;
36class UnwindStackMap : public BacktraceMap { 39class UnwindStackMap : public BacktraceMap {
37 public: 40 public:
38 explicit UnwindStackMap(pid_t pid); 41 explicit UnwindStackMap(pid_t pid);
39 ~UnwindStackMap(); 42 ~UnwindStackMap() = default;
40 43
41 bool Build() override; 44 bool Build() override;
42 45
@@ -51,7 +54,9 @@ class UnwindStackMap : public BacktraceMap {
51 54
52 unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); } 55 unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
53 56
54 UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info); 57#if !defined(NO_LIBDEXFILE_SUPPORT)
58 unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
59#endif
55 60
56 protected: 61 protected:
57 uint64_t GetLoadBias(size_t index) override; 62 uint64_t GetLoadBias(size_t index) override;
@@ -59,9 +64,8 @@ class UnwindStackMap : public BacktraceMap {
59 std::unique_ptr<unwindstack::Maps> stack_maps_; 64 std::unique_ptr<unwindstack::Maps> stack_maps_;
60 std::shared_ptr<unwindstack::Memory> process_memory_; 65 std::shared_ptr<unwindstack::Memory> process_memory_;
61 std::unique_ptr<unwindstack::JitDebug> jit_debug_; 66 std::unique_ptr<unwindstack::JitDebug> jit_debug_;
62#ifndef NO_LIBDEXFILE 67#if !defined(NO_LIBDEXFILE_SUPPORT)
63 std::mutex dex_lock_; 68 std::unique_ptr<unwindstack::DexFiles> dex_files_;
64 std::unordered_map<uint64_t, UnwindDexFile*> dex_files_;
65#endif 69#endif
66}; 70};
67 71
diff --git a/libbacktrace/unwind_dex_test.cpp b/libbacktrace/unwind_dex_test.cpp
deleted file mode 100644
index 449e66296..000000000
--- a/libbacktrace/unwind_dex_test.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
1/*
2 * Copyright (C) 2018 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 <sys/types.h>
19#include <unistd.h>
20
21#include <unordered_map>
22
23#include <android-base/test_utils.h>
24
25#include <unwindstack/MapInfo.h>
26#include <unwindstack/Memory.h>
27
28#include <dex/code_item_accessors-no_art-inl.h>
29#include <dex/standard_dex_file.h>
30
31#include <gtest/gtest.h>
32
33#include "UnwindDexFile.h"
34
35class MemoryFake : public unwindstack::Memory {
36 public:
37 MemoryFake() = default;
38 virtual ~MemoryFake() = default;
39
40 size_t Read(uint64_t addr, void* buffer, size_t size) override;
41
42 void SetMemory(uint64_t addr, const void* memory, size_t length);
43
44 void Clear() { data_.clear(); }
45
46 private:
47 std::unordered_map<uint64_t, uint8_t> data_;
48};
49
50void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
51 const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
52 for (size_t i = 0; i < length; i++, addr++) {
53 auto value = data_.find(addr);
54 if (value != data_.end()) {
55 value->second = src[i];
56 } else {
57 data_.insert({addr, src[i]});
58 }
59 }
60}
61
62size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
63 uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
64 for (size_t i = 0; i < size; i++, addr++) {
65 auto value = data_.find(addr);
66 if (value == data_.end()) {
67 return i;
68 }
69 dst[i] = value->second;
70 }
71 return size;
72}
73
74// Borrowed from art/dex/dex_file_test.cc.
75static constexpr uint32_t kDexData[] = {
76 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
77 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
78 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
79 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
80 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
81 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
82 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
83 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
84 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
85 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
86 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
87 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
88 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
89 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
90 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
91 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
92 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
93};
94
95TEST(UnwindDexTest, from_file_open_non_exist) {
96 UnwindDexFileFromFile dex_file;
97 ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
98}
99
100TEST(UnwindDexTest, from_file_open_too_small) {
101 TemporaryFile tf;
102 ASSERT_TRUE(tf.fd != -1);
103
104 ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
105 static_cast<size_t>(
106 TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
107
108 // Header too small.
109 UnwindDexFileFromFile dex_file;
110 ASSERT_FALSE(dex_file.Open(0, tf.path));
111
112 // Header correct, file too small.
113 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
114 ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
115 tf.fd, kDexData, sizeof(art::DexFile::Header)))));
116 ASSERT_FALSE(dex_file.Open(0, tf.path));
117}
118
119TEST(UnwindDexTest, from_file_open) {
120 TemporaryFile tf;
121 ASSERT_TRUE(tf.fd != -1);
122
123 ASSERT_EQ(sizeof(kDexData),
124 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
125
126 UnwindDexFileFromFile dex_file;
127 ASSERT_TRUE(dex_file.Open(0, tf.path));
128}
129
130TEST(UnwindDexTest, from_file_open_non_zero_offset) {
131 TemporaryFile tf;
132 ASSERT_TRUE(tf.fd != -1);
133
134 ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
135 ASSERT_EQ(sizeof(kDexData),
136 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
137
138 UnwindDexFileFromFile dex_file;
139 ASSERT_TRUE(dex_file.Open(0x100, tf.path));
140}
141
142TEST(UnwindDexTest, from_memory_fail_too_small_for_header) {
143 MemoryFake memory;
144
145 memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
146 UnwindDexFileFromMemory dex_file;
147
148 ASSERT_FALSE(dex_file.Open(0x1000, &memory));
149}
150
151TEST(UnwindDexTest, from_memory_fail_too_small_for_data) {
152 MemoryFake memory;
153
154 memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
155 UnwindDexFileFromMemory dex_file;
156
157 ASSERT_FALSE(dex_file.Open(0x1000, &memory));
158}
159
160TEST(UnwindDexTest, from_memory_open) {
161 MemoryFake memory;
162
163 memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
164 UnwindDexFileFromMemory dex_file;
165
166 ASSERT_TRUE(dex_file.Open(0x1000, &memory));
167}
168
169TEST(UnwindDexTest, create_using_file) {
170 TemporaryFile tf;
171 ASSERT_TRUE(tf.fd != -1);
172
173 ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
174 ASSERT_EQ(sizeof(kDexData),
175 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
176
177 MemoryFake memory;
178 unwindstack::MapInfo info(0, 0x10000, 0, 0x5, tf.path);
179 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x500, &memory, &info));
180 ASSERT_TRUE(dex_file != nullptr);
181}
182
183TEST(UnwindDexTest, create_using_file_non_zero_start) {
184 TemporaryFile tf;
185 ASSERT_TRUE(tf.fd != -1);
186
187 ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
188 ASSERT_EQ(sizeof(kDexData),
189 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
190
191 MemoryFake memory;
192 unwindstack::MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
193 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x600, &memory, &info));
194 ASSERT_TRUE(dex_file != nullptr);
195}
196
197TEST(UnwindDexTest, create_using_file_non_zero_offset) {
198 TemporaryFile tf;
199 ASSERT_TRUE(tf.fd != -1);
200
201 ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
202 ASSERT_EQ(sizeof(kDexData),
203 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
204
205 MemoryFake memory;
206 unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
207 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x400, &memory, &info));
208 ASSERT_TRUE(dex_file != nullptr);
209}
210
211TEST(UnwindDexTest, create_using_memory_empty_file) {
212 MemoryFake memory;
213 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
214 unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
215 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
216 ASSERT_TRUE(dex_file != nullptr);
217}
218
219TEST(UnwindDexTest, create_using_memory_file_does_not_exist) {
220 MemoryFake memory;
221 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
222 unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
223 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
224 ASSERT_TRUE(dex_file != nullptr);
225}
226
227TEST(UnwindDexTest, create_using_memory_file_is_malformed) {
228 TemporaryFile tf;
229 ASSERT_TRUE(tf.fd != -1);
230
231 ASSERT_EQ(sizeof(kDexData) - 10,
232 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
233
234 MemoryFake memory;
235 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
236 unwindstack::MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
237 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
238 ASSERT_TRUE(dex_file != nullptr);
239
240 // Check it came from memory by clearing memory and verifying it fails.
241 memory.Clear();
242 dex_file.reset(UnwindDexFile::Create(0x4000, &memory, &info));
243 ASSERT_TRUE(dex_file == nullptr);
244}
245
246TEST(UnwindDexTest, get_method_not_opened) {
247 std::string method("something");
248 uint64_t method_offset = 100;
249 UnwindDexFile dex_file;
250 dex_file.GetMethodInformation(0x100, &method, &method_offset);
251 EXPECT_EQ("something", method);
252 EXPECT_EQ(100U, method_offset);
253}
254
255TEST(UnwindDexTest, get_method) {
256 MemoryFake memory;
257 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
258 unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
259 std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
260 ASSERT_TRUE(dex_file != nullptr);
261
262 std::string method;
263 uint64_t method_offset;
264 dex_file->GetMethodInformation(0x102, &method, &method_offset);
265 EXPECT_EQ("Main.<init>", method);
266 EXPECT_EQ(2U, method_offset);
267
268 method = "not_in_a_method";
269 method_offset = 0x123;
270 dex_file->GetMethodInformation(0x100000, &method, &method_offset);
271 EXPECT_EQ("not_in_a_method", method);
272 EXPECT_EQ(0x123U, method_offset);
273}