Move dex pc frame creation into libunwindstack.
Test: Compiles, all unit tests pass.
Test: Ran 137-cfi art test in interpreter and verified interpreter
Test: frames still show up.
Change-Id: Icea90194986faa733a873e8cf467fc2513eb5573
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 28d7e64..74dfaa5 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -80,7 +80,13 @@
host: {
cflags: ["-O0", "-g"],
},
+ vendor: {
+ cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+ exclude_static_libs: ["libunwindstack_dex"],
+ exclude_shared_libs: ["libdexfile"],
+ },
},
+ whole_static_libs: ["libunwindstack_dex"],
arch: {
x86: {
@@ -99,14 +105,70 @@
shared_libs: [
"libbase",
+ "libdexfile",
"liblog",
"liblzma",
],
}
+// Isolate the dex file processing into a separate library. Currently,
+// it is necessary to add art include directories directly, which also
+// adds the art elf.h file in the include path, overriding the system one.
+// Work to isolate libdexfile is b/72216369.
+cc_library_static {
+ name: "libunwindstack_dex",
+ vendor_available: false,
+ defaults: ["libunwindstack_flags"],
+
+ cflags: [
+ "-Wexit-time-destructors",
+ ],
+
+ srcs: [
+ "DexFile.cpp",
+ "DexFiles.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libdexfile",
+ ],
+ local_include_dirs: ["include"],
+ allow_undefined_symbols: true,
+
+ // libdexfile will eventually properly export headers, for now include
+ // these directly.
+ include_dirs: [
+ "art/runtime",
+ ],
+}
+
//-------------------------------------------------------------------------
// Unit Tests
//-------------------------------------------------------------------------
+cc_test_library {
+ name: "libunwindstack_dex_test",
+ vendor_available: false,
+ defaults: ["libunwindstack_flags"],
+
+ srcs: [
+ "tests/DexFileTest.cpp",
+ ],
+ local_include_dirs: ["include"],
+ allow_undefined_symbols: true,
+
+ shared_libs: [
+ "libbase",
+ "libunwindstack",
+ ],
+
+ // libdexfile will eventually properly export headers, for now include
+ // these directly.
+ include_dirs: [
+ "art/runtime",
+ ],
+}
+
cc_test {
name: "libunwindstack_test",
defaults: ["libunwindstack_flags"],
@@ -168,6 +230,8 @@
"libgmock",
],
+ whole_static_libs: ["libunwindstack_dex_test"],
+
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
new file mode 100644
index 0000000..be6c2f7
--- /dev/null
+++ b/libunwindstack/DexFile.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <android-base/unique_fd.h>
+
+#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/compact_dex_file.h>
+#include <dex/dex_file-inl.h>
+#include <dex/dex_file_loader.h>
+#include <dex/standard_dex_file.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
+ if (!info->name.empty()) {
+ std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
+ if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
+ return dex_file.release();
+ }
+ }
+
+ std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
+ if (dex_file->Open(dex_file_offset_in_memory, memory)) {
+ return dex_file.release();
+ }
+ return nullptr;
+}
+
+void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+ uint64_t* method_offset) {
+ if (dex_file_ == nullptr) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
+ const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i);
+ const uint8_t* class_data = dex_file_->GetClassData(class_def);
+ if (class_data == nullptr) {
+ continue;
+ }
+ for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) {
+ if (!it.IsAtMethod()) {
+ continue;
+ }
+ const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item == nullptr) {
+ continue;
+ }
+ art::CodeItemInstructionAccessor code(*dex_file_.get(), code_item);
+ if (!code.HasCodeItem()) {
+ continue;
+ }
+
+ uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+ size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
+ if (offset <= dex_offset && dex_offset < offset + size) {
+ *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
+ *method_offset = dex_offset - offset;
+ return;
+ }
+ }
+ }
+}
+
+DexFileFromFile::~DexFileFromFile() {
+ if (size_ != 0) {
+ munmap(mapped_memory_, size_);
+ }
+}
+
+bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ return false;
+ }
+ struct stat buf;
+ if (fstat(fd, &buf) == -1) {
+ return false;
+ }
+ uint64_t length;
+ if (buf.st_size < 0 ||
+ __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
+ static_cast<uint64_t>(buf.st_size) < length) {
+ return false;
+ }
+
+ mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (mapped_memory_ == MAP_FAILED) {
+ return false;
+ }
+ size_ = buf.st_size;
+
+ uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);
+
+ art::DexFile::Header* header =
+ reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
+ if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
+ !art::CompactDexFile::IsMagicValid(header->magic_)) {
+ return false;
+ }
+
+ if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
+ static_cast<uint64_t>(buf.st_size) < length) {
+ return false;
+ }
+
+ art::DexFileLoader loader;
+ std::string error_msg;
+ auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
+ false, false, &error_msg);
+ dex_file_.reset(dex.release());
+ return dex_file_ != nullptr;
+}
+
+bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
+ art::DexFile::Header header;
+ if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
+ return false;
+ }
+
+ if (!art::StandardDexFile::IsMagicValid(header.magic_) &&
+ !art::CompactDexFile::IsMagicValid(header.magic_)) {
+ return false;
+ }
+
+ memory_.resize(header.file_size_);
+ if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) {
+ return false;
+ }
+
+ art::DexFileLoader loader;
+ std::string error_msg;
+ auto dex =
+ loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg);
+ dex_file_.reset(dex.release());
+ return dex_file_ != nullptr;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
new file mode 100644
index 0000000..22e98df
--- /dev/null
+++ b/libunwindstack/DexFile.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_DEX_FILE_H
+#define _LIBUNWINDSTACK_DEX_FILE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dex/dex_file-inl.h>
+
+namespace unwindstack {
+
+class DexFile {
+ public:
+ DexFile() = default;
+ virtual ~DexFile() = default;
+
+ void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+
+ static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
+
+ protected:
+ std::unique_ptr<const art::DexFile> dex_file_;
+};
+
+class DexFileFromFile : public DexFile {
+ public:
+ DexFileFromFile() = default;
+ virtual ~DexFileFromFile();
+
+ bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+
+ private:
+ void* mapped_memory_ = nullptr;
+ size_t size_ = 0;
+};
+
+class DexFileFromMemory : public DexFile {
+ public:
+ DexFileFromMemory() = default;
+ virtual ~DexFileFromMemory() = default;
+
+ bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
+
+ private:
+ std::vector<uint8_t> memory_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..3d67a6a
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+
+DexFiles::~DexFiles() {
+ for (auto& entry : files_) {
+ delete entry.second;
+ }
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+ // Lock while processing the data.
+ std::lock_guard<std::mutex> guard(files_lock_);
+ DexFile* dex_file;
+ auto entry = files_.find(dex_file_offset);
+ if (entry == files_.end()) {
+ dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+ files_[dex_file_offset] = dex_file;
+ } else {
+ dex_file = entry->second;
+ }
+ return dex_file;
+}
+
+void DexFiles::GetMethodInformation(uint64_t dex_offset, MapInfo* info, std::string* method_name,
+ uint64_t* method_offset) {
+ DexFile* dex_file = GetDexFile(dex_offset, info);
+ if (dex_file != nullptr) {
+ dex_file->GetMethodInformation(dex_offset, method_name, method_offset);
+ }
+}
+
+void DexFiles::SetArch(ArchEnum) {}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f70ed7b..d22e1e8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -31,8 +31,74 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Unwinder.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
+
namespace unwindstack {
+// Inject extra 'virtual' frame that represents the dex pc data.
+// The dex pc is a magic register defined in the Mterp interpreter,
+// and thus it will be restored/observed in the frame after it.
+// Adding the dex frame first here will create something like:
+// #7 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
+// #8 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
+// #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
+void Unwinder::FillInDexFrame() {
+ size_t frame_num = frames_.size();
+ frames_.resize(frame_num + 1);
+ FrameData* frame = &frames_.at(frame_num);
+
+ uint64_t dex_pc = regs_->dex_pc();
+ frame->pc = dex_pc;
+ frame->sp = regs_->sp();
+
+ auto it = maps_->begin();
+ uint64_t rel_dex_pc;
+ MapInfo* info;
+ for (; it != maps_->end(); ++it) {
+ auto entry = *it;
+ if (dex_pc >= entry->start && dex_pc < entry->end) {
+ info = entry;
+ rel_dex_pc = dex_pc - entry->start;
+ frame->map_start = entry->start;
+ frame->map_end = entry->end;
+ frame->map_offset = entry->offset;
+ frame->map_load_bias = entry->load_bias;
+ frame->map_flags = entry->flags;
+ frame->map_name = entry->name;
+ frame->rel_pc = rel_dex_pc;
+ break;
+ }
+ }
+
+ if (it == maps_->end() || ++it == maps_->end()) {
+ return;
+ }
+
+ auto entry = *it;
+ unwindstack::Elf* elf = entry->GetElf(process_memory_, true);
+ if (!elf->valid()) {
+ return;
+ }
+
+ // Adjust the relative dex by the offset.
+ rel_dex_pc += entry->elf_offset;
+
+ uint64_t dex_offset;
+ if (!elf->GetFunctionName(rel_dex_pc, &frame->function_name, &dex_offset)) {
+ return;
+ }
+ frame->function_offset = dex_offset;
+ if (frame->function_name != "$dexfile") {
+ return;
+ }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ dex_files_->GetMethodInformation(dex_offset, info, &frame->function_name, &frame->function_offset);
+#endif
+}
+
void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
@@ -40,7 +106,6 @@
frame->num = frame_num;
frame->sp = regs_->sp();
frame->rel_pc = adjusted_rel_pc;
- frame->dex_pc = regs_->dex_pc();
if (map_info == nullptr) {
frame->pc = regs_->pc();
@@ -128,6 +193,11 @@
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
+ if (regs_->dex_pc() != 0) {
+ // Add a frame to represent the dex file.
+ FillInDexFrame();
+ }
+
FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
// Once a frame is added, stop skipping frames.
@@ -240,4 +310,11 @@
jit_debug_ = jit_debug;
}
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+ dex_files->SetArch(arch);
+ dex_files_ = dex_files;
+}
+#endif
+
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..d80e9b7
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+class Memory;
+enum ArchEnum : uint8_t;
+
+class DexFiles {
+ public:
+ explicit DexFiles(std::shared_ptr<Memory>& memory);
+ ~DexFiles();
+
+ DexFile* GetDexFile(uint64_t dex_offset, MapInfo* info);
+
+ void GetMethodInformation(uint64_t dex_offset, MapInfo* info, std::string* method_name,
+ uint64_t* method_offset);
+
+ void SetArch(ArchEnum arch);
+
+ private:
+ std::shared_ptr<Memory> memory_;
+ std::mutex files_lock_;
+ std::unordered_map<uint64_t, DexFile*> files_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a7b57e6..e8af8b4 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -32,6 +32,7 @@
namespace unwindstack {
// Forward declarations.
+class DexFiles;
class Elf;
class JitDebug;
enum ArchEnum : uint8_t;
@@ -42,7 +43,6 @@
uint64_t rel_pc;
uint64_t pc;
uint64_t sp;
- uint64_t dex_pc;
std::string function_name;
uint64_t function_offset;
@@ -75,10 +75,15 @@
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+#endif
+
ErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
private:
+ void FillInDexFrame();
void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
size_t max_frames_;
@@ -87,6 +92,9 @@
std::vector<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
JitDebug* jit_debug_ = nullptr;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ DexFiles* dex_files_ = nullptr;
+#endif
ErrorData last_error_;
};
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
new file mode 100644
index 0000000..d1338cb
--- /dev/null
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unordered_map>
+
+#include <android-base/test_utils.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/standard_dex_file.h>
+
+#include <gtest/gtest.h>
+
+#include "DexFile.h"
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+// Borrowed from art/dex/dex_file_test.cc.
+static constexpr uint32_t kDexData[] = {
+ 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+ 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+ 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+ 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+ 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+ 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+ 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+ 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+ 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+ 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+ 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+ 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+ 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+ 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+ 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+ 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+ 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
+};
+
+TEST(DexFileTest, from_file_open_non_exist) {
+ DexFileFromFile dex_file;
+ ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+}
+
+TEST(DexFileTest, from_file_open_too_small) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+ static_cast<size_t>(
+ TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+
+ // Header too small.
+ DexFileFromFile dex_file;
+ ASSERT_FALSE(dex_file.Open(0, tf.path));
+
+ // Header correct, file too small.
+ ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
+ ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
+ tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+ ASSERT_FALSE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ DexFileFromFile dex_file;
+ ASSERT_TRUE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open_non_zero_offset) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ DexFileFromFile dex_file;
+ ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_header) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
+ DexFileFromMemory dex_file;
+
+ ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_data) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
+ DexFileFromMemory dex_file;
+
+ ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_open) {
+ MemoryFake memory;
+
+ memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
+ DexFileFromMemory dex_file;
+
+ ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, create_using_file) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_start) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_offset) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+ ASSERT_EQ(sizeof(kDexData),
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+ MemoryFake memory;
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_empty_file) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_does_not_exist) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_is_malformed) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_EQ(sizeof(kDexData) - 10,
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
+
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+
+ // Check it came from memory by clearing memory and verifying it fails.
+ memory.Clear();
+ dex_file.reset(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file == nullptr);
+}
+
+TEST(DexFileTest, get_method_not_opened) {
+ std::string method("something");
+ uint64_t method_offset = 100;
+ DexFile dex_file;
+ dex_file.GetMethodInformation(0x100, &method, &method_offset);
+ EXPECT_EQ("something", method);
+ EXPECT_EQ(100U, method_offset);
+}
+
+TEST(DexFileTest, get_method) {
+ MemoryFake memory;
+ memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+ MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+ std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ ASSERT_TRUE(dex_file != nullptr);
+
+ std::string method;
+ uint64_t method_offset;
+ dex_file->GetMethodInformation(0x102, &method, &method_offset);
+ EXPECT_EQ("Main.<init>", method);
+ EXPECT_EQ(2U, method_offset);
+
+ method = "not_in_a_method";
+ method_offset = 0x123;
+ dex_file->GetMethodInformation(0x100000, &method, &method_offset);
+ EXPECT_EQ("not_in_a_method", method);
+ EXPECT_EQ(0x123U, method_offset);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 33e5527..07e48af 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -96,13 +96,8 @@
unwinder.Unwind();
// Print the frames.
- const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
printf("%s\n", unwinder.FormatFrame(i).c_str());
- const unwindstack::FrameData* frame = &frames[i];
- if (frame->dex_pc != 0) {
- printf(" dex pc %" PRIx64 "\n", frame->dex_pc);
- }
}
}