diff options
author | Christopher Ferris | 2018-01-30 21:47:24 -0600 |
---|---|---|
committer | Christopher Ferris | 2018-01-31 16:19:42 -0600 |
commit | d70ea5ea8511ae9b9ae57b17390e4027d20e3390 (patch) | |
tree | 958dc628f9a4d173076a54bc7d012d85ecc2473e /libbacktrace | |
parent | 01ba1157325a5e6572122f5d46cfd0376b75aa98 (diff) | |
download | platform-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.bp | 8 | ||||
-rw-r--r-- | libbacktrace/UnwindDexFile.cpp | 162 | ||||
-rw-r--r-- | libbacktrace/UnwindDexFile.h | 70 | ||||
-rw-r--r-- | libbacktrace/UnwindStack.cpp | 93 | ||||
-rw-r--r-- | libbacktrace/UnwindStackMap.cpp | 32 | ||||
-rw-r--r-- | libbacktrace/UnwindStackMap.h | 14 | ||||
-rw-r--r-- | libbacktrace/unwind_dex_test.cpp | 273 |
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 | |||
38 | UnwindDexFile* 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 | |||
54 | void 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 | |||
90 | UnwindDexFileFromFile::~UnwindDexFileFromFile() { | ||
91 | if (size_ != 0) { | ||
92 | munmap(mapped_memory_, size_); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | bool 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 | |||
140 | bool 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 | |||
28 | namespace unwindstack { | ||
29 | class Memory; | ||
30 | struct MapInfo; | ||
31 | } // namespace unwindstack | ||
32 | |||
33 | class 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 | |||
47 | class 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 | |||
59 | class 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 | ||
48 | static 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 | |||
103 | bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, | 48 | bool 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 | //------------------------------------------------------------------------- |
33 | UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {} | 32 | UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {} |
34 | 33 | ||
35 | UnwindStackMap::~UnwindStackMap() { | ||
36 | #ifndef NO_LIBDEXFILE | ||
37 | for (auto& entry : dex_files_) { | ||
38 | delete entry.second; | ||
39 | } | ||
40 | #endif | ||
41 | } | ||
42 | |||
43 | bool UnwindStackMap::Build() { | 34 | bool 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 | ||
131 | UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) { | ||
132 | return nullptr; | ||
133 | } | ||
134 | #else | ||
135 | UnwindDexFile* 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 | |||
150 | UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {} | 124 | UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {} |
151 | 125 | ||
152 | bool UnwindStackOfflineMap::Build() { | 126 | bool 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; | |||
36 | class UnwindStackMap : public BacktraceMap { | 39 | class 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 | |||
35 | class 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 | |||
50 | void 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 | |||
62 | size_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. | ||
75 | static 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 | |||
95 | TEST(UnwindDexTest, from_file_open_non_exist) { | ||
96 | UnwindDexFileFromFile dex_file; | ||
97 | ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist")); | ||
98 | } | ||
99 | |||
100 | TEST(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 | |||
119 | TEST(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 | |||
130 | TEST(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 | |||
142 | TEST(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 | |||
151 | TEST(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 | |||
160 | TEST(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 | |||
169 | TEST(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 | |||
183 | TEST(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 | |||
197 | TEST(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 | |||
211 | TEST(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 | |||
219 | TEST(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 | |||
227 | TEST(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 | |||
246 | TEST(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 | |||
255 | TEST(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 | } | ||