system/core
修訂 | e5c4d62ba3fca09fed86ec605542b2be74a59851 (tree) |
---|---|
時間 | 2019-04-12 21:55:50 |
作者 | David Srbecky <dsrbecky@goog...> |
Commiter | David Srbecky |
Revert "Check for data races when reading JIT/DEX entries."
This reverts commit 85b5fecec920208ec43b42488f08d4c2e5aaeda2.
Reason for revert: Breaks ART tests, reverting to investigate.
Exempt-From-Owner-Approval: Revert.
(cherry picked from commit b9cc4fbb268652744c812415cb2e5d1fbe04879a)
Bug: 130406806
Change-Id: I634e37060b97484d627fc544e3b406fd90aaa784
@@ -48,6 +48,7 @@ | ||
48 | 48 | #define ATRACE_TAG ATRACE_TAG_BIONIC |
49 | 49 | #include <utils/Trace.h> |
50 | 50 | |
51 | +#include <unwindstack/DexFiles.h> | |
51 | 52 | #include <unwindstack/JitDebug.h> |
52 | 53 | #include <unwindstack/Maps.h> |
53 | 54 | #include <unwindstack/Memory.h> |
@@ -566,7 +567,7 @@ int main(int argc, char** argv) { | ||
566 | 567 | |
567 | 568 | // TODO: Use seccomp to lock ourselves down. |
568 | 569 | unwindstack::UnwinderFromPid unwinder(256, vm_pid); |
569 | - if (!unwinder.Init()) { | |
570 | + if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { | |
570 | 571 | LOG(FATAL) << "Failed to init unwinder object."; |
571 | 572 | } |
572 | 573 |
@@ -42,6 +42,7 @@ | ||
42 | 42 | #include <android-base/file.h> |
43 | 43 | #include <android-base/unique_fd.h> |
44 | 44 | #include <async_safe/log.h> |
45 | +#include <unwindstack/DexFiles.h> | |
45 | 46 | #include <unwindstack/JitDebug.h> |
46 | 47 | #include <unwindstack/Maps.h> |
47 | 48 | #include <unwindstack/Memory.h> |
@@ -80,12 +81,12 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) { | ||
80 | 81 | thread.pid = getpid(); |
81 | 82 | thread.tid = gettid(); |
82 | 83 | thread.thread_name = get_thread_name(gettid()); |
83 | - thread.registers.reset( | |
84 | - unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); | |
84 | + unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch(); | |
85 | + thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext)); | |
85 | 86 | |
86 | 87 | // TODO: Create this once and store it in a global? |
87 | 88 | unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid()); |
88 | - if (unwinder.Init()) { | |
89 | + if (unwinder.Init(arch)) { | |
89 | 90 | dump_backtrace_thread(output_fd, &unwinder, thread); |
90 | 91 | } else { |
91 | 92 | async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder."); |
@@ -45,6 +45,7 @@ | ||
45 | 45 | #include <log/log.h> |
46 | 46 | #include <log/logprint.h> |
47 | 47 | #include <private/android_filesystem_config.h> |
48 | +#include <unwindstack/DexFiles.h> | |
48 | 49 | #include <unwindstack/JitDebug.h> |
49 | 50 | #include <unwindstack/Maps.h> |
50 | 51 | #include <unwindstack/Memory.h> |
@@ -650,7 +651,7 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si | ||
650 | 651 | }; |
651 | 652 | |
652 | 653 | unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid); |
653 | - if (!unwinder.Init()) { | |
654 | + if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { | |
654 | 655 | LOG(FATAL) << "Failed to init unwinder object."; |
655 | 656 | } |
656 | 657 |
@@ -32,6 +32,9 @@ | ||
32 | 32 | #include <unwindstack/Regs.h> |
33 | 33 | #include <unwindstack/RegsGetLocal.h> |
34 | 34 | |
35 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
36 | +#include <unwindstack/DexFiles.h> | |
37 | +#endif | |
35 | 38 | #include <unwindstack/Unwinder.h> |
36 | 39 | |
37 | 40 | #include "BacktraceLog.h" |
@@ -47,6 +50,14 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, | ||
47 | 50 | regs, stack_map->process_memory()); |
48 | 51 | unwinder.SetResolveNames(stack_map->ResolveNames()); |
49 | 52 | stack_map->SetArch(regs->Arch()); |
53 | + if (stack_map->GetJitDebug() != nullptr) { | |
54 | + unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch()); | |
55 | + } | |
56 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
57 | + if (stack_map->GetDexFiles() != nullptr) { | |
58 | + unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch()); | |
59 | + } | |
60 | +#endif | |
50 | 61 | unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore()); |
51 | 62 | if (error != nullptr) { |
52 | 63 | switch (unwinder.LastErrorCode()) { |
@@ -43,6 +43,13 @@ bool UnwindStackMap::Build() { | ||
43 | 43 | // Create the process memory object. |
44 | 44 | process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_); |
45 | 45 | |
46 | + // Create a JitDebug object for getting jit unwind information. | |
47 | + std::vector<std::string> search_libs_{"libart.so", "libartd.so"}; | |
48 | + jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_)); | |
49 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
50 | + dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_)); | |
51 | +#endif | |
52 | + | |
46 | 53 | if (!stack_maps_->Parse()) { |
47 | 54 | return false; |
48 | 55 | } |
@@ -27,6 +27,9 @@ | ||
27 | 27 | |
28 | 28 | #include <backtrace/Backtrace.h> |
29 | 29 | #include <backtrace/BacktraceMap.h> |
30 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
31 | +#include <unwindstack/DexFiles.h> | |
32 | +#endif | |
30 | 33 | #include <unwindstack/Elf.h> |
31 | 34 | #include <unwindstack/JitDebug.h> |
32 | 35 | #include <unwindstack/Maps.h> |
@@ -50,6 +53,12 @@ class UnwindStackMap : public BacktraceMap { | ||
50 | 53 | |
51 | 54 | const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; } |
52 | 55 | |
56 | + unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); } | |
57 | + | |
58 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
59 | + unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); } | |
60 | +#endif | |
61 | + | |
53 | 62 | void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; } |
54 | 63 | |
55 | 64 | protected: |
@@ -57,6 +66,11 @@ class UnwindStackMap : public BacktraceMap { | ||
57 | 66 | |
58 | 67 | std::unique_ptr<unwindstack::Maps> stack_maps_; |
59 | 68 | std::shared_ptr<unwindstack::Memory> process_memory_; |
69 | + std::unique_ptr<unwindstack::JitDebug> jit_debug_; | |
70 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
71 | + std::unique_ptr<unwindstack::DexFiles> dex_files_; | |
72 | +#endif | |
73 | + | |
60 | 74 | unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN; |
61 | 75 | }; |
62 | 76 |
@@ -49,6 +49,7 @@ cc_library { | ||
49 | 49 | srcs: [ |
50 | 50 | "ArmExidx.cpp", |
51 | 51 | "DexFile.cpp", |
52 | + "DexFiles.cpp", | |
52 | 53 | "DwarfCfa.cpp", |
53 | 54 | "DwarfEhFrameWithHdr.cpp", |
54 | 55 | "DwarfMemory.cpp", |
@@ -91,6 +92,7 @@ cc_library { | ||
91 | 92 | cflags: ["-DNO_LIBDEXFILE_SUPPORT"], |
92 | 93 | exclude_srcs: [ |
93 | 94 | "DexFile.cpp", |
95 | + "DexFiles.cpp", | |
94 | 96 | ], |
95 | 97 | exclude_shared_libs: [ |
96 | 98 | "libdexfile_support", |
@@ -100,6 +102,7 @@ cc_library { | ||
100 | 102 | cflags: ["-DNO_LIBDEXFILE_SUPPORT"], |
101 | 103 | exclude_srcs: [ |
102 | 104 | "DexFile.cpp", |
105 | + "DexFiles.cpp", | |
103 | 106 | ], |
104 | 107 | exclude_shared_libs: [ |
105 | 108 | "libdexfile_support", |
@@ -35,31 +35,22 @@ namespace unwindstack { | ||
35 | 35 | std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, |
36 | 36 | MapInfo* info) { |
37 | 37 | if (!info->name.empty()) { |
38 | - std::unique_ptr<DexFile> dex_file_from_file = | |
38 | + std::unique_ptr<DexFile> dex_file = | |
39 | 39 | DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name); |
40 | - if (dex_file_from_file) { | |
41 | - dex_file_from_file->addr_ = dex_file_offset_in_memory; | |
42 | - return dex_file_from_file; | |
40 | + if (dex_file) { | |
41 | + return dex_file; | |
43 | 42 | } |
44 | 43 | } |
45 | - std::unique_ptr<DexFile> dex_file_from_memory = | |
46 | - DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); | |
47 | - if (dex_file_from_memory) { | |
48 | - dex_file_from_memory->addr_ = dex_file_offset_in_memory; | |
49 | - return dex_file_from_memory; | |
50 | - } | |
51 | - return nullptr; | |
44 | + return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); | |
52 | 45 | } |
53 | 46 | |
54 | -bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) { | |
55 | - uint64_t dex_offset = dex_pc - addr_; | |
47 | +bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, | |
48 | + uint64_t* method_offset) { | |
56 | 49 | art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false); |
57 | 50 | if (method_info.offset == 0) { |
58 | 51 | return false; |
59 | 52 | } |
60 | - if (method_name != nullptr) { | |
61 | - *method_name = method_info.name; | |
62 | - } | |
53 | + *method_name = method_info.name; | |
63 | 54 | *method_offset = dex_offset - method_info.offset; |
64 | 55 | return true; |
65 | 56 | } |
@@ -29,22 +29,17 @@ | ||
29 | 29 | |
30 | 30 | namespace unwindstack { |
31 | 31 | |
32 | -class Memory; | |
33 | -struct MapInfo; | |
34 | - | |
35 | 32 | class DexFile : protected art_api::dex::DexFile { |
36 | 33 | public: |
37 | 34 | virtual ~DexFile() = default; |
38 | 35 | |
39 | - bool GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset); | |
36 | + bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); | |
40 | 37 | |
41 | 38 | static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory, |
42 | 39 | MapInfo* info); |
43 | 40 | |
44 | 41 | protected: |
45 | 42 | DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {} |
46 | - | |
47 | - uint64_t addr_ = 0; | |
48 | 43 | }; |
49 | 44 | |
50 | 45 | class DexFileFromFile : public DexFile { |
@@ -0,0 +1,179 @@ | ||
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 <unwindstack/DexFiles.h> | |
26 | +#include <unwindstack/MapInfo.h> | |
27 | +#include <unwindstack/Maps.h> | |
28 | +#include <unwindstack/Memory.h> | |
29 | + | |
30 | +#include "DexFile.h" | |
31 | + | |
32 | +namespace unwindstack { | |
33 | + | |
34 | +struct DEXFileEntry32 { | |
35 | + uint32_t next; | |
36 | + uint32_t prev; | |
37 | + uint32_t dex_file; | |
38 | +}; | |
39 | + | |
40 | +struct DEXFileEntry64 { | |
41 | + uint64_t next; | |
42 | + uint64_t prev; | |
43 | + uint64_t dex_file; | |
44 | +}; | |
45 | + | |
46 | +DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {} | |
47 | + | |
48 | +DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) | |
49 | + : Global(memory, search_libs) {} | |
50 | + | |
51 | +DexFiles::~DexFiles() {} | |
52 | + | |
53 | +void DexFiles::ProcessArch() { | |
54 | + switch (arch()) { | |
55 | + case ARCH_ARM: | |
56 | + case ARCH_MIPS: | |
57 | + case ARCH_X86: | |
58 | + read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32; | |
59 | + read_entry_func_ = &DexFiles::ReadEntry32; | |
60 | + break; | |
61 | + | |
62 | + case ARCH_ARM64: | |
63 | + case ARCH_MIPS64: | |
64 | + case ARCH_X86_64: | |
65 | + read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64; | |
66 | + read_entry_func_ = &DexFiles::ReadEntry64; | |
67 | + break; | |
68 | + | |
69 | + case ARCH_UNKNOWN: | |
70 | + abort(); | |
71 | + } | |
72 | +} | |
73 | + | |
74 | +uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) { | |
75 | + uint32_t entry; | |
76 | + const uint32_t field_offset = 12; // offset of first_entry_ in the descriptor struct. | |
77 | + if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) { | |
78 | + return 0; | |
79 | + } | |
80 | + return entry; | |
81 | +} | |
82 | + | |
83 | +uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) { | |
84 | + uint64_t entry; | |
85 | + const uint32_t field_offset = 16; // offset of first_entry_ in the descriptor struct. | |
86 | + if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) { | |
87 | + return 0; | |
88 | + } | |
89 | + return entry; | |
90 | +} | |
91 | + | |
92 | +bool DexFiles::ReadEntry32() { | |
93 | + DEXFileEntry32 entry; | |
94 | + if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { | |
95 | + entry_addr_ = 0; | |
96 | + return false; | |
97 | + } | |
98 | + | |
99 | + addrs_.push_back(entry.dex_file); | |
100 | + entry_addr_ = entry.next; | |
101 | + return true; | |
102 | +} | |
103 | + | |
104 | +bool DexFiles::ReadEntry64() { | |
105 | + DEXFileEntry64 entry; | |
106 | + if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { | |
107 | + entry_addr_ = 0; | |
108 | + return false; | |
109 | + } | |
110 | + | |
111 | + addrs_.push_back(entry.dex_file); | |
112 | + entry_addr_ = entry.next; | |
113 | + return true; | |
114 | +} | |
115 | + | |
116 | +bool DexFiles::ReadVariableData(uint64_t ptr_offset) { | |
117 | + entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset); | |
118 | + return entry_addr_ != 0; | |
119 | +} | |
120 | + | |
121 | +void DexFiles::Init(Maps* maps) { | |
122 | + if (initialized_) { | |
123 | + return; | |
124 | + } | |
125 | + initialized_ = true; | |
126 | + entry_addr_ = 0; | |
127 | + | |
128 | + FindAndReadVariable(maps, "__dex_debug_descriptor"); | |
129 | +} | |
130 | + | |
131 | +DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { | |
132 | + // Lock while processing the data. | |
133 | + DexFile* dex_file; | |
134 | + auto entry = files_.find(dex_file_offset); | |
135 | + if (entry == files_.end()) { | |
136 | + std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); | |
137 | + dex_file = new_dex_file.get(); | |
138 | + files_[dex_file_offset] = std::move(new_dex_file); | |
139 | + } else { | |
140 | + dex_file = entry->second.get(); | |
141 | + } | |
142 | + return dex_file; | |
143 | +} | |
144 | + | |
145 | +bool DexFiles::GetAddr(size_t index, uint64_t* addr) { | |
146 | + if (index < addrs_.size()) { | |
147 | + *addr = addrs_[index]; | |
148 | + return true; | |
149 | + } | |
150 | + if (entry_addr_ != 0 && (this->*read_entry_func_)()) { | |
151 | + *addr = addrs_.back(); | |
152 | + return true; | |
153 | + } | |
154 | + return false; | |
155 | +} | |
156 | + | |
157 | +void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, | |
158 | + std::string* method_name, uint64_t* method_offset) { | |
159 | + std::lock_guard<std::mutex> guard(lock_); | |
160 | + if (!initialized_) { | |
161 | + Init(maps); | |
162 | + } | |
163 | + | |
164 | + size_t index = 0; | |
165 | + uint64_t addr; | |
166 | + while (GetAddr(index++, &addr)) { | |
167 | + if (addr < info->start || addr >= info->end) { | |
168 | + continue; | |
169 | + } | |
170 | + | |
171 | + DexFile* dex_file = GetDexFile(addr, info); | |
172 | + if (dex_file != nullptr && | |
173 | + dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) { | |
174 | + break; | |
175 | + } | |
176 | + } | |
177 | +} | |
178 | + | |
179 | +} // namespace unwindstack |
@@ -243,24 +243,6 @@ bool Elf::IsValidPc(uint64_t pc) { | ||
243 | 243 | return false; |
244 | 244 | } |
245 | 245 | |
246 | -bool Elf::GetTextRange(uint64_t* addr, uint64_t* size) { | |
247 | - if (!valid_) { | |
248 | - return false; | |
249 | - } | |
250 | - | |
251 | - if (interface_->GetTextRange(addr, size)) { | |
252 | - *addr += load_bias_; | |
253 | - return true; | |
254 | - } | |
255 | - | |
256 | - if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->GetTextRange(addr, size)) { | |
257 | - *addr += load_bias_; | |
258 | - return true; | |
259 | - } | |
260 | - | |
261 | - return false; | |
262 | -} | |
263 | - | |
264 | 246 | ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { |
265 | 247 | if (!IsValidElf(memory)) { |
266 | 248 | return nullptr; |
@@ -69,15 +69,6 @@ bool ElfInterface::IsValidPc(uint64_t pc) { | ||
69 | 69 | return false; |
70 | 70 | } |
71 | 71 | |
72 | -bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) { | |
73 | - if (text_size_ != 0) { | |
74 | - *addr = text_addr_; | |
75 | - *size = text_size_; | |
76 | - return true; | |
77 | - } | |
78 | - return false; | |
79 | -} | |
80 | - | |
81 | 72 | Memory* ElfInterface::CreateGnuDebugdataMemory() { |
82 | 73 | if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) { |
83 | 74 | return nullptr; |
@@ -339,26 +330,29 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { | ||
339 | 330 | } |
340 | 331 | symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, |
341 | 332 | str_shdr.sh_offset, str_shdr.sh_size)); |
342 | - } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) { | |
333 | + } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) { | |
343 | 334 | // Look for the .debug_frame and .gnu_debugdata. |
344 | 335 | if (shdr.sh_name < sec_size) { |
345 | 336 | std::string name; |
346 | 337 | if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { |
338 | + uint64_t* offset_ptr = nullptr; | |
339 | + uint64_t* size_ptr = nullptr; | |
347 | 340 | if (name == ".debug_frame") { |
348 | - debug_frame_offset_ = shdr.sh_offset; | |
349 | - debug_frame_size_ = shdr.sh_size; | |
341 | + offset_ptr = &debug_frame_offset_; | |
342 | + size_ptr = &debug_frame_size_; | |
350 | 343 | } else if (name == ".gnu_debugdata") { |
351 | - gnu_debugdata_offset_ = shdr.sh_offset; | |
352 | - gnu_debugdata_size_ = shdr.sh_size; | |
344 | + offset_ptr = &gnu_debugdata_offset_; | |
345 | + size_ptr = &gnu_debugdata_size_; | |
353 | 346 | } else if (name == ".eh_frame") { |
354 | - eh_frame_offset_ = shdr.sh_offset; | |
355 | - eh_frame_size_ = shdr.sh_size; | |
347 | + offset_ptr = &eh_frame_offset_; | |
348 | + size_ptr = &eh_frame_size_; | |
356 | 349 | } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") { |
357 | - eh_frame_hdr_offset_ = shdr.sh_offset; | |
358 | - eh_frame_hdr_size_ = shdr.sh_size; | |
359 | - } else if (name == ".text") { | |
360 | - text_addr_ = shdr.sh_addr; | |
361 | - text_size_ = shdr.sh_size; | |
350 | + offset_ptr = &eh_frame_hdr_offset_; | |
351 | + size_ptr = &eh_frame_hdr_size_; | |
352 | + } | |
353 | + if (offset_ptr != nullptr) { | |
354 | + *offset_ptr = shdr.sh_offset; | |
355 | + *size_ptr = shdr.sh_size; | |
362 | 356 | } |
363 | 357 | } |
364 | 358 | } |
@@ -16,13 +16,8 @@ | ||
16 | 16 | |
17 | 17 | #include <stdint.h> |
18 | 18 | #include <sys/mman.h> |
19 | -#include <cstddef> | |
20 | 19 | |
21 | -#include <atomic> | |
22 | -#include <deque> | |
23 | -#include <map> | |
24 | 20 | #include <memory> |
25 | -#include <unordered_set> | |
26 | 21 | #include <vector> |
27 | 22 | |
28 | 23 | #include <unwindstack/Elf.h> |
@@ -30,334 +25,197 @@ | ||
30 | 25 | #include <unwindstack/Maps.h> |
31 | 26 | #include <unwindstack/Memory.h> |
32 | 27 | |
33 | -#if !defined(NO_LIBDEXFILE_SUPPORT) | |
34 | -#include <DexFile.h> | |
35 | -#endif | |
36 | - | |
37 | 28 | // This implements the JIT Compilation Interface. |
38 | 29 | // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html |
39 | 30 | |
40 | 31 | namespace unwindstack { |
41 | 32 | |
42 | -// 32-bit platforms may differ in alignment of uint64_t. | |
43 | -struct Uint64_P { | |
44 | - uint64_t value; | |
33 | +struct JITCodeEntry32Pack { | |
34 | + uint32_t next; | |
35 | + uint32_t prev; | |
36 | + uint32_t symfile_addr; | |
37 | + uint64_t symfile_size; | |
45 | 38 | } __attribute__((packed)); |
46 | -struct Uint64_A { | |
47 | - uint64_t value; | |
48 | -} __attribute__((aligned(8))); | |
49 | - | |
50 | -// Wrapper around other memory object which protects us against data races. | |
51 | -// It will check seqlock after every read, and fail if the seqlock changed. | |
52 | -// This ensues that the read memory has not been partially modified. | |
53 | -struct JitMemory : public Memory { | |
54 | - size_t Read(uint64_t addr, void* dst, size_t size) override; | |
55 | - | |
56 | - Memory* parent_ = nullptr; | |
57 | - uint64_t seqlock_addr_ = 0; | |
58 | - uint32_t expected_seqlock_ = 0; | |
59 | - bool failed_due_to_race_ = false; | |
60 | -}; | |
61 | 39 | |
62 | -template <typename Symfile> | |
63 | -struct JitCacheEntry { | |
64 | - // PC memory range described by this entry. | |
65 | - uint64_t addr_ = 0; | |
66 | - uint64_t size_ = 0; | |
67 | - std::unique_ptr<Symfile> symfile_; | |
40 | +struct JITCodeEntry32Pad { | |
41 | + uint32_t next; | |
42 | + uint32_t prev; | |
43 | + uint32_t symfile_addr; | |
44 | + uint32_t pad; | |
45 | + uint64_t symfile_size; | |
46 | +}; | |
68 | 47 | |
69 | - bool Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t size); | |
48 | +struct JITCodeEntry64 { | |
49 | + uint64_t next; | |
50 | + uint64_t prev; | |
51 | + uint64_t symfile_addr; | |
52 | + uint64_t symfile_size; | |
70 | 53 | }; |
71 | 54 | |
72 | -template <typename Symfile, typename PointerT, typename Uint64_T> | |
73 | -class JitDebugImpl : public JitDebug<Symfile>, public Global { | |
74 | - public: | |
75 | - static constexpr const char* kDescriptorExtMagic = "Android1"; | |
76 | - static constexpr int kMaxRaceRetries = 16; | |
77 | - | |
78 | - struct JITCodeEntry { | |
79 | - PointerT next; | |
80 | - PointerT prev; | |
81 | - PointerT symfile_addr; | |
82 | - Uint64_T symfile_size; | |
83 | - }; | |
84 | - | |
85 | - struct JITDescriptor { | |
86 | - uint32_t version; | |
87 | - uint32_t action_flag; | |
88 | - PointerT relevant_entry; | |
89 | - PointerT first_entry; | |
90 | - }; | |
91 | - | |
92 | - // Android-specific extensions. | |
93 | - struct JITDescriptorExt { | |
94 | - JITDescriptor desc; | |
95 | - uint8_t magic[8]; | |
96 | - uint32_t flags; | |
97 | - uint32_t sizeof_descriptor; | |
98 | - uint32_t sizeof_entry; | |
99 | - uint32_t action_seqlock; | |
100 | - uint64_t action_timestamp; | |
101 | - }; | |
102 | - | |
103 | - JitDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory, | |
104 | - std::vector<std::string>& search_libs) | |
105 | - : Global(memory, search_libs) { | |
106 | - SetArch(arch); | |
107 | - } | |
55 | +struct JITDescriptorHeader { | |
56 | + uint32_t version; | |
57 | + uint32_t action_flag; | |
58 | +}; | |
108 | 59 | |
109 | - Symfile* Get(Maps* maps, uint64_t pc) override; | |
110 | - virtual bool ReadVariableData(uint64_t offset); | |
111 | - virtual void ProcessArch() {} | |
112 | - bool Update(Maps* maps); | |
113 | - bool Read(Maps* maps, JitMemory* memory); | |
60 | +struct JITDescriptor32 { | |
61 | + JITDescriptorHeader header; | |
62 | + uint32_t relevant_entry; | |
63 | + uint32_t first_entry; | |
64 | +}; | |
114 | 65 | |
115 | - bool initialized_ = false; | |
116 | - uint64_t descriptor_addr_ = 0; // Non-zero if we have found (non-empty) descriptor. | |
117 | - uint64_t seqlock_addr_ = 0; // Re-read entries if the value at this address changes. | |
118 | - uint32_t last_seqlock_ = ~0u; // The value of seqlock when we last read the entries. | |
66 | +struct JITDescriptor64 { | |
67 | + JITDescriptorHeader header; | |
68 | + uint64_t relevant_entry; | |
69 | + uint64_t first_entry; | |
70 | +}; | |
119 | 71 | |
120 | - std::deque<JitCacheEntry<Symfile>> entries_; | |
72 | +JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {} | |
121 | 73 | |
122 | - std::mutex lock_; | |
123 | -}; | |
74 | +JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) | |
75 | + : Global(memory, search_libs) {} | |
124 | 76 | |
125 | -template <typename Symfile> | |
126 | -std::unique_ptr<JitDebug<Symfile>> JitDebug<Symfile>::Create(ArchEnum arch, | |
127 | - std::shared_ptr<Memory>& memory, | |
128 | - std::vector<std::string> search_libs) { | |
129 | - typedef JitDebugImpl<Symfile, uint32_t, Uint64_P> JitDebugImpl32P; | |
130 | - typedef JitDebugImpl<Symfile, uint32_t, Uint64_A> JitDebugImpl32A; | |
131 | - typedef JitDebugImpl<Symfile, uint64_t, Uint64_A> JitDebugImpl64A; | |
132 | - switch (arch) { | |
133 | - case ARCH_X86: | |
134 | - static_assert(sizeof(typename JitDebugImpl32P::JITCodeEntry) == 20, "layout"); | |
135 | - static_assert(sizeof(typename JitDebugImpl32P::JITDescriptor) == 16, "layout"); | |
136 | - static_assert(sizeof(typename JitDebugImpl32P::JITDescriptorExt) == 48, "layout"); | |
137 | - return std::unique_ptr<JitDebug>(new JitDebugImpl32P(arch, memory, search_libs)); | |
138 | - break; | |
139 | - case ARCH_ARM: | |
140 | - case ARCH_MIPS: | |
141 | - static_assert(sizeof(typename JitDebugImpl32A::JITCodeEntry) == 24, "layout"); | |
142 | - static_assert(sizeof(typename JitDebugImpl32A::JITDescriptor) == 16, "layout"); | |
143 | - static_assert(sizeof(typename JitDebugImpl32A::JITDescriptorExt) == 48, "layout"); | |
144 | - return std::unique_ptr<JitDebug>(new JitDebugImpl32A(arch, memory, search_libs)); | |
145 | - break; | |
146 | - case ARCH_ARM64: | |
147 | - case ARCH_X86_64: | |
148 | - case ARCH_MIPS64: | |
149 | - static_assert(sizeof(typename JitDebugImpl64A::JITCodeEntry) == 32, "layout"); | |
150 | - static_assert(sizeof(typename JitDebugImpl64A::JITDescriptor) == 24, "layout"); | |
151 | - static_assert(sizeof(typename JitDebugImpl64A::JITDescriptorExt) == 56, "layout"); | |
152 | - return std::unique_ptr<JitDebug>(new JitDebugImpl64A(arch, memory, search_libs)); | |
153 | - break; | |
154 | - default: | |
155 | - abort(); | |
77 | +JitDebug::~JitDebug() { | |
78 | + for (auto* elf : elf_list_) { | |
79 | + delete elf; | |
156 | 80 | } |
157 | 81 | } |
158 | 82 | |
159 | -size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) { | |
160 | - if (!parent_->ReadFully(addr, dst, size)) { | |
83 | +uint64_t JitDebug::ReadDescriptor32(uint64_t addr) { | |
84 | + JITDescriptor32 desc; | |
85 | + if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { | |
161 | 86 | return 0; |
162 | 87 | } |
163 | - // This is required for memory synchronization if the we are working with local memory. | |
164 | - // For other types of memory (e.g. remote) this is no-op and has no significant effect. | |
165 | - std::atomic_thread_fence(std::memory_order_acquire); | |
166 | - uint32_t seen_seqlock; | |
167 | - if (!parent_->Read32(seqlock_addr_, &seen_seqlock)) { | |
168 | - return 0; | |
169 | - } | |
170 | - if (seen_seqlock != expected_seqlock_) { | |
171 | - failed_due_to_race_ = true; | |
88 | + | |
89 | + if (desc.header.version != 1 || desc.first_entry == 0) { | |
90 | + // Either unknown version, or no jit entries. | |
172 | 91 | return 0; |
173 | 92 | } |
174 | - return size; | |
93 | + | |
94 | + return desc.first_entry; | |
175 | 95 | } |
176 | 96 | |
177 | -template <typename Symfile, typename PointerT, typename Uint64_T> | |
178 | -bool JitDebugImpl<Symfile, PointerT, Uint64_T>::ReadVariableData(uint64_t addr) { | |
179 | - JITDescriptor desc; | |
180 | - if (!this->memory_->ReadFully(addr, &desc, sizeof(desc))) { | |
181 | - return false; | |
182 | - } | |
183 | - if (desc.version != 1) { | |
184 | - return false; | |
185 | - } | |
186 | - if (desc.first_entry == 0) { | |
187 | - return false; // There could be multiple descriptors. Ignore empty ones. | |
188 | - } | |
189 | - descriptor_addr_ = addr; | |
190 | - JITDescriptorExt desc_ext; | |
191 | - if (this->memory_->ReadFully(addr, &desc_ext, sizeof(desc_ext)) && | |
192 | - memcmp(desc_ext.magic, kDescriptorExtMagic, 8) == 0) { | |
193 | - seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptorExt, action_seqlock); | |
194 | - } else { | |
195 | - // In the absence of Android-specific fields, use the head pointer instead. | |
196 | - seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptor, first_entry); | |
97 | +uint64_t JitDebug::ReadDescriptor64(uint64_t addr) { | |
98 | + JITDescriptor64 desc; | |
99 | + if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { | |
100 | + return 0; | |
197 | 101 | } |
198 | - return true; | |
199 | -} | |
200 | 102 | |
201 | -template <typename Symfile> | |
202 | -static const char* GetDescriptorName(); | |
103 | + if (desc.header.version != 1 || desc.first_entry == 0) { | |
104 | + // Either unknown version, or no jit entries. | |
105 | + return 0; | |
106 | + } | |
203 | 107 | |
204 | -template <> | |
205 | -const char* GetDescriptorName<Elf>() { | |
206 | - return "__jit_debug_descriptor"; | |
108 | + return desc.first_entry; | |
207 | 109 | } |
208 | 110 | |
209 | -template <typename Symfile, typename PointerT, typename Uint64_T> | |
210 | -Symfile* JitDebugImpl<Symfile, PointerT, Uint64_T>::Get(Maps* maps, uint64_t pc) { | |
211 | - std::lock_guard<std::mutex> guard(lock_); | |
212 | - if (!initialized_) { | |
213 | - FindAndReadVariable(maps, GetDescriptorName<Symfile>()); | |
214 | - initialized_ = true; | |
111 | +uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) { | |
112 | + JITCodeEntry32Pack code; | |
113 | + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { | |
114 | + return 0; | |
215 | 115 | } |
216 | 116 | |
217 | - if (descriptor_addr_ == 0) { | |
218 | - return nullptr; | |
219 | - } | |
117 | + *start = code.symfile_addr; | |
118 | + *size = code.symfile_size; | |
119 | + return code.next; | |
120 | +} | |
220 | 121 | |
221 | - if (!Update(maps)) { | |
222 | - return nullptr; | |
122 | +uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) { | |
123 | + JITCodeEntry32Pad code; | |
124 | + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { | |
125 | + return 0; | |
223 | 126 | } |
224 | 127 | |
225 | - Symfile* fallback = nullptr; | |
226 | - for (auto& entry : entries_) { | |
227 | - // Skip entries which are obviously not relevant (if we know the PC range). | |
228 | - if (entry.size_ == 0 || (entry.addr_ <= pc && (pc - entry.addr_) < entry.size_)) { | |
229 | - // Double check the entry contains the PC in case there are overlapping entries. | |
230 | - // This is might happen for native-code due to GC and for DEX due to data sharing. | |
231 | - std::string method_name; | |
232 | - uint64_t method_offset; | |
233 | - if (entry.symfile_->GetFunctionName(pc, &method_name, &method_offset)) { | |
234 | - return entry.symfile_.get(); | |
235 | - } | |
236 | - fallback = entry.symfile_.get(); // Tests don't have any symbols. | |
237 | - } | |
238 | - } | |
239 | - return fallback; // Not found. | |
128 | + *start = code.symfile_addr; | |
129 | + *size = code.symfile_size; | |
130 | + return code.next; | |
240 | 131 | } |
241 | 132 | |
242 | -// Update JIT entries if needed. It will retry if there are data races. | |
243 | -template <typename Symfile, typename PointerT, typename Uint64_T> | |
244 | -bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Update(Maps* maps) { | |
245 | - // We might need to retry the whole read in the presence of data races. | |
246 | - for (int i = 0; i < kMaxRaceRetries; i++) { | |
247 | - // Read the seqlock (counter which is incremented before and after any modification). | |
248 | - uint32_t seqlock = 0; | |
249 | - if (!this->memory_->Read32(seqlock_addr_, &seqlock)) { | |
250 | - return false; // Failed to read seqlock. | |
251 | - } | |
252 | - | |
253 | - // Check if anything changed since the last time we checked. | |
254 | - if (last_seqlock_ != seqlock) { | |
255 | - // Create memory wrapper to allow us to read the entries safely even in a live process. | |
256 | - JitMemory safe_memory; | |
257 | - safe_memory.parent_ = this->memory_.get(); | |
258 | - safe_memory.seqlock_addr_ = seqlock_addr_; | |
259 | - safe_memory.expected_seqlock_ = seqlock; | |
260 | - std::atomic_thread_fence(std::memory_order_acquire); | |
261 | - | |
262 | - // Add all entries to our cache. | |
263 | - if (!Read(maps, &safe_memory)) { | |
264 | - if (safe_memory.failed_due_to_race_) { | |
265 | - sleep(0); | |
266 | - continue; // Try again (there was a data race). | |
267 | - } else { | |
268 | - return false; // Proper failure (we could not read the data). | |
269 | - } | |
270 | - } | |
271 | - last_seqlock_ = seqlock; | |
272 | - } | |
273 | - return true; | |
133 | +uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) { | |
134 | + JITCodeEntry64 code; | |
135 | + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { | |
136 | + return 0; | |
274 | 137 | } |
275 | - return false; // Too many retries. | |
138 | + | |
139 | + *start = code.symfile_addr; | |
140 | + *size = code.symfile_size; | |
141 | + return code.next; | |
276 | 142 | } |
277 | 143 | |
278 | -// Read all JIT entries. It might randomly fail due to data races. | |
279 | -template <typename Symfile, typename PointerT, typename Uint64_T> | |
280 | -bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Read(Maps* maps, JitMemory* memory) { | |
281 | - std::unordered_set<uint64_t> seen_entry_addr; | |
144 | +void JitDebug::ProcessArch() { | |
145 | + switch (arch()) { | |
146 | + case ARCH_X86: | |
147 | + read_descriptor_func_ = &JitDebug::ReadDescriptor32; | |
148 | + read_entry_func_ = &JitDebug::ReadEntry32Pack; | |
149 | + break; | |
282 | 150 | |
283 | - // Read and verify the descriptor (must be after we have read the initial seqlock). | |
284 | - JITDescriptor desc; | |
285 | - if (!(memory->ReadFully(descriptor_addr_, &desc, sizeof(desc)))) { | |
286 | - return false; | |
287 | - } | |
151 | + case ARCH_ARM: | |
152 | + case ARCH_MIPS: | |
153 | + read_descriptor_func_ = &JitDebug::ReadDescriptor32; | |
154 | + read_entry_func_ = &JitDebug::ReadEntry32Pad; | |
155 | + break; | |
288 | 156 | |
289 | - entries_.clear(); | |
290 | - JITCodeEntry entry; | |
291 | - for (uint64_t entry_addr = desc.first_entry; entry_addr != 0; entry_addr = entry.next) { | |
292 | - // Check for infinite loops in the lined list. | |
293 | - if (!seen_entry_addr.emplace(entry_addr).second) { | |
294 | - return true; // TODO: Fail when seening infinite loop. | |
295 | - } | |
157 | + case ARCH_ARM64: | |
158 | + case ARCH_X86_64: | |
159 | + case ARCH_MIPS64: | |
160 | + read_descriptor_func_ = &JitDebug::ReadDescriptor64; | |
161 | + read_entry_func_ = &JitDebug::ReadEntry64; | |
162 | + break; | |
163 | + case ARCH_UNKNOWN: | |
164 | + abort(); | |
165 | + } | |
166 | +} | |
296 | 167 | |
297 | - // Read the entry (while checking for data races). | |
298 | - if (!memory->ReadFully(entry_addr, &entry, sizeof(entry))) { | |
299 | - return false; | |
300 | - } | |
168 | +bool JitDebug::ReadVariableData(uint64_t ptr) { | |
169 | + entry_addr_ = (this->*read_descriptor_func_)(ptr); | |
170 | + return entry_addr_ != 0; | |
171 | +} | |
301 | 172 | |
302 | - // Copy and load the symfile. | |
303 | - entries_.emplace_back(JitCacheEntry<Symfile>()); | |
304 | - if (!entries_.back().Init(maps, memory, entry.symfile_addr, entry.symfile_size.value)) { | |
305 | - return false; | |
306 | - } | |
173 | +void JitDebug::Init(Maps* maps) { | |
174 | + if (initialized_) { | |
175 | + return; | |
307 | 176 | } |
177 | + // Regardless of what happens below, consider the init finished. | |
178 | + initialized_ = true; | |
308 | 179 | |
309 | - return true; | |
180 | + FindAndReadVariable(maps, "__jit_debug_descriptor"); | |
310 | 181 | } |
311 | 182 | |
312 | -// Copy and load ELF file. | |
313 | -template <> | |
314 | -bool JitCacheEntry<Elf>::Init(Maps*, JitMemory* memory, uint64_t addr, uint64_t size) { | |
315 | - // Make a copy of the in-memory symbol file (while checking for data races). | |
316 | - std::unique_ptr<MemoryBuffer> buffer(new MemoryBuffer()); | |
317 | - buffer->Resize(size); | |
318 | - if (!memory->ReadFully(addr, buffer->GetPtr(0), buffer->Size())) { | |
319 | - return false; | |
183 | +Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) { | |
184 | + // Use a single lock, this object should be used so infrequently that | |
185 | + // a fine grain lock is unnecessary. | |
186 | + std::lock_guard<std::mutex> guard(lock_); | |
187 | + if (!initialized_) { | |
188 | + Init(maps); | |
320 | 189 | } |
321 | 190 | |
322 | - // Load and validate the ELF file. | |
323 | - symfile_.reset(new Elf(buffer.release())); | |
324 | - symfile_->Init(); | |
325 | - if (!symfile_->valid()) { | |
326 | - return false; | |
191 | + // Search the existing elf object first. | |
192 | + for (Elf* elf : elf_list_) { | |
193 | + if (elf->IsValidPc(pc)) { | |
194 | + return elf; | |
195 | + } | |
327 | 196 | } |
328 | 197 | |
329 | - symfile_->GetTextRange(&addr_, &size_); | |
330 | - return true; | |
331 | -} | |
198 | + while (entry_addr_ != 0) { | |
199 | + uint64_t start; | |
200 | + uint64_t size; | |
201 | + entry_addr_ = (this->*read_entry_func_)(&start, &size); | |
332 | 202 | |
333 | -template std::unique_ptr<JitDebug<Elf>> JitDebug<Elf>::Create(ArchEnum, std::shared_ptr<Memory>&, | |
334 | - std::vector<std::string>); | |
335 | - | |
336 | -#if !defined(NO_LIBDEXFILE_SUPPORT) | |
337 | - | |
338 | -template <> | |
339 | -const char* GetDescriptorName<DexFile>() { | |
340 | - return "__dex_debug_descriptor"; | |
341 | -} | |
203 | + Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0)); | |
204 | + elf->Init(); | |
205 | + if (!elf->valid()) { | |
206 | + // The data is not formatted in a way we understand, do not attempt | |
207 | + // to process any other entries. | |
208 | + entry_addr_ = 0; | |
209 | + delete elf; | |
210 | + return nullptr; | |
211 | + } | |
212 | + elf_list_.push_back(elf); | |
342 | 213 | |
343 | -// Copy and load DEX file. | |
344 | -template <> | |
345 | -bool JitCacheEntry<DexFile>::Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t) { | |
346 | - MapInfo* info = maps->Find(addr); | |
347 | - if (info == nullptr) { | |
348 | - return false; | |
349 | - } | |
350 | - symfile_ = DexFile::Create(addr, memory, info); | |
351 | - if (symfile_ == nullptr) { | |
352 | - return false; | |
214 | + if (elf->IsValidPc(pc)) { | |
215 | + return elf; | |
216 | + } | |
353 | 217 | } |
354 | - return true; | |
218 | + return nullptr; | |
355 | 219 | } |
356 | 220 | |
357 | -template std::unique_ptr<JitDebug<DexFile>> JitDebug<DexFile>::Create(ArchEnum, | |
358 | - std::shared_ptr<Memory>&, | |
359 | - std::vector<std::string>); | |
360 | - | |
361 | -#endif | |
362 | - | |
363 | 221 | } // namespace unwindstack |
@@ -36,38 +36,11 @@ | ||
36 | 36 | #include <unwindstack/Unwinder.h> |
37 | 37 | |
38 | 38 | #if !defined(NO_LIBDEXFILE_SUPPORT) |
39 | -#include <DexFile.h> | |
39 | +#include <unwindstack/DexFiles.h> | |
40 | 40 | #endif |
41 | 41 | |
42 | 42 | namespace unwindstack { |
43 | 43 | |
44 | -Unwinder::Unwinder(size_t max_frames, Maps* maps, Regs* regs, | |
45 | - std::shared_ptr<Memory> process_memory) | |
46 | - : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) { | |
47 | - frames_.reserve(max_frames); | |
48 | - if (regs != nullptr) { | |
49 | - ArchEnum arch = regs_->Arch(); | |
50 | - | |
51 | - jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_); | |
52 | -#if !defined(NO_LIBDEXFILE_SUPPORT) | |
53 | - dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_); | |
54 | -#endif | |
55 | - } | |
56 | -} | |
57 | - | |
58 | -void Unwinder::SetRegs(Regs* regs) { | |
59 | - regs_ = regs; | |
60 | - | |
61 | - if (jit_debug_ == nullptr) { | |
62 | - ArchEnum arch = regs_->Arch(); | |
63 | - | |
64 | - jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_); | |
65 | -#if !defined(NO_LIBDEXFILE_SUPPORT) | |
66 | - dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_); | |
67 | -#endif | |
68 | - } | |
69 | -} | |
70 | - | |
71 | 44 | // Inject extra 'virtual' frame that represents the dex pc data. |
72 | 45 | // The dex pc is a magic register defined in the Mterp interpreter, |
73 | 46 | // and thus it will be restored/observed in the frame after it. |
@@ -111,7 +84,8 @@ void Unwinder::FillInDexFrame() { | ||
111 | 84 | return; |
112 | 85 | } |
113 | 86 | |
114 | - dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset); | |
87 | + dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name, | |
88 | + &frame->function_offset); | |
115 | 89 | #endif |
116 | 90 | } |
117 | 91 |
@@ -211,7 +185,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip, | ||
211 | 185 | // using the jit debug information. |
212 | 186 | if (!elf->valid() && jit_debug_ != nullptr) { |
213 | 187 | uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment; |
214 | - Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc); | |
188 | + Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc); | |
215 | 189 | if (jit_elf != nullptr) { |
216 | 190 | // The jit debug information requires a non relative adjusted pc. |
217 | 191 | step_pc = adjusted_jit_pc; |
@@ -356,7 +330,19 @@ std::string Unwinder::FormatFrame(size_t frame_num) { | ||
356 | 330 | return FormatFrame(frames_[frame_num]); |
357 | 331 | } |
358 | 332 | |
359 | -bool UnwinderFromPid::Init() { | |
333 | +void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) { | |
334 | + jit_debug->SetArch(arch); | |
335 | + jit_debug_ = jit_debug; | |
336 | +} | |
337 | + | |
338 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
339 | +void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) { | |
340 | + dex_files->SetArch(arch); | |
341 | + dex_files_ = dex_files; | |
342 | +} | |
343 | +#endif | |
344 | + | |
345 | +bool UnwinderFromPid::Init(ArchEnum arch) { | |
360 | 346 | if (pid_ == getpid()) { |
361 | 347 | maps_ptr_.reset(new LocalMaps()); |
362 | 348 | } else { |
@@ -369,6 +355,15 @@ bool UnwinderFromPid::Init() { | ||
369 | 355 | |
370 | 356 | process_memory_ = Memory::CreateProcessMemoryCached(pid_); |
371 | 357 | |
358 | + jit_debug_ptr_.reset(new JitDebug(process_memory_)); | |
359 | + jit_debug_ = jit_debug_ptr_.get(); | |
360 | + SetJitDebug(jit_debug_, arch); | |
361 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
362 | + dex_files_ptr_.reset(new DexFiles(process_memory_)); | |
363 | + dex_files_ = dex_files_ptr_.get(); | |
364 | + SetDexFiles(dex_files_, arch); | |
365 | +#endif | |
366 | + | |
372 | 367 | return true; |
373 | 368 | } |
374 | 369 |
@@ -0,0 +1,79 @@ | ||
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 _LIBUNWINDSTACK_DEX_FILES_H | |
18 | +#define _LIBUNWINDSTACK_DEX_FILES_H | |
19 | + | |
20 | +#include <stdint.h> | |
21 | + | |
22 | +#include <memory> | |
23 | +#include <mutex> | |
24 | +#include <string> | |
25 | +#include <unordered_map> | |
26 | +#include <vector> | |
27 | + | |
28 | +#include <unwindstack/Global.h> | |
29 | +#include <unwindstack/Memory.h> | |
30 | + | |
31 | +namespace unwindstack { | |
32 | + | |
33 | +// Forward declarations. | |
34 | +class DexFile; | |
35 | +class Maps; | |
36 | +struct MapInfo; | |
37 | +enum ArchEnum : uint8_t; | |
38 | + | |
39 | +class DexFiles : public Global { | |
40 | + public: | |
41 | + explicit DexFiles(std::shared_ptr<Memory>& memory); | |
42 | + DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs); | |
43 | + virtual ~DexFiles(); | |
44 | + | |
45 | + DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info); | |
46 | + | |
47 | + void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name, | |
48 | + uint64_t* method_offset); | |
49 | + | |
50 | + private: | |
51 | + void Init(Maps* maps); | |
52 | + | |
53 | + bool GetAddr(size_t index, uint64_t* addr); | |
54 | + | |
55 | + uint64_t ReadEntryPtr32(uint64_t addr); | |
56 | + | |
57 | + uint64_t ReadEntryPtr64(uint64_t addr); | |
58 | + | |
59 | + bool ReadEntry32(); | |
60 | + | |
61 | + bool ReadEntry64(); | |
62 | + | |
63 | + bool ReadVariableData(uint64_t ptr_offset) override; | |
64 | + | |
65 | + void ProcessArch() override; | |
66 | + | |
67 | + std::mutex lock_; | |
68 | + bool initialized_ = false; | |
69 | + std::unordered_map<uint64_t, std::unique_ptr<DexFile>> files_; | |
70 | + | |
71 | + uint64_t entry_addr_ = 0; | |
72 | + uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr; | |
73 | + bool (DexFiles::*read_entry_func_)() = nullptr; | |
74 | + std::vector<uint64_t> addrs_; | |
75 | +}; | |
76 | + | |
77 | +} // namespace unwindstack | |
78 | + | |
79 | +#endif // _LIBUNWINDSTACK_DEX_FILES_H |
@@ -78,8 +78,6 @@ class Elf { | ||
78 | 78 | |
79 | 79 | bool IsValidPc(uint64_t pc); |
80 | 80 | |
81 | - bool GetTextRange(uint64_t* addr, uint64_t* size); | |
82 | - | |
83 | 81 | void GetLastError(ErrorData* data); |
84 | 82 | ErrorCode GetLastErrorCode(); |
85 | 83 | uint64_t GetLastErrorAddress(); |
@@ -68,8 +68,6 @@ class ElfInterface { | ||
68 | 68 | |
69 | 69 | virtual bool IsValidPc(uint64_t pc); |
70 | 70 | |
71 | - bool GetTextRange(uint64_t* addr, uint64_t* size); | |
72 | - | |
73 | 71 | Memory* CreateGnuDebugdataMemory(); |
74 | 72 | |
75 | 73 | Memory* memory() { return memory_; } |
@@ -158,9 +156,6 @@ class ElfInterface { | ||
158 | 156 | uint64_t gnu_build_id_offset_ = 0; |
159 | 157 | uint64_t gnu_build_id_size_ = 0; |
160 | 158 | |
161 | - uint64_t text_addr_ = 0; | |
162 | - uint64_t text_size_ = 0; | |
163 | - | |
164 | 159 | uint8_t soname_type_ = SONAME_UNKNOWN; |
165 | 160 | std::string soname_; |
166 | 161 |
@@ -19,7 +19,6 @@ | ||
19 | 19 | |
20 | 20 | #include <stdint.h> |
21 | 21 | |
22 | -#include <map> | |
23 | 22 | #include <memory> |
24 | 23 | #include <mutex> |
25 | 24 | #include <string> |
@@ -31,24 +30,40 @@ | ||
31 | 30 | namespace unwindstack { |
32 | 31 | |
33 | 32 | // Forward declarations. |
33 | +class Elf; | |
34 | 34 | class Maps; |
35 | 35 | enum ArchEnum : uint8_t; |
36 | 36 | |
37 | -template <typename Symfile> | |
38 | -class JitDebug { | |
37 | +class JitDebug : public Global { | |
39 | 38 | public: |
40 | - static std::unique_ptr<JitDebug> Create(ArchEnum arch, std::shared_ptr<Memory>& memory, | |
41 | - std::vector<std::string> search_libs = {}); | |
42 | - virtual ~JitDebug() {} | |
43 | - | |
44 | - // Find symbol file for given pc. | |
45 | - virtual Symfile* Get(Maps* maps, uint64_t pc) = 0; | |
46 | - | |
47 | - // Find symbol for given pc. | |
48 | - bool GetFunctionName(Maps* maps, uint64_t pc, std::string* name, uint64_t* offset) { | |
49 | - Symfile* file = Get(maps, pc); | |
50 | - return file != nullptr && file->GetFunctionName(pc, name, offset); | |
51 | - } | |
39 | + explicit JitDebug(std::shared_ptr<Memory>& memory); | |
40 | + JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs); | |
41 | + virtual ~JitDebug(); | |
42 | + | |
43 | + Elf* GetElf(Maps* maps, uint64_t pc); | |
44 | + | |
45 | + private: | |
46 | + void Init(Maps* maps); | |
47 | + | |
48 | + uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr; | |
49 | + uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr; | |
50 | + | |
51 | + uint64_t ReadDescriptor32(uint64_t); | |
52 | + uint64_t ReadDescriptor64(uint64_t); | |
53 | + | |
54 | + uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size); | |
55 | + uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size); | |
56 | + uint64_t ReadEntry64(uint64_t* start, uint64_t* size); | |
57 | + | |
58 | + bool ReadVariableData(uint64_t ptr_offset) override; | |
59 | + | |
60 | + void ProcessArch() override; | |
61 | + | |
62 | + uint64_t entry_addr_ = 0; | |
63 | + bool initialized_ = false; | |
64 | + std::vector<Elf*> elf_list_; | |
65 | + | |
66 | + std::mutex lock_; | |
52 | 67 | }; |
53 | 68 | |
54 | 69 | } // namespace unwindstack |
@@ -24,6 +24,7 @@ | ||
24 | 24 | #include <string> |
25 | 25 | #include <vector> |
26 | 26 | |
27 | +#include <unwindstack/DexFiles.h> | |
27 | 28 | #include <unwindstack/Error.h> |
28 | 29 | #include <unwindstack/JitDebug.h> |
29 | 30 | #include <unwindstack/Maps.h> |
@@ -33,7 +34,6 @@ | ||
33 | 34 | namespace unwindstack { |
34 | 35 | |
35 | 36 | // Forward declarations. |
36 | -class DexFile; | |
37 | 37 | class Elf; |
38 | 38 | enum ArchEnum : uint8_t; |
39 | 39 |
@@ -63,14 +63,14 @@ struct FrameData { | ||
63 | 63 | |
64 | 64 | class Unwinder { |
65 | 65 | public: |
66 | - Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory); | |
66 | + Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory) | |
67 | + : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) { | |
68 | + frames_.reserve(max_frames); | |
69 | + } | |
67 | 70 | Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory) |
68 | - : Unwinder(max_frames, maps, nullptr, process_memory) {} | |
69 | - | |
70 | - Unwinder(const Unwinder&) = delete; | |
71 | - Unwinder& operator=(const Unwinder&) = delete; | |
72 | - Unwinder(Unwinder&&) = default; | |
73 | - Unwinder& operator=(Unwinder&&) = default; | |
71 | + : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) { | |
72 | + frames_.reserve(max_frames); | |
73 | + } | |
74 | 74 | |
75 | 75 | virtual ~Unwinder() = default; |
76 | 76 |
@@ -90,7 +90,9 @@ class Unwinder { | ||
90 | 90 | std::string FormatFrame(size_t frame_num); |
91 | 91 | std::string FormatFrame(const FrameData& frame); |
92 | 92 | |
93 | - void SetRegs(Regs* regs); | |
93 | + void SetJitDebug(JitDebug* jit_debug, ArchEnum arch); | |
94 | + | |
95 | + void SetRegs(Regs* regs) { regs_ = regs; } | |
94 | 96 | Maps* GetMaps() { return maps_; } |
95 | 97 | std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; } |
96 | 98 |
@@ -105,6 +107,10 @@ class Unwinder { | ||
105 | 107 | |
106 | 108 | void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; } |
107 | 109 | |
110 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
111 | + void SetDexFiles(DexFiles* dex_files, ArchEnum arch); | |
112 | +#endif | |
113 | + | |
108 | 114 | ErrorCode LastErrorCode() { return last_error_.code; } |
109 | 115 | uint64_t LastErrorAddress() { return last_error_.address; } |
110 | 116 |
@@ -120,9 +126,9 @@ class Unwinder { | ||
120 | 126 | Regs* regs_; |
121 | 127 | std::vector<FrameData> frames_; |
122 | 128 | std::shared_ptr<Memory> process_memory_; |
123 | - std::unique_ptr<JitDebug<Elf>> jit_debug_; | |
129 | + JitDebug* jit_debug_ = nullptr; | |
124 | 130 | #if !defined(NO_LIBDEXFILE_SUPPORT) |
125 | - std::unique_ptr<JitDebug<DexFile>> dex_files_; | |
131 | + DexFiles* dex_files_ = nullptr; | |
126 | 132 | #endif |
127 | 133 | bool resolve_names_ = true; |
128 | 134 | bool embedded_soname_ = true; |
@@ -135,11 +141,15 @@ class UnwinderFromPid : public Unwinder { | ||
135 | 141 | UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {} |
136 | 142 | virtual ~UnwinderFromPid() = default; |
137 | 143 | |
138 | - bool Init(); | |
144 | + bool Init(ArchEnum arch); | |
139 | 145 | |
140 | 146 | private: |
141 | 147 | pid_t pid_; |
142 | 148 | std::unique_ptr<Maps> maps_ptr_; |
149 | + std::unique_ptr<JitDebug> jit_debug_ptr_; | |
150 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
151 | + std::unique_ptr<DexFiles> dex_files_ptr_; | |
152 | +#endif | |
143 | 153 | }; |
144 | 154 | |
145 | 155 | } // namespace unwindstack |
@@ -177,11 +177,11 @@ TEST(DexFileTest, get_method) { | ||
177 | 177 | |
178 | 178 | std::string method; |
179 | 179 | uint64_t method_offset; |
180 | - ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset)); | |
180 | + ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset)); | |
181 | 181 | EXPECT_EQ("Main.<init>", method); |
182 | 182 | EXPECT_EQ(2U, method_offset); |
183 | 183 | |
184 | - ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset)); | |
184 | + ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset)); | |
185 | 185 | EXPECT_EQ("Main.main", method); |
186 | 186 | EXPECT_EQ(0U, method_offset); |
187 | 187 | } |
@@ -195,9 +195,9 @@ TEST(DexFileTest, get_method_empty) { | ||
195 | 195 | |
196 | 196 | std::string method; |
197 | 197 | uint64_t method_offset; |
198 | - EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset)); | |
198 | + EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset)); | |
199 | 199 | |
200 | - EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset)); | |
200 | + EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset)); | |
201 | 201 | } |
202 | 202 | |
203 | 203 | } // namespace unwindstack |
@@ -22,8 +22,8 @@ | ||
22 | 22 | |
23 | 23 | #include <gtest/gtest.h> |
24 | 24 | |
25 | +#include <unwindstack/DexFiles.h> | |
25 | 26 | #include <unwindstack/Elf.h> |
26 | -#include <unwindstack/JitDebug.h> | |
27 | 27 | #include <unwindstack/MapInfo.h> |
28 | 28 | #include <unwindstack/Maps.h> |
29 | 29 | #include <unwindstack/Memory.h> |
@@ -32,10 +32,6 @@ | ||
32 | 32 | #include "ElfFake.h" |
33 | 33 | #include "MemoryFake.h" |
34 | 34 | |
35 | -#if !defined(NO_LIBDEXFILE_SUPPORT) | |
36 | -#include <DexFile.h> | |
37 | -#endif | |
38 | - | |
39 | 35 | namespace unwindstack { |
40 | 36 | |
41 | 37 | class DexFilesTest : public ::testing::Test { |
@@ -52,7 +48,8 @@ class DexFilesTest : public ::testing::Test { | ||
52 | 48 | } |
53 | 49 | |
54 | 50 | void Init(ArchEnum arch) { |
55 | - dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_); | |
51 | + dex_files_.reset(new DexFiles(process_memory_)); | |
52 | + dex_files_->SetArch(arch); | |
56 | 53 | |
57 | 54 | maps_.reset( |
58 | 55 | new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n" |
@@ -89,11 +86,10 @@ class DexFilesTest : public ::testing::Test { | ||
89 | 86 | Init(ARCH_ARM); |
90 | 87 | } |
91 | 88 | |
92 | - void WriteDescriptor32(uint64_t addr, uint32_t entry); | |
93 | - void WriteDescriptor64(uint64_t addr, uint64_t entry); | |
94 | - void WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex); | |
95 | - void WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex); | |
96 | - void WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex); | |
89 | + void WriteDescriptor32(uint64_t addr, uint32_t head); | |
90 | + void WriteDescriptor64(uint64_t addr, uint64_t head); | |
91 | + void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file); | |
92 | + void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file); | |
97 | 93 | void WriteDex(uint64_t dex_file); |
98 | 94 | |
99 | 95 | static constexpr size_t kMapGlobalNonReadable = 2; |
@@ -105,70 +101,40 @@ class DexFilesTest : public ::testing::Test { | ||
105 | 101 | |
106 | 102 | std::shared_ptr<Memory> process_memory_; |
107 | 103 | MemoryFake* memory_; |
108 | - std::unique_ptr<JitDebug<DexFile>> dex_files_; | |
104 | + std::unique_ptr<DexFiles> dex_files_; | |
109 | 105 | std::unique_ptr<BufferMaps> maps_; |
110 | 106 | }; |
111 | 107 | |
112 | -void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) { | |
113 | - // Format of the 32 bit JITDescriptor structure: | |
114 | - // uint32_t version | |
115 | - memory_->SetData32(addr, 1); | |
116 | - // uint32_t action_flag | |
117 | - memory_->SetData32(addr + 4, 0); | |
118 | - // uint32_t relevant_entry | |
119 | - memory_->SetData32(addr + 8, 0); | |
120 | - // uint32_t first_entry | |
121 | - memory_->SetData32(addr + 12, entry); | |
122 | -} | |
123 | - | |
124 | -void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) { | |
125 | - // Format of the 64 bit JITDescriptor structure: | |
126 | - // uint32_t version | |
127 | - memory_->SetData32(addr, 1); | |
128 | - // uint32_t action_flag | |
129 | - memory_->SetData32(addr + 4, 0); | |
130 | - // uint64_t relevant_entry | |
131 | - memory_->SetData64(addr + 8, 0); | |
132 | - // uint64_t first_entry | |
133 | - memory_->SetData64(addr + 16, entry); | |
108 | +void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) { | |
109 | + // void* first_entry_ | |
110 | + memory_->SetData32(addr + 12, head); | |
134 | 111 | } |
135 | 112 | |
136 | -void DexFilesTest::WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) { | |
137 | - // Format of the 32 bit JITCodeEntry structure: | |
138 | - // uint32_t next | |
139 | - memory_->SetData32(addr, next); | |
140 | - // uint32_t prev | |
141 | - memory_->SetData32(addr + 4, prev); | |
142 | - // uint32_t dex | |
143 | - memory_->SetData32(addr + 8, dex); | |
144 | - // uint64_t symfile_size | |
145 | - memory_->SetData64(addr + 12, sizeof(kDexData) * sizeof(uint32_t)); | |
113 | +void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) { | |
114 | + // void* first_entry_ | |
115 | + memory_->SetData64(addr + 16, head); | |
146 | 116 | } |
147 | 117 | |
148 | -void DexFilesTest::WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) { | |
149 | - // Format of the 32 bit JITCodeEntry structure: | |
118 | +void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, | |
119 | + uint32_t dex_file) { | |
120 | + // Format of the 32 bit DEXFileEntry structure: | |
150 | 121 | // uint32_t next |
151 | - memory_->SetData32(addr, next); | |
122 | + memory_->SetData32(entry_addr, next); | |
152 | 123 | // uint32_t prev |
153 | - memory_->SetData32(addr + 4, prev); | |
154 | - // uint32_t dex | |
155 | - memory_->SetData32(addr + 8, dex); | |
156 | - // uint32_t pad | |
157 | - memory_->SetData32(addr + 12, 0); | |
158 | - // uint64_t symfile_size | |
159 | - memory_->SetData64(addr + 16, sizeof(kDexData) * sizeof(uint32_t)); | |
124 | + memory_->SetData32(entry_addr + 4, prev); | |
125 | + // uint32_t dex_file | |
126 | + memory_->SetData32(entry_addr + 8, dex_file); | |
160 | 127 | } |
161 | 128 | |
162 | -void DexFilesTest::WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex) { | |
163 | - // Format of the 64 bit JITCodeEntry structure: | |
129 | +void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, | |
130 | + uint64_t dex_file) { | |
131 | + // Format of the 64 bit DEXFileEntry structure: | |
164 | 132 | // uint64_t next |
165 | - memory_->SetData64(addr, next); | |
133 | + memory_->SetData64(entry_addr, next); | |
166 | 134 | // uint64_t prev |
167 | - memory_->SetData64(addr + 8, prev); | |
168 | - // uint64_t dex | |
169 | - memory_->SetData64(addr + 16, dex); | |
170 | - // uint64_t symfile_size | |
171 | - memory_->SetData64(addr + 24, sizeof(kDexData) * sizeof(uint32_t)); | |
135 | + memory_->SetData64(entry_addr + 8, prev); | |
136 | + // uint64_t dex_file | |
137 | + memory_->SetData64(entry_addr + 16, dex_file); | |
172 | 138 | } |
173 | 139 | |
174 | 140 | void DexFilesTest::WriteDex(uint64_t dex_file) { |
@@ -178,8 +144,9 @@ void DexFilesTest::WriteDex(uint64_t dex_file) { | ||
178 | 144 | TEST_F(DexFilesTest, get_method_information_invalid) { |
179 | 145 | std::string method_name = "nothing"; |
180 | 146 | uint64_t method_offset = 0x124; |
147 | + MapInfo* info = maps_->Get(kMapDexFileEntries); | |
181 | 148 | |
182 | - dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset); | |
149 | + dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset); | |
183 | 150 | EXPECT_EQ("nothing", method_name); |
184 | 151 | EXPECT_EQ(0x124U, method_offset); |
185 | 152 | } |
@@ -187,12 +154,13 @@ TEST_F(DexFilesTest, get_method_information_invalid) { | ||
187 | 154 | TEST_F(DexFilesTest, get_method_information_32) { |
188 | 155 | std::string method_name = "nothing"; |
189 | 156 | uint64_t method_offset = 0x124; |
157 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
190 | 158 | |
191 | 159 | WriteDescriptor32(0xf800, 0x200000); |
192 | - WriteEntry32Pad(0x200000, 0, 0, 0x300000); | |
160 | + WriteEntry32(0x200000, 0, 0, 0x300000); | |
193 | 161 | WriteDex(0x300000); |
194 | 162 | |
195 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
163 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
196 | 164 | EXPECT_EQ("Main.<init>", method_name); |
197 | 165 | EXPECT_EQ(0U, method_offset); |
198 | 166 | } |
@@ -202,12 +170,13 @@ TEST_F(DexFilesTest, get_method_information_64) { | ||
202 | 170 | |
203 | 171 | std::string method_name = "nothing"; |
204 | 172 | uint64_t method_offset = 0x124; |
173 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
205 | 174 | |
206 | 175 | WriteDescriptor64(0xf800, 0x200000); |
207 | 176 | WriteEntry64(0x200000, 0, 0, 0x301000); |
208 | 177 | WriteDex(0x301000); |
209 | 178 | |
210 | - dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset); | |
179 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset); | |
211 | 180 | EXPECT_EQ("Main.<init>", method_name); |
212 | 181 | EXPECT_EQ(2U, method_offset); |
213 | 182 | } |
@@ -215,14 +184,14 @@ TEST_F(DexFilesTest, get_method_information_64) { | ||
215 | 184 | TEST_F(DexFilesTest, get_method_information_not_first_entry_32) { |
216 | 185 | std::string method_name = "nothing"; |
217 | 186 | uint64_t method_offset = 0x124; |
187 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
218 | 188 | |
219 | 189 | WriteDescriptor32(0xf800, 0x200000); |
220 | - WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000); | |
221 | - WriteDex(0x100000); | |
222 | - WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000); | |
190 | + WriteEntry32(0x200000, 0x200100, 0, 0x100000); | |
191 | + WriteEntry32(0x200100, 0, 0x200000, 0x300000); | |
223 | 192 | WriteDex(0x300000); |
224 | 193 | |
225 | - dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); | |
194 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); | |
226 | 195 | EXPECT_EQ("Main.<init>", method_name); |
227 | 196 | EXPECT_EQ(4U, method_offset); |
228 | 197 | } |
@@ -232,14 +201,14 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { | ||
232 | 201 | |
233 | 202 | std::string method_name = "nothing"; |
234 | 203 | uint64_t method_offset = 0x124; |
204 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
235 | 205 | |
236 | 206 | WriteDescriptor64(0xf800, 0x200000); |
237 | 207 | WriteEntry64(0x200000, 0x200100, 0, 0x100000); |
238 | - WriteDex(0x100000); | |
239 | 208 | WriteEntry64(0x200100, 0, 0x200000, 0x300000); |
240 | 209 | WriteDex(0x300000); |
241 | 210 | |
242 | - dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset); | |
211 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset); | |
243 | 212 | EXPECT_EQ("Main.<init>", method_name); |
244 | 213 | EXPECT_EQ(6U, method_offset); |
245 | 214 | } |
@@ -247,18 +216,19 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { | ||
247 | 216 | TEST_F(DexFilesTest, get_method_information_cached) { |
248 | 217 | std::string method_name = "nothing"; |
249 | 218 | uint64_t method_offset = 0x124; |
219 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
250 | 220 | |
251 | 221 | WriteDescriptor32(0xf800, 0x200000); |
252 | - WriteEntry32Pad(0x200000, 0, 0, 0x300000); | |
222 | + WriteEntry32(0x200000, 0, 0, 0x300000); | |
253 | 223 | WriteDex(0x300000); |
254 | 224 | |
255 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
225 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
256 | 226 | EXPECT_EQ("Main.<init>", method_name); |
257 | 227 | EXPECT_EQ(0U, method_offset); |
258 | 228 | |
259 | 229 | // Clear all memory and make sure that data is acquired from the cache. |
260 | 230 | memory_->Clear(); |
261 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
231 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
262 | 232 | EXPECT_EQ("Main.<init>", method_name); |
263 | 233 | EXPECT_EQ(0U, method_offset); |
264 | 234 | } |
@@ -266,24 +236,26 @@ TEST_F(DexFilesTest, get_method_information_cached) { | ||
266 | 236 | TEST_F(DexFilesTest, get_method_information_search_libs) { |
267 | 237 | std::string method_name = "nothing"; |
268 | 238 | uint64_t method_offset = 0x124; |
239 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
269 | 240 | |
270 | 241 | WriteDescriptor32(0xf800, 0x200000); |
271 | - WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000); | |
272 | - WriteDex(0x100000); | |
273 | - WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000); | |
242 | + WriteEntry32(0x200000, 0x200100, 0, 0x100000); | |
243 | + WriteEntry32(0x200100, 0, 0x200000, 0x300000); | |
274 | 244 | WriteDex(0x300000); |
275 | 245 | |
276 | 246 | // Only search a given named list of libs. |
277 | 247 | std::vector<std::string> libs{"libart.so"}; |
278 | - dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs); | |
248 | + dex_files_.reset(new DexFiles(process_memory_, libs)); | |
249 | + dex_files_->SetArch(ARCH_ARM); | |
279 | 250 | |
280 | - dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); | |
251 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); | |
281 | 252 | EXPECT_EQ("nothing", method_name); |
282 | 253 | EXPECT_EQ(0x124U, method_offset); |
283 | 254 | |
284 | 255 | MapInfo* map_info = maps_->Get(kMapGlobal); |
285 | 256 | map_info->name = "/system/lib/libart.so"; |
286 | - dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs); | |
257 | + dex_files_.reset(new DexFiles(process_memory_, libs)); | |
258 | + dex_files_->SetArch(ARCH_ARM); | |
287 | 259 | // Set the rw map to the same name or this will not scan this entry. |
288 | 260 | map_info = maps_->Get(kMapGlobalRw); |
289 | 261 | map_info->name = "/system/lib/libart.so"; |
@@ -291,7 +263,7 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { | ||
291 | 263 | // DexFiles object. |
292 | 264 | libs.clear(); |
293 | 265 | |
294 | - dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); | |
266 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); | |
295 | 267 | EXPECT_EQ("Main.<init>", method_name); |
296 | 268 | EXPECT_EQ(4U, method_offset); |
297 | 269 | } |
@@ -299,24 +271,26 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { | ||
299 | 271 | TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) { |
300 | 272 | std::string method_name = "nothing"; |
301 | 273 | uint64_t method_offset = 0x124; |
274 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
302 | 275 | |
303 | 276 | // First global variable found, but value is zero. |
304 | 277 | WriteDescriptor32(0xa800, 0); |
305 | 278 | |
306 | 279 | WriteDescriptor32(0xf800, 0x200000); |
307 | - WriteEntry32Pad(0x200000, 0, 0, 0x300000); | |
280 | + WriteEntry32(0x200000, 0, 0, 0x300000); | |
308 | 281 | WriteDex(0x300000); |
309 | 282 | |
310 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
283 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
311 | 284 | EXPECT_EQ("Main.<init>", method_name); |
312 | 285 | EXPECT_EQ(0U, method_offset); |
313 | 286 | |
314 | 287 | // Verify that second is ignored when first is set to non-zero |
315 | - dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_); | |
288 | + dex_files_.reset(new DexFiles(process_memory_)); | |
289 | + dex_files_->SetArch(ARCH_ARM); | |
316 | 290 | method_name = "fail"; |
317 | 291 | method_offset = 0x123; |
318 | 292 | WriteDescriptor32(0xa800, 0x100000); |
319 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
293 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
320 | 294 | EXPECT_EQ("fail", method_name); |
321 | 295 | EXPECT_EQ(0x123U, method_offset); |
322 | 296 | } |
@@ -326,6 +300,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { | ||
326 | 300 | |
327 | 301 | std::string method_name = "nothing"; |
328 | 302 | uint64_t method_offset = 0x124; |
303 | + MapInfo* info = maps_->Get(kMapDexFiles); | |
329 | 304 | |
330 | 305 | // First global variable found, but value is zero. |
331 | 306 | WriteDescriptor64(0xa800, 0); |
@@ -334,16 +309,17 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { | ||
334 | 309 | WriteEntry64(0x200000, 0, 0, 0x300000); |
335 | 310 | WriteDex(0x300000); |
336 | 311 | |
337 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
312 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
338 | 313 | EXPECT_EQ("Main.<init>", method_name); |
339 | 314 | EXPECT_EQ(0U, method_offset); |
340 | 315 | |
341 | 316 | // Verify that second is ignored when first is set to non-zero |
342 | - dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM64, process_memory_); | |
317 | + dex_files_.reset(new DexFiles(process_memory_)); | |
318 | + dex_files_->SetArch(ARCH_ARM64); | |
343 | 319 | method_name = "fail"; |
344 | 320 | method_offset = 0x123; |
345 | 321 | WriteDescriptor64(0xa800, 0x100000); |
346 | - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
322 | + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
347 | 323 | EXPECT_EQ("fail", method_name); |
348 | 324 | EXPECT_EQ(0x123U, method_offset); |
349 | 325 | } |
@@ -46,7 +46,8 @@ class JitDebugTest : public ::testing::Test { | ||
46 | 46 | } |
47 | 47 | |
48 | 48 | void Init(ArchEnum arch) { |
49 | - jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_); | |
49 | + jit_debug_.reset(new JitDebug(process_memory_)); | |
50 | + jit_debug_->SetArch(arch); | |
50 | 51 | |
51 | 52 | maps_.reset( |
52 | 53 | new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n" |
@@ -61,12 +62,6 @@ class JitDebugTest : public ::testing::Test { | ||
61 | 62 | "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n")); |
62 | 63 | ASSERT_TRUE(maps_->Parse()); |
63 | 64 | |
64 | - // Ensure all memory of the ELF file is initialized, | |
65 | - // otherwise reads within it may fail. | |
66 | - for (uint64_t addr = 0x4000; addr < 0x6000; addr += 8) { | |
67 | - memory_->SetData64(addr, 0); | |
68 | - } | |
69 | - | |
70 | 65 | MapInfo* map_info = maps_->Get(3); |
71 | 66 | ASSERT_TRUE(map_info != nullptr); |
72 | 67 | CreateFakeElf(map_info); |
@@ -99,7 +94,7 @@ class JitDebugTest : public ::testing::Test { | ||
99 | 94 | ehdr.e_shstrndx = 1; |
100 | 95 | ehdr.e_shoff = sh_offset; |
101 | 96 | ehdr.e_shentsize = sizeof(ShdrType); |
102 | - ehdr.e_shnum = 4; | |
97 | + ehdr.e_shnum = 3; | |
103 | 98 | memory_->SetMemory(offset, &ehdr, sizeof(ehdr)); |
104 | 99 | |
105 | 100 | ShdrType shdr; |
@@ -115,7 +110,6 @@ class JitDebugTest : public ::testing::Test { | ||
115 | 110 | shdr.sh_size = 0x100; |
116 | 111 | memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); |
117 | 112 | memory_->SetMemory(offset + 0x500, ".debug_frame"); |
118 | - memory_->SetMemory(offset + 0x550, ".text"); | |
119 | 113 | |
120 | 114 | sh_offset += sizeof(shdr); |
121 | 115 | memset(&shdr, 0, sizeof(shdr)); |
@@ -126,15 +120,6 @@ class JitDebugTest : public ::testing::Test { | ||
126 | 120 | shdr.sh_size = 0x200; |
127 | 121 | memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); |
128 | 122 | |
129 | - sh_offset += sizeof(shdr); | |
130 | - memset(&shdr, 0, sizeof(shdr)); | |
131 | - shdr.sh_type = SHT_NOBITS; | |
132 | - shdr.sh_name = 0x50; | |
133 | - shdr.sh_addr = pc; | |
134 | - shdr.sh_offset = 0; | |
135 | - shdr.sh_size = size; | |
136 | - memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); | |
137 | - | |
138 | 123 | // Now add a single cie/fde. |
139 | 124 | uint64_t dwarf_offset = offset + 0x600; |
140 | 125 | if (class_type == ELFCLASS32) { |
@@ -183,7 +168,7 @@ class JitDebugTest : public ::testing::Test { | ||
183 | 168 | |
184 | 169 | std::shared_ptr<Memory> process_memory_; |
185 | 170 | MemoryFake* memory_; |
186 | - std::unique_ptr<JitDebug<Elf>> jit_debug_; | |
171 | + std::unique_ptr<JitDebug> jit_debug_; | |
187 | 172 | std::unique_ptr<BufferMaps> maps_; |
188 | 173 | }; |
189 | 174 |
@@ -253,20 +238,20 @@ void JitDebugTest::WriteEntry64(uint64_t addr, uint64_t prev, uint64_t next, uin | ||
253 | 238 | } |
254 | 239 | |
255 | 240 | TEST_F(JitDebugTest, get_elf_invalid) { |
256 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
241 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
257 | 242 | ASSERT_TRUE(elf == nullptr); |
258 | 243 | } |
259 | 244 | |
260 | 245 | TEST_F(JitDebugTest, get_elf_no_global_variable) { |
261 | 246 | maps_.reset(new BufferMaps("")); |
262 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
247 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
263 | 248 | ASSERT_TRUE(elf == nullptr); |
264 | 249 | } |
265 | 250 | |
266 | 251 | TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) { |
267 | 252 | CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); |
268 | 253 | |
269 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
254 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
270 | 255 | ASSERT_TRUE(elf == nullptr); |
271 | 256 | } |
272 | 257 |
@@ -275,7 +260,7 @@ TEST_F(JitDebugTest, get_elf_no_valid_code_entry) { | ||
275 | 260 | |
276 | 261 | WriteDescriptor32(0xf800, 0x200000); |
277 | 262 | |
278 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
263 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
279 | 264 | ASSERT_TRUE(elf == nullptr); |
280 | 265 | } |
281 | 266 |
@@ -284,7 +269,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_first_entry) { | ||
284 | 269 | |
285 | 270 | WriteDescriptor32(0xf800, 0); |
286 | 271 | |
287 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
272 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
288 | 273 | ASSERT_TRUE(elf == nullptr); |
289 | 274 | } |
290 | 275 |
@@ -295,7 +280,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_version) { | ||
295 | 280 | // Set the version to an invalid value. |
296 | 281 | memory_->SetData32(0xf800, 2); |
297 | 282 | |
298 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
283 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
299 | 284 | ASSERT_TRUE(elf == nullptr); |
300 | 285 | } |
301 | 286 |
@@ -305,18 +290,12 @@ TEST_F(JitDebugTest, get_elf_32) { | ||
305 | 290 | WriteDescriptor32(0xf800, 0x200000); |
306 | 291 | WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000); |
307 | 292 | |
308 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
293 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
309 | 294 | ASSERT_TRUE(elf != nullptr); |
310 | - uint64_t text_addr; | |
311 | - uint64_t text_size; | |
312 | - ASSERT_TRUE(elf->GetTextRange(&text_addr, &text_size)); | |
313 | - ASSERT_EQ(text_addr, 0x1500u); | |
314 | - ASSERT_EQ(text_size, 0x200u); | |
315 | 295 | |
316 | 296 | // Clear the memory and verify all of the data is cached. |
317 | 297 | memory_->Clear(); |
318 | - WriteDescriptor32(0xf800, 0x200000); | |
319 | - Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); | |
298 | + Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); | |
320 | 299 | ASSERT_TRUE(elf2 != nullptr); |
321 | 300 | EXPECT_EQ(elf, elf2); |
322 | 301 | } |
@@ -330,15 +309,16 @@ TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) { | ||
330 | 309 | WriteDescriptor32(0x12800, 0x201000); |
331 | 310 | WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000); |
332 | 311 | |
333 | - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr); | |
334 | - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr); | |
312 | + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); | |
313 | + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr); | |
335 | 314 | |
336 | 315 | // Now clear the descriptor entry for the first one. |
337 | 316 | WriteDescriptor32(0xf800, 0); |
338 | - jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_); | |
317 | + jit_debug_.reset(new JitDebug(process_memory_)); | |
318 | + jit_debug_->SetArch(ARCH_ARM); | |
339 | 319 | |
340 | - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr); | |
341 | - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr); | |
320 | + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr); | |
321 | + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr); | |
342 | 322 | } |
343 | 323 | |
344 | 324 | TEST_F(JitDebugTest, get_elf_x86) { |
@@ -349,14 +329,13 @@ TEST_F(JitDebugTest, get_elf_x86) { | ||
349 | 329 | WriteDescriptor32(0xf800, 0x200000); |
350 | 330 | WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000); |
351 | 331 | |
352 | - jit_debug_ = JitDebug<Elf>::Create(ARCH_X86, process_memory_); | |
353 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
332 | + jit_debug_->SetArch(ARCH_X86); | |
333 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
354 | 334 | ASSERT_TRUE(elf != nullptr); |
355 | 335 | |
356 | 336 | // Clear the memory and verify all of the data is cached. |
357 | 337 | memory_->Clear(); |
358 | - WriteDescriptor32(0xf800, 0x200000); | |
359 | - Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); | |
338 | + Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); | |
360 | 339 | ASSERT_TRUE(elf2 != nullptr); |
361 | 340 | EXPECT_EQ(elf, elf2); |
362 | 341 | } |
@@ -369,13 +348,12 @@ TEST_F(JitDebugTest, get_elf_64) { | ||
369 | 348 | WriteDescriptor64(0xf800, 0x200000); |
370 | 349 | WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000); |
371 | 350 | |
372 | - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
351 | + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
373 | 352 | ASSERT_TRUE(elf != nullptr); |
374 | 353 | |
375 | 354 | // Clear the memory and verify all of the data is cached. |
376 | 355 | memory_->Clear(); |
377 | - WriteDescriptor64(0xf800, 0x200000); | |
378 | - Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); | |
356 | + Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); | |
379 | 357 | ASSERT_TRUE(elf2 != nullptr); |
380 | 358 | EXPECT_EQ(elf, elf2); |
381 | 359 | } |
@@ -388,21 +366,20 @@ TEST_F(JitDebugTest, get_elf_multiple_entries) { | ||
388 | 366 | WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000); |
389 | 367 | WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000); |
390 | 368 | |
391 | - Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400); | |
369 | + Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400); | |
392 | 370 | ASSERT_TRUE(elf_2 != nullptr); |
393 | 371 | |
394 | - Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600); | |
372 | + Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600); | |
395 | 373 | ASSERT_TRUE(elf_1 != nullptr); |
396 | 374 | |
397 | 375 | // Clear the memory and verify all of the data is cached. |
398 | 376 | memory_->Clear(); |
399 | - WriteDescriptor32(0xf800, 0x200000); | |
400 | - EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x1500)); | |
401 | - EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x16ff)); | |
402 | - EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x2300)); | |
403 | - EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x26ff)); | |
404 | - EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x1700)); | |
405 | - EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x2700)); | |
377 | + EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x1500)); | |
378 | + EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x16ff)); | |
379 | + EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x2300)); | |
380 | + EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x26ff)); | |
381 | + EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x1700)); | |
382 | + EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x2700)); | |
406 | 383 | } |
407 | 384 | |
408 | 385 | TEST_F(JitDebugTest, get_elf_search_libs) { |
@@ -413,19 +390,21 @@ TEST_F(JitDebugTest, get_elf_search_libs) { | ||
413 | 390 | |
414 | 391 | // Only search a given named list of libs. |
415 | 392 | std::vector<std::string> libs{"libart.so"}; |
416 | - jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_, libs); | |
417 | - EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr); | |
393 | + jit_debug_.reset(new JitDebug(process_memory_, libs)); | |
394 | + jit_debug_->SetArch(ARCH_ARM); | |
395 | + EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr); | |
418 | 396 | |
419 | 397 | // Change the name of the map that includes the value and verify this works. |
420 | 398 | MapInfo* map_info = maps_->Get(5); |
421 | 399 | map_info->name = "/system/lib/libart.so"; |
422 | 400 | map_info = maps_->Get(6); |
423 | 401 | map_info->name = "/system/lib/libart.so"; |
424 | - jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_); | |
402 | + jit_debug_.reset(new JitDebug(process_memory_, libs)); | |
425 | 403 | // Make sure that clearing our copy of the libs doesn't affect the |
426 | 404 | // JitDebug object. |
427 | 405 | libs.clear(); |
428 | - EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr); | |
406 | + jit_debug_->SetArch(ARCH_ARM); | |
407 | + EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); | |
429 | 408 | } |
430 | 409 | |
431 | 410 | } // namespace unwindstack |
@@ -307,7 +307,9 @@ TEST_F(UnwindOfflineTest, jit_debug_x86) { | ||
307 | 307 | } |
308 | 308 | process_memory_.reset(memory); |
309 | 309 | |
310 | + JitDebug jit_debug(process_memory_); | |
310 | 311 | Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); |
312 | + unwinder.SetJitDebug(&jit_debug, regs_->Arch()); | |
311 | 313 | unwinder.Unwind(); |
312 | 314 | |
313 | 315 | std::string frame_info(DumpFrames(unwinder)); |
@@ -607,7 +609,9 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { | ||
607 | 609 | } |
608 | 610 | process_memory_.reset(memory); |
609 | 611 | |
612 | + JitDebug jit_debug(process_memory_); | |
610 | 613 | Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); |
614 | + unwinder.SetJitDebug(&jit_debug, regs_->Arch()); | |
611 | 615 | unwinder.Unwind(); |
612 | 616 | |
613 | 617 | std::string frame_info(DumpFrames(unwinder)); |
@@ -928,7 +932,9 @@ static void OfflineUnwind(void* data) { | ||
928 | 932 | LeakType* leak_data = reinterpret_cast<LeakType*>(data); |
929 | 933 | |
930 | 934 | std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone()); |
935 | + JitDebug jit_debug(leak_data->process_memory); | |
931 | 936 | Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory); |
937 | + unwinder.SetJitDebug(&jit_debug, regs_copy->Arch()); | |
932 | 938 | unwinder.Unwind(); |
933 | 939 | ASSERT_EQ(76U, unwinder.NumFrames()); |
934 | 940 | } |
@@ -1049,7 +1055,9 @@ TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) { | ||
1049 | 1055 | } |
1050 | 1056 | process_memory_.reset(memory); |
1051 | 1057 | |
1058 | + JitDebug jit_debug(process_memory_); | |
1052 | 1059 | Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); |
1060 | + unwinder.SetJitDebug(&jit_debug, regs_->Arch()); | |
1053 | 1061 | unwinder.Unwind(); |
1054 | 1062 | |
1055 | 1063 | std::string frame_info(DumpFrames(unwinder)); |
@@ -170,7 +170,7 @@ extern "C" void InnerFunction(TestTypeEnum test_type) { | ||
170 | 170 | unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory)); |
171 | 171 | } else { |
172 | 172 | UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid()); |
173 | - ASSERT_TRUE(unwinder_from_pid->Init()); | |
173 | + ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch())); | |
174 | 174 | unwinder_from_pid->SetRegs(regs.get()); |
175 | 175 | unwinder.reset(unwinder_from_pid); |
176 | 176 | } |
@@ -283,7 +283,7 @@ TEST_F(UnwindTest, unwind_from_pid_remote) { | ||
283 | 283 | ASSERT_TRUE(regs.get() != nullptr); |
284 | 284 | |
285 | 285 | UnwinderFromPid unwinder(512, pid); |
286 | - ASSERT_TRUE(unwinder.Init()); | |
286 | + ASSERT_TRUE(unwinder.Init(regs->Arch())); | |
287 | 287 | unwinder.SetRegs(regs.get()); |
288 | 288 | |
289 | 289 | VerifyUnwind(&unwinder, kFunctionOrder); |
@@ -335,7 +335,7 @@ static void RemoteUnwindFromPid(void* data) { | ||
335 | 335 | ASSERT_TRUE(regs.get() != nullptr); |
336 | 336 | |
337 | 337 | UnwinderFromPid unwinder(512, *pid); |
338 | - ASSERT_TRUE(unwinder.Init()); | |
338 | + ASSERT_TRUE(unwinder.Init(regs->Arch())); | |
339 | 339 | unwinder.SetRegs(regs.get()); |
340 | 340 | |
341 | 341 | VerifyUnwind(&unwinder, kFunctionOrder); |
@@ -26,6 +26,7 @@ | ||
26 | 26 | #include <sys/types.h> |
27 | 27 | #include <unistd.h> |
28 | 28 | |
29 | +#include <unwindstack/DexFiles.h> | |
29 | 30 | #include <unwindstack/Elf.h> |
30 | 31 | #include <unwindstack/JitDebug.h> |
31 | 32 | #include <unwindstack/Maps.h> |
@@ -89,7 +90,7 @@ void DoUnwind(pid_t pid) { | ||
89 | 90 | printf("\n"); |
90 | 91 | |
91 | 92 | unwindstack::UnwinderFromPid unwinder(1024, pid); |
92 | - if (!unwinder.Init()) { | |
93 | + if (!unwinder.Init(regs->Arch())) { | |
93 | 94 | printf("Failed to init unwinder object.\n"); |
94 | 95 | return; |
95 | 96 | } |
@@ -248,7 +248,7 @@ int SaveData(pid_t pid) { | ||
248 | 248 | // Do an unwind so we know how much of the stack to save, and what |
249 | 249 | // elf files are involved. |
250 | 250 | unwindstack::UnwinderFromPid unwinder(1024, pid); |
251 | - if (!unwinder.Init()) { | |
251 | + if (!unwinder.Init(regs->Arch())) { | |
252 | 252 | printf("Unable to init unwinder object.\n"); |
253 | 253 | return 1; |
254 | 254 | } |