system/core
修訂 | 4d03a384c2cd5a8b0cd65b682cf7653aff0b0379 (tree) |
---|---|
時間 | 2019-04-03 17:39:57 |
作者 | David Srbecky <dsrbecky@goog...> |
Commiter | android-build-merger |
Merge "Check for data races when reading JIT/DEX entries." am: 59c70a5b75
am: 9363485979
Change-Id: If702c873330b09020dd701f5e786a03ca4d28ac0
@@ -48,7 +48,6 @@ | ||
48 | 48 | #define ATRACE_TAG ATRACE_TAG_BIONIC |
49 | 49 | #include <utils/Trace.h> |
50 | 50 | |
51 | -#include <unwindstack/DexFiles.h> | |
52 | 51 | #include <unwindstack/JitDebug.h> |
53 | 52 | #include <unwindstack/Maps.h> |
54 | 53 | #include <unwindstack/Memory.h> |
@@ -567,7 +566,7 @@ int main(int argc, char** argv) { | ||
567 | 566 | |
568 | 567 | // TODO: Use seccomp to lock ourselves down. |
569 | 568 | unwindstack::UnwinderFromPid unwinder(256, vm_pid); |
570 | - if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { | |
569 | + if (!unwinder.Init()) { | |
571 | 570 | LOG(FATAL) << "Failed to init unwinder object."; |
572 | 571 | } |
573 | 572 |
@@ -42,7 +42,6 @@ | ||
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> | |
46 | 45 | #include <unwindstack/JitDebug.h> |
47 | 46 | #include <unwindstack/Maps.h> |
48 | 47 | #include <unwindstack/Memory.h> |
@@ -81,12 +80,12 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) { | ||
81 | 80 | thread.pid = getpid(); |
82 | 81 | thread.tid = gettid(); |
83 | 82 | thread.thread_name = get_thread_name(gettid()); |
84 | - unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch(); | |
85 | - thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext)); | |
83 | + thread.registers.reset( | |
84 | + unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); | |
86 | 85 | |
87 | 86 | // TODO: Create this once and store it in a global? |
88 | 87 | unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid()); |
89 | - if (unwinder.Init(arch)) { | |
88 | + if (unwinder.Init()) { | |
90 | 89 | dump_backtrace_thread(output_fd, &unwinder, thread); |
91 | 90 | } else { |
92 | 91 | async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder."); |
@@ -44,7 +44,6 @@ | ||
44 | 44 | #include <log/log.h> |
45 | 45 | #include <log/logprint.h> |
46 | 46 | #include <private/android_filesystem_config.h> |
47 | -#include <unwindstack/DexFiles.h> | |
48 | 47 | #include <unwindstack/JitDebug.h> |
49 | 48 | #include <unwindstack/Maps.h> |
50 | 49 | #include <unwindstack/Memory.h> |
@@ -650,7 +649,7 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si | ||
650 | 649 | }; |
651 | 650 | |
652 | 651 | unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid); |
653 | - if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { | |
652 | + if (!unwinder.Init()) { | |
654 | 653 | LOG(FATAL) << "Failed to init unwinder object."; |
655 | 654 | } |
656 | 655 |
@@ -32,9 +32,6 @@ | ||
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 | |
38 | 35 | #include <unwindstack/Unwinder.h> |
39 | 36 | |
40 | 37 | #include "BacktraceLog.h" |
@@ -50,14 +47,6 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, | ||
50 | 47 | regs, stack_map->process_memory()); |
51 | 48 | unwinder.SetResolveNames(stack_map->ResolveNames()); |
52 | 49 | 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 | |
61 | 50 | unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore()); |
62 | 51 | if (error != nullptr) { |
63 | 52 | switch (unwinder.LastErrorCode()) { |
@@ -43,13 +43,6 @@ 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 | - | |
53 | 46 | if (!stack_maps_->Parse()) { |
54 | 47 | return false; |
55 | 48 | } |
@@ -27,9 +27,6 @@ | ||
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 | |
33 | 30 | #include <unwindstack/Elf.h> |
34 | 31 | #include <unwindstack/JitDebug.h> |
35 | 32 | #include <unwindstack/Maps.h> |
@@ -53,12 +50,6 @@ class UnwindStackMap : public BacktraceMap { | ||
53 | 50 | |
54 | 51 | const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; } |
55 | 52 | |
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 | - | |
62 | 53 | void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; } |
63 | 54 | |
64 | 55 | protected: |
@@ -66,11 +57,6 @@ class UnwindStackMap : public BacktraceMap { | ||
66 | 57 | |
67 | 58 | std::unique_ptr<unwindstack::Maps> stack_maps_; |
68 | 59 | 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 | - | |
74 | 60 | unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN; |
75 | 61 | }; |
76 | 62 |
@@ -49,7 +49,6 @@ cc_library { | ||
49 | 49 | srcs: [ |
50 | 50 | "ArmExidx.cpp", |
51 | 51 | "DexFile.cpp", |
52 | - "DexFiles.cpp", | |
53 | 52 | "DwarfCfa.cpp", |
54 | 53 | "DwarfEhFrameWithHdr.cpp", |
55 | 54 | "DwarfMemory.cpp", |
@@ -92,7 +91,6 @@ cc_library { | ||
92 | 91 | cflags: ["-DNO_LIBDEXFILE_SUPPORT"], |
93 | 92 | exclude_srcs: [ |
94 | 93 | "DexFile.cpp", |
95 | - "DexFiles.cpp", | |
96 | 94 | ], |
97 | 95 | exclude_shared_libs: [ |
98 | 96 | "libdexfile_support", |
@@ -102,7 +100,6 @@ cc_library { | ||
102 | 100 | cflags: ["-DNO_LIBDEXFILE_SUPPORT"], |
103 | 101 | exclude_srcs: [ |
104 | 102 | "DexFile.cpp", |
105 | - "DexFiles.cpp", | |
106 | 103 | ], |
107 | 104 | exclude_shared_libs: [ |
108 | 105 | "libdexfile_support", |
@@ -35,22 +35,31 @@ 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 = | |
38 | + std::unique_ptr<DexFile> dex_file_from_file = | |
39 | 39 | DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name); |
40 | - if (dex_file) { | |
41 | - return dex_file; | |
40 | + if (dex_file_from_file) { | |
41 | + dex_file_from_file->addr_ = dex_file_offset_in_memory; | |
42 | + return dex_file_from_file; | |
42 | 43 | } |
43 | 44 | } |
44 | - return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); | |
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; | |
45 | 52 | } |
46 | 53 | |
47 | -bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, | |
48 | - uint64_t* method_offset) { | |
54 | +bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) { | |
55 | + uint64_t dex_offset = dex_pc - addr_; | |
49 | 56 | art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false); |
50 | 57 | if (method_info.offset == 0) { |
51 | 58 | return false; |
52 | 59 | } |
53 | - *method_name = method_info.name; | |
60 | + if (method_name != nullptr) { | |
61 | + *method_name = method_info.name; | |
62 | + } | |
54 | 63 | *method_offset = dex_offset - method_info.offset; |
55 | 64 | return true; |
56 | 65 | } |
@@ -29,17 +29,22 @@ | ||
29 | 29 | |
30 | 30 | namespace unwindstack { |
31 | 31 | |
32 | +class Memory; | |
33 | +struct MapInfo; | |
34 | + | |
32 | 35 | class DexFile : protected art_api::dex::DexFile { |
33 | 36 | public: |
34 | 37 | virtual ~DexFile() = default; |
35 | 38 | |
36 | - bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); | |
39 | + bool GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset); | |
37 | 40 | |
38 | 41 | static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory, |
39 | 42 | MapInfo* info); |
40 | 43 | |
41 | 44 | protected: |
42 | 45 | DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {} |
46 | + | |
47 | + uint64_t addr_ = 0; | |
43 | 48 | }; |
44 | 49 | |
45 | 50 | class DexFileFromFile : public DexFile { |
@@ -1,179 +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 <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,6 +243,24 @@ 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 | + | |
246 | 264 | ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { |
247 | 265 | if (!IsValidElf(memory)) { |
248 | 266 | return nullptr; |
@@ -69,6 +69,15 @@ 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 | + | |
72 | 81 | Memory* ElfInterface::CreateGnuDebugdataMemory() { |
73 | 82 | if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) { |
74 | 83 | return nullptr; |
@@ -330,29 +339,26 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { | ||
330 | 339 | } |
331 | 340 | symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, |
332 | 341 | str_shdr.sh_offset, str_shdr.sh_size)); |
333 | - } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) { | |
342 | + } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) { | |
334 | 343 | // Look for the .debug_frame and .gnu_debugdata. |
335 | 344 | if (shdr.sh_name < sec_size) { |
336 | 345 | std::string name; |
337 | 346 | if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { |
338 | - uint64_t* offset_ptr = nullptr; | |
339 | - uint64_t* size_ptr = nullptr; | |
340 | 347 | if (name == ".debug_frame") { |
341 | - offset_ptr = &debug_frame_offset_; | |
342 | - size_ptr = &debug_frame_size_; | |
348 | + debug_frame_offset_ = shdr.sh_offset; | |
349 | + debug_frame_size_ = shdr.sh_size; | |
343 | 350 | } else if (name == ".gnu_debugdata") { |
344 | - offset_ptr = &gnu_debugdata_offset_; | |
345 | - size_ptr = &gnu_debugdata_size_; | |
351 | + gnu_debugdata_offset_ = shdr.sh_offset; | |
352 | + gnu_debugdata_size_ = shdr.sh_size; | |
346 | 353 | } else if (name == ".eh_frame") { |
347 | - offset_ptr = &eh_frame_offset_; | |
348 | - size_ptr = &eh_frame_size_; | |
354 | + eh_frame_offset_ = shdr.sh_offset; | |
355 | + eh_frame_size_ = shdr.sh_size; | |
349 | 356 | } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") { |
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; | |
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; | |
356 | 362 | } |
357 | 363 | } |
358 | 364 | } |
@@ -16,8 +16,13 @@ | ||
16 | 16 | |
17 | 17 | #include <stdint.h> |
18 | 18 | #include <sys/mman.h> |
19 | +#include <cstddef> | |
19 | 20 | |
21 | +#include <atomic> | |
22 | +#include <deque> | |
23 | +#include <map> | |
20 | 24 | #include <memory> |
25 | +#include <unordered_set> | |
21 | 26 | #include <vector> |
22 | 27 | |
23 | 28 | #include <unwindstack/Elf.h> |
@@ -25,197 +30,334 @@ | ||
25 | 30 | #include <unwindstack/Maps.h> |
26 | 31 | #include <unwindstack/Memory.h> |
27 | 32 | |
33 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
34 | +#include <DexFile.h> | |
35 | +#endif | |
36 | + | |
28 | 37 | // This implements the JIT Compilation Interface. |
29 | 38 | // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html |
30 | 39 | |
31 | 40 | namespace unwindstack { |
32 | 41 | |
33 | -struct JITCodeEntry32Pack { | |
34 | - uint32_t next; | |
35 | - uint32_t prev; | |
36 | - uint32_t symfile_addr; | |
37 | - uint64_t symfile_size; | |
42 | +// 32-bit platforms may differ in alignment of uint64_t. | |
43 | +struct Uint64_P { | |
44 | + uint64_t value; | |
38 | 45 | } __attribute__((packed)); |
39 | - | |
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 | +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; | |
46 | 60 | }; |
47 | 61 | |
48 | -struct JITCodeEntry64 { | |
49 | - uint64_t next; | |
50 | - uint64_t prev; | |
51 | - uint64_t symfile_addr; | |
52 | - uint64_t symfile_size; | |
53 | -}; | |
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_; | |
54 | 68 | |
55 | -struct JITDescriptorHeader { | |
56 | - uint32_t version; | |
57 | - uint32_t action_flag; | |
69 | + bool Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t size); | |
58 | 70 | }; |
59 | 71 | |
60 | -struct JITDescriptor32 { | |
61 | - JITDescriptorHeader header; | |
62 | - uint32_t relevant_entry; | |
63 | - uint32_t first_entry; | |
64 | -}; | |
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 | + } | |
65 | 108 | |
66 | -struct JITDescriptor64 { | |
67 | - JITDescriptorHeader header; | |
68 | - uint64_t relevant_entry; | |
69 | - uint64_t first_entry; | |
70 | -}; | |
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); | |
114 | + | |
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. | |
71 | 119 | |
72 | -JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {} | |
120 | + std::deque<JitCacheEntry<Symfile>> entries_; | |
73 | 121 | |
74 | -JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) | |
75 | - : Global(memory, search_libs) {} | |
122 | + std::mutex lock_; | |
123 | +}; | |
76 | 124 | |
77 | -JitDebug::~JitDebug() { | |
78 | - for (auto* elf : elf_list_) { | |
79 | - delete elf; | |
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(); | |
80 | 156 | } |
81 | 157 | } |
82 | 158 | |
83 | -uint64_t JitDebug::ReadDescriptor32(uint64_t addr) { | |
84 | - JITDescriptor32 desc; | |
85 | - if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { | |
159 | +size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) { | |
160 | + if (!parent_->ReadFully(addr, dst, size)) { | |
86 | 161 | return 0; |
87 | 162 | } |
88 | - | |
89 | - if (desc.header.version != 1 || desc.first_entry == 0) { | |
90 | - // Either unknown version, or no jit entries. | |
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)) { | |
91 | 168 | return 0; |
92 | 169 | } |
93 | - | |
94 | - return desc.first_entry; | |
95 | -} | |
96 | - | |
97 | -uint64_t JitDebug::ReadDescriptor64(uint64_t addr) { | |
98 | - JITDescriptor64 desc; | |
99 | - if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { | |
170 | + if (seen_seqlock != expected_seqlock_) { | |
171 | + failed_due_to_race_ = true; | |
100 | 172 | return 0; |
101 | 173 | } |
174 | + return size; | |
175 | +} | |
102 | 176 | |
103 | - if (desc.header.version != 1 || desc.first_entry == 0) { | |
104 | - // Either unknown version, or no jit entries. | |
105 | - return 0; | |
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; | |
106 | 182 | } |
107 | - | |
108 | - return desc.first_entry; | |
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); | |
197 | + } | |
198 | + return true; | |
109 | 199 | } |
110 | 200 | |
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; | |
115 | - } | |
201 | +template <typename Symfile> | |
202 | +static const char* GetDescriptorName(); | |
116 | 203 | |
117 | - *start = code.symfile_addr; | |
118 | - *size = code.symfile_size; | |
119 | - return code.next; | |
204 | +template <> | |
205 | +const char* GetDescriptorName<Elf>() { | |
206 | + return "__jit_debug_descriptor"; | |
120 | 207 | } |
121 | 208 | |
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; | |
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; | |
126 | 215 | } |
127 | 216 | |
128 | - *start = code.symfile_addr; | |
129 | - *size = code.symfile_size; | |
130 | - return code.next; | |
131 | -} | |
217 | + if (descriptor_addr_ == 0) { | |
218 | + return nullptr; | |
219 | + } | |
132 | 220 | |
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; | |
221 | + if (!Update(maps)) { | |
222 | + return nullptr; | |
137 | 223 | } |
138 | 224 | |
139 | - *start = code.symfile_addr; | |
140 | - *size = code.symfile_size; | |
141 | - return code.next; | |
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. | |
142 | 240 | } |
143 | 241 | |
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; | |
150 | - | |
151 | - case ARCH_ARM: | |
152 | - case ARCH_MIPS: | |
153 | - read_descriptor_func_ = &JitDebug::ReadDescriptor32; | |
154 | - read_entry_func_ = &JitDebug::ReadEntry32Pad; | |
155 | - break; | |
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 | + } | |
156 | 252 | |
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(); | |
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; | |
165 | 274 | } |
275 | + return false; // Too many retries. | |
166 | 276 | } |
167 | 277 | |
168 | -bool JitDebug::ReadVariableData(uint64_t ptr) { | |
169 | - entry_addr_ = (this->*read_descriptor_func_)(ptr); | |
170 | - return entry_addr_ != 0; | |
171 | -} | |
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; | |
172 | 282 | |
173 | -void JitDebug::Init(Maps* maps) { | |
174 | - if (initialized_) { | |
175 | - return; | |
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; | |
176 | 287 | } |
177 | - // Regardless of what happens below, consider the init finished. | |
178 | - initialized_ = true; | |
179 | 288 | |
180 | - FindAndReadVariable(maps, "__jit_debug_descriptor"); | |
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 | + } | |
296 | + | |
297 | + // Read the entry (while checking for data races). | |
298 | + if (!memory->ReadFully(entry_addr, &entry, sizeof(entry))) { | |
299 | + return false; | |
300 | + } | |
301 | + | |
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 | + } | |
307 | + } | |
308 | + | |
309 | + return true; | |
181 | 310 | } |
182 | 311 | |
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); | |
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; | |
189 | 320 | } |
190 | 321 | |
191 | - // Search the existing elf object first. | |
192 | - for (Elf* elf : elf_list_) { | |
193 | - if (elf->IsValidPc(pc)) { | |
194 | - return elf; | |
195 | - } | |
322 | + // Load and validate the ELF file. | |
323 | + symfile_.reset(new Elf(buffer.release())); | |
324 | + symfile_->Init(); | |
325 | + if (!symfile_->valid()) { | |
326 | + return false; | |
196 | 327 | } |
197 | 328 | |
198 | - while (entry_addr_ != 0) { | |
199 | - uint64_t start; | |
200 | - uint64_t size; | |
201 | - entry_addr_ = (this->*read_entry_func_)(&start, &size); | |
329 | + symfile_->GetTextRange(&addr_, &size_); | |
330 | + return true; | |
331 | +} | |
202 | 332 | |
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); | |
333 | +template std::unique_ptr<JitDebug<Elf>> JitDebug<Elf>::Create(ArchEnum, std::shared_ptr<Memory>&, | |
334 | + std::vector<std::string>); | |
213 | 335 | |
214 | - if (elf->IsValidPc(pc)) { | |
215 | - return elf; | |
216 | - } | |
336 | +#if !defined(NO_LIBDEXFILE_SUPPORT) | |
337 | + | |
338 | +template <> | |
339 | +const char* GetDescriptorName<DexFile>() { | |
340 | + return "__dex_debug_descriptor"; | |
341 | +} | |
342 | + | |
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; | |
217 | 353 | } |
218 | - return nullptr; | |
354 | + return true; | |
219 | 355 | } |
220 | 356 | |
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 | + | |
221 | 363 | } // namespace unwindstack |
@@ -36,11 +36,38 @@ | ||
36 | 36 | #include <unwindstack/Unwinder.h> |
37 | 37 | |
38 | 38 | #if !defined(NO_LIBDEXFILE_SUPPORT) |
39 | -#include <unwindstack/DexFiles.h> | |
39 | +#include <DexFile.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 | + | |
44 | 71 | // Inject extra 'virtual' frame that represents the dex pc data. |
45 | 72 | // The dex pc is a magic register defined in the Mterp interpreter, |
46 | 73 | // and thus it will be restored/observed in the frame after it. |
@@ -84,8 +111,7 @@ void Unwinder::FillInDexFrame() { | ||
84 | 111 | return; |
85 | 112 | } |
86 | 113 | |
87 | - dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name, | |
88 | - &frame->function_offset); | |
114 | + dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset); | |
89 | 115 | #endif |
90 | 116 | } |
91 | 117 |
@@ -185,7 +211,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip, | ||
185 | 211 | // using the jit debug information. |
186 | 212 | if (!elf->valid() && jit_debug_ != nullptr) { |
187 | 213 | uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment; |
188 | - Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc); | |
214 | + Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc); | |
189 | 215 | if (jit_elf != nullptr) { |
190 | 216 | // The jit debug information requires a non relative adjusted pc. |
191 | 217 | step_pc = adjusted_jit_pc; |
@@ -330,19 +356,7 @@ std::string Unwinder::FormatFrame(size_t frame_num) { | ||
330 | 356 | return FormatFrame(frames_[frame_num]); |
331 | 357 | } |
332 | 358 | |
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) { | |
359 | +bool UnwinderFromPid::Init() { | |
346 | 360 | if (pid_ == getpid()) { |
347 | 361 | maps_ptr_.reset(new LocalMaps()); |
348 | 362 | } else { |
@@ -355,15 +369,6 @@ bool UnwinderFromPid::Init(ArchEnum arch) { | ||
355 | 369 | |
356 | 370 | process_memory_ = Memory::CreateProcessMemoryCached(pid_); |
357 | 371 | |
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 | - | |
367 | 372 | return true; |
368 | 373 | } |
369 | 374 |
@@ -1,79 +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 _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,6 +78,8 @@ class Elf { | ||
78 | 78 | |
79 | 79 | bool IsValidPc(uint64_t pc); |
80 | 80 | |
81 | + bool GetTextRange(uint64_t* addr, uint64_t* size); | |
82 | + | |
81 | 83 | void GetLastError(ErrorData* data); |
82 | 84 | ErrorCode GetLastErrorCode(); |
83 | 85 | uint64_t GetLastErrorAddress(); |
@@ -68,6 +68,8 @@ class ElfInterface { | ||
68 | 68 | |
69 | 69 | virtual bool IsValidPc(uint64_t pc); |
70 | 70 | |
71 | + bool GetTextRange(uint64_t* addr, uint64_t* size); | |
72 | + | |
71 | 73 | Memory* CreateGnuDebugdataMemory(); |
72 | 74 | |
73 | 75 | Memory* memory() { return memory_; } |
@@ -156,6 +158,9 @@ class ElfInterface { | ||
156 | 158 | uint64_t gnu_build_id_offset_ = 0; |
157 | 159 | uint64_t gnu_build_id_size_ = 0; |
158 | 160 | |
161 | + uint64_t text_addr_ = 0; | |
162 | + uint64_t text_size_ = 0; | |
163 | + | |
159 | 164 | uint8_t soname_type_ = SONAME_UNKNOWN; |
160 | 165 | std::string soname_; |
161 | 166 |
@@ -19,6 +19,7 @@ | ||
19 | 19 | |
20 | 20 | #include <stdint.h> |
21 | 21 | |
22 | +#include <map> | |
22 | 23 | #include <memory> |
23 | 24 | #include <mutex> |
24 | 25 | #include <string> |
@@ -30,40 +31,24 @@ | ||
30 | 31 | namespace unwindstack { |
31 | 32 | |
32 | 33 | // Forward declarations. |
33 | -class Elf; | |
34 | 34 | class Maps; |
35 | 35 | enum ArchEnum : uint8_t; |
36 | 36 | |
37 | -class JitDebug : public Global { | |
37 | +template <typename Symfile> | |
38 | +class JitDebug { | |
38 | 39 | public: |
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_; | |
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 | + } | |
67 | 52 | }; |
68 | 53 | |
69 | 54 | } // namespace unwindstack |
@@ -24,7 +24,6 @@ | ||
24 | 24 | #include <string> |
25 | 25 | #include <vector> |
26 | 26 | |
27 | -#include <unwindstack/DexFiles.h> | |
28 | 27 | #include <unwindstack/Error.h> |
29 | 28 | #include <unwindstack/JitDebug.h> |
30 | 29 | #include <unwindstack/Maps.h> |
@@ -34,6 +33,7 @@ | ||
34 | 33 | namespace unwindstack { |
35 | 34 | |
36 | 35 | // 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) | |
67 | - : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) { | |
68 | - frames_.reserve(max_frames); | |
69 | - } | |
66 | + Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory); | |
70 | 67 | Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory) |
71 | - : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) { | |
72 | - frames_.reserve(max_frames); | |
73 | - } | |
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; | |
74 | 74 | |
75 | 75 | virtual ~Unwinder() = default; |
76 | 76 |
@@ -90,9 +90,7 @@ class Unwinder { | ||
90 | 90 | std::string FormatFrame(size_t frame_num); |
91 | 91 | std::string FormatFrame(const FrameData& frame); |
92 | 92 | |
93 | - void SetJitDebug(JitDebug* jit_debug, ArchEnum arch); | |
94 | - | |
95 | - void SetRegs(Regs* regs) { regs_ = regs; } | |
93 | + void SetRegs(Regs* regs); | |
96 | 94 | Maps* GetMaps() { return maps_; } |
97 | 95 | std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; } |
98 | 96 |
@@ -107,10 +105,6 @@ class Unwinder { | ||
107 | 105 | |
108 | 106 | void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; } |
109 | 107 | |
110 | -#if !defined(NO_LIBDEXFILE_SUPPORT) | |
111 | - void SetDexFiles(DexFiles* dex_files, ArchEnum arch); | |
112 | -#endif | |
113 | - | |
114 | 108 | ErrorCode LastErrorCode() { return last_error_.code; } |
115 | 109 | uint64_t LastErrorAddress() { return last_error_.address; } |
116 | 110 |
@@ -126,9 +120,9 @@ class Unwinder { | ||
126 | 120 | Regs* regs_; |
127 | 121 | std::vector<FrameData> frames_; |
128 | 122 | std::shared_ptr<Memory> process_memory_; |
129 | - JitDebug* jit_debug_ = nullptr; | |
123 | + std::unique_ptr<JitDebug<Elf>> jit_debug_; | |
130 | 124 | #if !defined(NO_LIBDEXFILE_SUPPORT) |
131 | - DexFiles* dex_files_ = nullptr; | |
125 | + std::unique_ptr<JitDebug<DexFile>> dex_files_; | |
132 | 126 | #endif |
133 | 127 | bool resolve_names_ = true; |
134 | 128 | bool embedded_soname_ = true; |
@@ -141,15 +135,11 @@ class UnwinderFromPid : public Unwinder { | ||
141 | 135 | UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {} |
142 | 136 | virtual ~UnwinderFromPid() = default; |
143 | 137 | |
144 | - bool Init(ArchEnum arch); | |
138 | + bool Init(); | |
145 | 139 | |
146 | 140 | private: |
147 | 141 | pid_t pid_; |
148 | 142 | 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 | |
153 | 143 | }; |
154 | 144 | |
155 | 145 | } // 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->GetMethodInformation(0x102, &method, &method_offset)); | |
180 | + ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset)); | |
181 | 181 | EXPECT_EQ("Main.<init>", method); |
182 | 182 | EXPECT_EQ(2U, method_offset); |
183 | 183 | |
184 | - ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset)); | |
184 | + ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &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->GetMethodInformation(0x100000, &method, &method_offset)); | |
198 | + EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset)); | |
199 | 199 | |
200 | - EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset)); | |
200 | + EXPECT_FALSE(dex_file->GetFunctionName(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> | |
26 | 25 | #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,6 +32,10 @@ | ||
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 | + | |
35 | 39 | namespace unwindstack { |
36 | 40 | |
37 | 41 | class DexFilesTest : public ::testing::Test { |
@@ -48,8 +52,7 @@ class DexFilesTest : public ::testing::Test { | ||
48 | 52 | } |
49 | 53 | |
50 | 54 | void Init(ArchEnum arch) { |
51 | - dex_files_.reset(new DexFiles(process_memory_)); | |
52 | - dex_files_->SetArch(arch); | |
55 | + dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_); | |
53 | 56 | |
54 | 57 | maps_.reset( |
55 | 58 | new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n" |
@@ -86,10 +89,11 @@ class DexFilesTest : public ::testing::Test { | ||
86 | 89 | Init(ARCH_ARM); |
87 | 90 | } |
88 | 91 | |
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); | |
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); | |
93 | 97 | void WriteDex(uint64_t dex_file); |
94 | 98 | |
95 | 99 | static constexpr size_t kMapGlobalNonReadable = 2; |
@@ -101,40 +105,70 @@ class DexFilesTest : public ::testing::Test { | ||
101 | 105 | |
102 | 106 | std::shared_ptr<Memory> process_memory_; |
103 | 107 | MemoryFake* memory_; |
104 | - std::unique_ptr<DexFiles> dex_files_; | |
108 | + std::unique_ptr<JitDebug<DexFile>> dex_files_; | |
105 | 109 | std::unique_ptr<BufferMaps> maps_; |
106 | 110 | }; |
107 | 111 | |
108 | -void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) { | |
109 | - // void* first_entry_ | |
110 | - memory_->SetData32(addr + 12, head); | |
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); | |
111 | 134 | } |
112 | 135 | |
113 | -void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) { | |
114 | - // void* first_entry_ | |
115 | - memory_->SetData64(addr + 16, head); | |
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)); | |
116 | 146 | } |
117 | 147 | |
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: | |
148 | +void DexFilesTest::WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) { | |
149 | + // Format of the 32 bit JITCodeEntry structure: | |
121 | 150 | // uint32_t next |
122 | - memory_->SetData32(entry_addr, next); | |
151 | + memory_->SetData32(addr, next); | |
123 | 152 | // uint32_t prev |
124 | - memory_->SetData32(entry_addr + 4, prev); | |
125 | - // uint32_t dex_file | |
126 | - memory_->SetData32(entry_addr + 8, dex_file); | |
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)); | |
127 | 160 | } |
128 | 161 | |
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: | |
162 | +void DexFilesTest::WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex) { | |
163 | + // Format of the 64 bit JITCodeEntry structure: | |
132 | 164 | // uint64_t next |
133 | - memory_->SetData64(entry_addr, next); | |
165 | + memory_->SetData64(addr, next); | |
134 | 166 | // uint64_t prev |
135 | - memory_->SetData64(entry_addr + 8, prev); | |
136 | - // uint64_t dex_file | |
137 | - memory_->SetData64(entry_addr + 16, dex_file); | |
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)); | |
138 | 172 | } |
139 | 173 | |
140 | 174 | void DexFilesTest::WriteDex(uint64_t dex_file) { |
@@ -144,9 +178,8 @@ void DexFilesTest::WriteDex(uint64_t dex_file) { | ||
144 | 178 | TEST_F(DexFilesTest, get_method_information_invalid) { |
145 | 179 | std::string method_name = "nothing"; |
146 | 180 | uint64_t method_offset = 0x124; |
147 | - MapInfo* info = maps_->Get(kMapDexFileEntries); | |
148 | 181 | |
149 | - dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset); | |
182 | + dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset); | |
150 | 183 | EXPECT_EQ("nothing", method_name); |
151 | 184 | EXPECT_EQ(0x124U, method_offset); |
152 | 185 | } |
@@ -154,13 +187,12 @@ TEST_F(DexFilesTest, get_method_information_invalid) { | ||
154 | 187 | TEST_F(DexFilesTest, get_method_information_32) { |
155 | 188 | std::string method_name = "nothing"; |
156 | 189 | uint64_t method_offset = 0x124; |
157 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
158 | 190 | |
159 | 191 | WriteDescriptor32(0xf800, 0x200000); |
160 | - WriteEntry32(0x200000, 0, 0, 0x300000); | |
192 | + WriteEntry32Pad(0x200000, 0, 0, 0x300000); | |
161 | 193 | WriteDex(0x300000); |
162 | 194 | |
163 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
195 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
164 | 196 | EXPECT_EQ("Main.<init>", method_name); |
165 | 197 | EXPECT_EQ(0U, method_offset); |
166 | 198 | } |
@@ -170,13 +202,12 @@ TEST_F(DexFilesTest, get_method_information_64) { | ||
170 | 202 | |
171 | 203 | std::string method_name = "nothing"; |
172 | 204 | uint64_t method_offset = 0x124; |
173 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
174 | 205 | |
175 | 206 | WriteDescriptor64(0xf800, 0x200000); |
176 | 207 | WriteEntry64(0x200000, 0, 0, 0x301000); |
177 | 208 | WriteDex(0x301000); |
178 | 209 | |
179 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset); | |
210 | + dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset); | |
180 | 211 | EXPECT_EQ("Main.<init>", method_name); |
181 | 212 | EXPECT_EQ(2U, method_offset); |
182 | 213 | } |
@@ -184,14 +215,14 @@ TEST_F(DexFilesTest, get_method_information_64) { | ||
184 | 215 | TEST_F(DexFilesTest, get_method_information_not_first_entry_32) { |
185 | 216 | std::string method_name = "nothing"; |
186 | 217 | uint64_t method_offset = 0x124; |
187 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
188 | 218 | |
189 | 219 | WriteDescriptor32(0xf800, 0x200000); |
190 | - WriteEntry32(0x200000, 0x200100, 0, 0x100000); | |
191 | - WriteEntry32(0x200100, 0, 0x200000, 0x300000); | |
220 | + WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000); | |
221 | + WriteDex(0x100000); | |
222 | + WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000); | |
192 | 223 | WriteDex(0x300000); |
193 | 224 | |
194 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); | |
225 | + dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); | |
195 | 226 | EXPECT_EQ("Main.<init>", method_name); |
196 | 227 | EXPECT_EQ(4U, method_offset); |
197 | 228 | } |
@@ -201,14 +232,14 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { | ||
201 | 232 | |
202 | 233 | std::string method_name = "nothing"; |
203 | 234 | uint64_t method_offset = 0x124; |
204 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
205 | 235 | |
206 | 236 | WriteDescriptor64(0xf800, 0x200000); |
207 | 237 | WriteEntry64(0x200000, 0x200100, 0, 0x100000); |
238 | + WriteDex(0x100000); | |
208 | 239 | WriteEntry64(0x200100, 0, 0x200000, 0x300000); |
209 | 240 | WriteDex(0x300000); |
210 | 241 | |
211 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset); | |
242 | + dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset); | |
212 | 243 | EXPECT_EQ("Main.<init>", method_name); |
213 | 244 | EXPECT_EQ(6U, method_offset); |
214 | 245 | } |
@@ -216,19 +247,18 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { | ||
216 | 247 | TEST_F(DexFilesTest, get_method_information_cached) { |
217 | 248 | std::string method_name = "nothing"; |
218 | 249 | uint64_t method_offset = 0x124; |
219 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
220 | 250 | |
221 | 251 | WriteDescriptor32(0xf800, 0x200000); |
222 | - WriteEntry32(0x200000, 0, 0, 0x300000); | |
252 | + WriteEntry32Pad(0x200000, 0, 0, 0x300000); | |
223 | 253 | WriteDex(0x300000); |
224 | 254 | |
225 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
255 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
226 | 256 | EXPECT_EQ("Main.<init>", method_name); |
227 | 257 | EXPECT_EQ(0U, method_offset); |
228 | 258 | |
229 | 259 | // Clear all memory and make sure that data is acquired from the cache. |
230 | 260 | memory_->Clear(); |
231 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
261 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
232 | 262 | EXPECT_EQ("Main.<init>", method_name); |
233 | 263 | EXPECT_EQ(0U, method_offset); |
234 | 264 | } |
@@ -236,26 +266,24 @@ TEST_F(DexFilesTest, get_method_information_cached) { | ||
236 | 266 | TEST_F(DexFilesTest, get_method_information_search_libs) { |
237 | 267 | std::string method_name = "nothing"; |
238 | 268 | uint64_t method_offset = 0x124; |
239 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
240 | 269 | |
241 | 270 | WriteDescriptor32(0xf800, 0x200000); |
242 | - WriteEntry32(0x200000, 0x200100, 0, 0x100000); | |
243 | - WriteEntry32(0x200100, 0, 0x200000, 0x300000); | |
271 | + WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000); | |
272 | + WriteDex(0x100000); | |
273 | + WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000); | |
244 | 274 | WriteDex(0x300000); |
245 | 275 | |
246 | 276 | // Only search a given named list of libs. |
247 | 277 | std::vector<std::string> libs{"libart.so"}; |
248 | - dex_files_.reset(new DexFiles(process_memory_, libs)); | |
249 | - dex_files_->SetArch(ARCH_ARM); | |
278 | + dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs); | |
250 | 279 | |
251 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); | |
280 | + dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); | |
252 | 281 | EXPECT_EQ("nothing", method_name); |
253 | 282 | EXPECT_EQ(0x124U, method_offset); |
254 | 283 | |
255 | 284 | MapInfo* map_info = maps_->Get(kMapGlobal); |
256 | 285 | map_info->name = "/system/lib/libart.so"; |
257 | - dex_files_.reset(new DexFiles(process_memory_, libs)); | |
258 | - dex_files_->SetArch(ARCH_ARM); | |
286 | + dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs); | |
259 | 287 | // Set the rw map to the same name or this will not scan this entry. |
260 | 288 | map_info = maps_->Get(kMapGlobalRw); |
261 | 289 | map_info->name = "/system/lib/libart.so"; |
@@ -263,7 +291,7 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { | ||
263 | 291 | // DexFiles object. |
264 | 292 | libs.clear(); |
265 | 293 | |
266 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); | |
294 | + dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); | |
267 | 295 | EXPECT_EQ("Main.<init>", method_name); |
268 | 296 | EXPECT_EQ(4U, method_offset); |
269 | 297 | } |
@@ -271,26 +299,24 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { | ||
271 | 299 | TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) { |
272 | 300 | std::string method_name = "nothing"; |
273 | 301 | uint64_t method_offset = 0x124; |
274 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
275 | 302 | |
276 | 303 | // First global variable found, but value is zero. |
277 | 304 | WriteDescriptor32(0xa800, 0); |
278 | 305 | |
279 | 306 | WriteDescriptor32(0xf800, 0x200000); |
280 | - WriteEntry32(0x200000, 0, 0, 0x300000); | |
307 | + WriteEntry32Pad(0x200000, 0, 0, 0x300000); | |
281 | 308 | WriteDex(0x300000); |
282 | 309 | |
283 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
310 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
284 | 311 | EXPECT_EQ("Main.<init>", method_name); |
285 | 312 | EXPECT_EQ(0U, method_offset); |
286 | 313 | |
287 | 314 | // Verify that second is ignored when first is set to non-zero |
288 | - dex_files_.reset(new DexFiles(process_memory_)); | |
289 | - dex_files_->SetArch(ARCH_ARM); | |
315 | + dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_); | |
290 | 316 | method_name = "fail"; |
291 | 317 | method_offset = 0x123; |
292 | 318 | WriteDescriptor32(0xa800, 0x100000); |
293 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
319 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
294 | 320 | EXPECT_EQ("fail", method_name); |
295 | 321 | EXPECT_EQ(0x123U, method_offset); |
296 | 322 | } |
@@ -300,7 +326,6 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { | ||
300 | 326 | |
301 | 327 | std::string method_name = "nothing"; |
302 | 328 | uint64_t method_offset = 0x124; |
303 | - MapInfo* info = maps_->Get(kMapDexFiles); | |
304 | 329 | |
305 | 330 | // First global variable found, but value is zero. |
306 | 331 | WriteDescriptor64(0xa800, 0); |
@@ -309,17 +334,16 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { | ||
309 | 334 | WriteEntry64(0x200000, 0, 0, 0x300000); |
310 | 335 | WriteDex(0x300000); |
311 | 336 | |
312 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
337 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
313 | 338 | EXPECT_EQ("Main.<init>", method_name); |
314 | 339 | EXPECT_EQ(0U, method_offset); |
315 | 340 | |
316 | 341 | // Verify that second is ignored when first is set to non-zero |
317 | - dex_files_.reset(new DexFiles(process_memory_)); | |
318 | - dex_files_->SetArch(ARCH_ARM64); | |
342 | + dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM64, process_memory_); | |
319 | 343 | method_name = "fail"; |
320 | 344 | method_offset = 0x123; |
321 | 345 | WriteDescriptor64(0xa800, 0x100000); |
322 | - dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); | |
346 | + dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); | |
323 | 347 | EXPECT_EQ("fail", method_name); |
324 | 348 | EXPECT_EQ(0x123U, method_offset); |
325 | 349 | } |
@@ -46,8 +46,7 @@ class JitDebugTest : public ::testing::Test { | ||
46 | 46 | } |
47 | 47 | |
48 | 48 | void Init(ArchEnum arch) { |
49 | - jit_debug_.reset(new JitDebug(process_memory_)); | |
50 | - jit_debug_->SetArch(arch); | |
49 | + jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_); | |
51 | 50 | |
52 | 51 | maps_.reset( |
53 | 52 | new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n" |
@@ -62,6 +61,12 @@ class JitDebugTest : public ::testing::Test { | ||
62 | 61 | "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n")); |
63 | 62 | ASSERT_TRUE(maps_->Parse()); |
64 | 63 | |
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 | + | |
65 | 70 | MapInfo* map_info = maps_->Get(3); |
66 | 71 | ASSERT_TRUE(map_info != nullptr); |
67 | 72 | CreateFakeElf(map_info); |
@@ -94,7 +99,7 @@ class JitDebugTest : public ::testing::Test { | ||
94 | 99 | ehdr.e_shstrndx = 1; |
95 | 100 | ehdr.e_shoff = sh_offset; |
96 | 101 | ehdr.e_shentsize = sizeof(ShdrType); |
97 | - ehdr.e_shnum = 3; | |
102 | + ehdr.e_shnum = 4; | |
98 | 103 | memory_->SetMemory(offset, &ehdr, sizeof(ehdr)); |
99 | 104 | |
100 | 105 | ShdrType shdr; |
@@ -110,6 +115,7 @@ class JitDebugTest : public ::testing::Test { | ||
110 | 115 | shdr.sh_size = 0x100; |
111 | 116 | memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); |
112 | 117 | memory_->SetMemory(offset + 0x500, ".debug_frame"); |
118 | + memory_->SetMemory(offset + 0x550, ".text"); | |
113 | 119 | |
114 | 120 | sh_offset += sizeof(shdr); |
115 | 121 | memset(&shdr, 0, sizeof(shdr)); |
@@ -120,6 +126,15 @@ class JitDebugTest : public ::testing::Test { | ||
120 | 126 | shdr.sh_size = 0x200; |
121 | 127 | memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); |
122 | 128 | |
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 | + | |
123 | 138 | // Now add a single cie/fde. |
124 | 139 | uint64_t dwarf_offset = offset + 0x600; |
125 | 140 | if (class_type == ELFCLASS32) { |
@@ -168,7 +183,7 @@ class JitDebugTest : public ::testing::Test { | ||
168 | 183 | |
169 | 184 | std::shared_ptr<Memory> process_memory_; |
170 | 185 | MemoryFake* memory_; |
171 | - std::unique_ptr<JitDebug> jit_debug_; | |
186 | + std::unique_ptr<JitDebug<Elf>> jit_debug_; | |
172 | 187 | std::unique_ptr<BufferMaps> maps_; |
173 | 188 | }; |
174 | 189 |
@@ -238,20 +253,20 @@ void JitDebugTest::WriteEntry64(uint64_t addr, uint64_t prev, uint64_t next, uin | ||
238 | 253 | } |
239 | 254 | |
240 | 255 | TEST_F(JitDebugTest, get_elf_invalid) { |
241 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
256 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
242 | 257 | ASSERT_TRUE(elf == nullptr); |
243 | 258 | } |
244 | 259 | |
245 | 260 | TEST_F(JitDebugTest, get_elf_no_global_variable) { |
246 | 261 | maps_.reset(new BufferMaps("")); |
247 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
262 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
248 | 263 | ASSERT_TRUE(elf == nullptr); |
249 | 264 | } |
250 | 265 | |
251 | 266 | TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) { |
252 | 267 | CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); |
253 | 268 | |
254 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
269 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
255 | 270 | ASSERT_TRUE(elf == nullptr); |
256 | 271 | } |
257 | 272 |
@@ -260,7 +275,7 @@ TEST_F(JitDebugTest, get_elf_no_valid_code_entry) { | ||
260 | 275 | |
261 | 276 | WriteDescriptor32(0xf800, 0x200000); |
262 | 277 | |
263 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
278 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
264 | 279 | ASSERT_TRUE(elf == nullptr); |
265 | 280 | } |
266 | 281 |
@@ -269,7 +284,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_first_entry) { | ||
269 | 284 | |
270 | 285 | WriteDescriptor32(0xf800, 0); |
271 | 286 | |
272 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
287 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
273 | 288 | ASSERT_TRUE(elf == nullptr); |
274 | 289 | } |
275 | 290 |
@@ -280,7 +295,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_version) { | ||
280 | 295 | // Set the version to an invalid value. |
281 | 296 | memory_->SetData32(0xf800, 2); |
282 | 297 | |
283 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
298 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
284 | 299 | ASSERT_TRUE(elf == nullptr); |
285 | 300 | } |
286 | 301 |
@@ -290,12 +305,18 @@ TEST_F(JitDebugTest, get_elf_32) { | ||
290 | 305 | WriteDescriptor32(0xf800, 0x200000); |
291 | 306 | WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000); |
292 | 307 | |
293 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
308 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
294 | 309 | 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); | |
295 | 315 | |
296 | 316 | // Clear the memory and verify all of the data is cached. |
297 | 317 | memory_->Clear(); |
298 | - Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); | |
318 | + WriteDescriptor32(0xf800, 0x200000); | |
319 | + Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); | |
299 | 320 | ASSERT_TRUE(elf2 != nullptr); |
300 | 321 | EXPECT_EQ(elf, elf2); |
301 | 322 | } |
@@ -309,16 +330,15 @@ TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) { | ||
309 | 330 | WriteDescriptor32(0x12800, 0x201000); |
310 | 331 | WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000); |
311 | 332 | |
312 | - ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); | |
313 | - ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr); | |
333 | + ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr); | |
334 | + ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr); | |
314 | 335 | |
315 | 336 | // Now clear the descriptor entry for the first one. |
316 | 337 | WriteDescriptor32(0xf800, 0); |
317 | - jit_debug_.reset(new JitDebug(process_memory_)); | |
318 | - jit_debug_->SetArch(ARCH_ARM); | |
338 | + jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_); | |
319 | 339 | |
320 | - ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr); | |
321 | - ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr); | |
340 | + ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr); | |
341 | + ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr); | |
322 | 342 | } |
323 | 343 | |
324 | 344 | TEST_F(JitDebugTest, get_elf_x86) { |
@@ -329,13 +349,14 @@ TEST_F(JitDebugTest, get_elf_x86) { | ||
329 | 349 | WriteDescriptor32(0xf800, 0x200000); |
330 | 350 | WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000); |
331 | 351 | |
332 | - jit_debug_->SetArch(ARCH_X86); | |
333 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
352 | + jit_debug_ = JitDebug<Elf>::Create(ARCH_X86, process_memory_); | |
353 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
334 | 354 | ASSERT_TRUE(elf != nullptr); |
335 | 355 | |
336 | 356 | // Clear the memory and verify all of the data is cached. |
337 | 357 | memory_->Clear(); |
338 | - Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); | |
358 | + WriteDescriptor32(0xf800, 0x200000); | |
359 | + Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); | |
339 | 360 | ASSERT_TRUE(elf2 != nullptr); |
340 | 361 | EXPECT_EQ(elf, elf2); |
341 | 362 | } |
@@ -348,12 +369,13 @@ TEST_F(JitDebugTest, get_elf_64) { | ||
348 | 369 | WriteDescriptor64(0xf800, 0x200000); |
349 | 370 | WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000); |
350 | 371 | |
351 | - Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); | |
372 | + Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); | |
352 | 373 | ASSERT_TRUE(elf != nullptr); |
353 | 374 | |
354 | 375 | // Clear the memory and verify all of the data is cached. |
355 | 376 | memory_->Clear(); |
356 | - Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); | |
377 | + WriteDescriptor64(0xf800, 0x200000); | |
378 | + Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); | |
357 | 379 | ASSERT_TRUE(elf2 != nullptr); |
358 | 380 | EXPECT_EQ(elf, elf2); |
359 | 381 | } |
@@ -366,20 +388,21 @@ TEST_F(JitDebugTest, get_elf_multiple_entries) { | ||
366 | 388 | WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000); |
367 | 389 | WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000); |
368 | 390 | |
369 | - Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400); | |
391 | + Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400); | |
370 | 392 | ASSERT_TRUE(elf_2 != nullptr); |
371 | 393 | |
372 | - Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600); | |
394 | + Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600); | |
373 | 395 | ASSERT_TRUE(elf_1 != nullptr); |
374 | 396 | |
375 | 397 | // Clear the memory and verify all of the data is cached. |
376 | 398 | memory_->Clear(); |
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)); | |
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)); | |
383 | 406 | } |
384 | 407 | |
385 | 408 | TEST_F(JitDebugTest, get_elf_search_libs) { |
@@ -390,21 +413,19 @@ TEST_F(JitDebugTest, get_elf_search_libs) { | ||
390 | 413 | |
391 | 414 | // Only search a given named list of libs. |
392 | 415 | std::vector<std::string> libs{"libart.so"}; |
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); | |
416 | + jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_, libs); | |
417 | + EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr); | |
396 | 418 | |
397 | 419 | // Change the name of the map that includes the value and verify this works. |
398 | 420 | MapInfo* map_info = maps_->Get(5); |
399 | 421 | map_info->name = "/system/lib/libart.so"; |
400 | 422 | map_info = maps_->Get(6); |
401 | 423 | map_info->name = "/system/lib/libart.so"; |
402 | - jit_debug_.reset(new JitDebug(process_memory_, libs)); | |
424 | + jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_); | |
403 | 425 | // Make sure that clearing our copy of the libs doesn't affect the |
404 | 426 | // JitDebug object. |
405 | 427 | libs.clear(); |
406 | - jit_debug_->SetArch(ARCH_ARM); | |
407 | - EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); | |
428 | + EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr); | |
408 | 429 | } |
409 | 430 | |
410 | 431 | } // namespace unwindstack |
@@ -290,9 +290,7 @@ TEST_F(UnwindOfflineTest, jit_debug_x86) { | ||
290 | 290 | } |
291 | 291 | process_memory_.reset(memory); |
292 | 292 | |
293 | - JitDebug jit_debug(process_memory_); | |
294 | 293 | Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); |
295 | - unwinder.SetJitDebug(&jit_debug, regs_->Arch()); | |
296 | 294 | unwinder.Unwind(); |
297 | 295 | |
298 | 296 | std::string frame_info(DumpFrames(unwinder)); |
@@ -592,9 +590,7 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { | ||
592 | 590 | } |
593 | 591 | process_memory_.reset(memory); |
594 | 592 | |
595 | - JitDebug jit_debug(process_memory_); | |
596 | 593 | Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); |
597 | - unwinder.SetJitDebug(&jit_debug, regs_->Arch()); | |
598 | 594 | unwinder.Unwind(); |
599 | 595 | |
600 | 596 | std::string frame_info(DumpFrames(unwinder)); |
@@ -915,9 +911,7 @@ static void OfflineUnwind(void* data) { | ||
915 | 911 | LeakType* leak_data = reinterpret_cast<LeakType*>(data); |
916 | 912 | |
917 | 913 | std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone()); |
918 | - JitDebug jit_debug(leak_data->process_memory); | |
919 | 914 | Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory); |
920 | - unwinder.SetJitDebug(&jit_debug, regs_copy->Arch()); | |
921 | 915 | unwinder.Unwind(); |
922 | 916 | ASSERT_EQ(76U, unwinder.NumFrames()); |
923 | 917 | } |
@@ -1038,9 +1032,7 @@ TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) { | ||
1038 | 1032 | } |
1039 | 1033 | process_memory_.reset(memory); |
1040 | 1034 | |
1041 | - JitDebug jit_debug(process_memory_); | |
1042 | 1035 | Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); |
1043 | - unwinder.SetJitDebug(&jit_debug, regs_->Arch()); | |
1044 | 1036 | unwinder.Unwind(); |
1045 | 1037 | |
1046 | 1038 | 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(regs->Arch())); | |
173 | + ASSERT_TRUE(unwinder_from_pid->Init()); | |
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(regs->Arch())); | |
286 | + ASSERT_TRUE(unwinder.Init()); | |
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(regs->Arch())); | |
338 | + ASSERT_TRUE(unwinder.Init()); | |
339 | 339 | unwinder.SetRegs(regs.get()); |
340 | 340 | |
341 | 341 | VerifyUnwind(&unwinder, kFunctionOrder); |
@@ -26,7 +26,6 @@ | ||
26 | 26 | #include <sys/types.h> |
27 | 27 | #include <unistd.h> |
28 | 28 | |
29 | -#include <unwindstack/DexFiles.h> | |
30 | 29 | #include <unwindstack/Elf.h> |
31 | 30 | #include <unwindstack/JitDebug.h> |
32 | 31 | #include <unwindstack/Maps.h> |
@@ -90,7 +89,7 @@ void DoUnwind(pid_t pid) { | ||
90 | 89 | printf("\n"); |
91 | 90 | |
92 | 91 | unwindstack::UnwinderFromPid unwinder(1024, pid); |
93 | - if (!unwinder.Init(regs->Arch())) { | |
92 | + if (!unwinder.Init()) { | |
94 | 93 | printf("Failed to init unwinder object.\n"); |
95 | 94 | return; |
96 | 95 | } |
@@ -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(regs->Arch())) { | |
251 | + if (!unwinder.Init()) { | |
252 | 252 | printf("Unable to init unwinder object.\n"); |
253 | 253 | return 1; |
254 | 254 | } |