Merge "Fix which maps to search for globals."
This commit is contained in:
commit
7cffd15110
12 changed files with 214 additions and 97 deletions
|
|
@ -58,6 +58,7 @@ cc_library {
|
|||
"Elf.cpp",
|
||||
"ElfInterface.cpp",
|
||||
"ElfInterfaceArm.cpp",
|
||||
"Global.cpp",
|
||||
"JitDebug.cpp",
|
||||
"Log.cpp",
|
||||
"MapInfo.cpp",
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ struct DEXFileEntry64 {
|
|||
uint64_t dex_file;
|
||||
};
|
||||
|
||||
DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
|
||||
DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
|
||||
|
||||
DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
|
||||
: memory_(memory), search_libs_(search_libs) {}
|
||||
: Global(memory, search_libs) {}
|
||||
|
||||
DexFiles::~DexFiles() {
|
||||
for (auto& entry : files_) {
|
||||
|
|
@ -117,6 +117,11 @@ bool DexFiles::ReadEntry64() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
|
||||
entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
|
||||
return entry_addr_ != 0;
|
||||
}
|
||||
|
||||
void DexFiles::Init(Maps* maps) {
|
||||
if (initialized_) {
|
||||
return;
|
||||
|
|
@ -124,36 +129,7 @@ void DexFiles::Init(Maps* maps) {
|
|||
initialized_ = true;
|
||||
entry_addr_ = 0;
|
||||
|
||||
const std::string dex_debug_name("__dex_debug_descriptor");
|
||||
for (MapInfo* info : *maps) {
|
||||
if (!(info->flags & PROT_READ) || info->offset != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!search_libs_.empty()) {
|
||||
bool found = false;
|
||||
const char* lib = basename(info->name.c_str());
|
||||
for (const std::string& name : search_libs_) {
|
||||
if (name == lib) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Elf* elf = info->GetElf(memory_, true);
|
||||
uint64_t ptr;
|
||||
// Find first non-empty list (libart might be loaded multiple times).
|
||||
if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
|
||||
entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
|
||||
if (entry_addr_ != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
FindAndReadVariable(maps, "__dex_debug_descriptor");
|
||||
}
|
||||
|
||||
DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
|
||||
|
|
|
|||
96
libunwindstack/Global.cpp
Normal file
96
libunwindstack/Global.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Global.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Maps.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
Global::Global(std::shared_ptr<Memory>& memory) : memory_(memory) {}
|
||||
Global::Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
|
||||
: memory_(memory), search_libs_(search_libs) {}
|
||||
|
||||
uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
|
||||
if (!search_libs_.empty()) {
|
||||
bool found = false;
|
||||
const char* lib = basename(info->name.c_str());
|
||||
for (const std::string& name : search_libs_) {
|
||||
if (name == lib) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Elf* elf = info->GetElf(memory_, true);
|
||||
uint64_t ptr;
|
||||
// Find first non-empty list (libraries might be loaded multiple times).
|
||||
if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) {
|
||||
return ptr + info->start;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Global::FindAndReadVariable(Maps* maps, const char* var_str) {
|
||||
std::string variable(var_str);
|
||||
// When looking for global variables, do not arbitrarily search every
|
||||
// readable map. Instead look for a specific pattern that must exist.
|
||||
// The pattern should be a readable map, followed by a read-write
|
||||
// map with a non-zero offset.
|
||||
// For example:
|
||||
// f0000-f1000 0 r-- /system/lib/libc.so
|
||||
// f1000-f2000 1000 r-x /system/lib/libc.so
|
||||
// f2000-f3000 2000 rw- /system/lib/libc.so
|
||||
// This also works:
|
||||
// f0000-f2000 0 r-- /system/lib/libc.so
|
||||
// f2000-f3000 2000 rw- /system/lib/libc.so
|
||||
MapInfo* map_start = nullptr;
|
||||
for (MapInfo* info : *maps) {
|
||||
if (map_start != nullptr) {
|
||||
if (map_start->name == info->name) {
|
||||
if (info->offset != 0 &&
|
||||
(info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
|
||||
uint64_t ptr = GetVariableOffset(map_start, variable);
|
||||
if (ptr != 0 && ReadVariableData(ptr)) {
|
||||
break;
|
||||
} else {
|
||||
// Failed to find the global variable, do not bother trying again.
|
||||
map_start = nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
map_start = nullptr;
|
||||
}
|
||||
}
|
||||
if (map_start == nullptr && (info->flags & PROT_READ) && info->offset == 0 &&
|
||||
!info->name.empty()) {
|
||||
map_start = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
@ -69,10 +69,10 @@ struct JITDescriptor64 {
|
|||
uint64_t first_entry;
|
||||
};
|
||||
|
||||
JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : memory_(memory) {}
|
||||
JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
|
||||
|
||||
JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
|
||||
: memory_(memory), search_libs_(search_libs) {}
|
||||
: Global(memory, search_libs) {}
|
||||
|
||||
JitDebug::~JitDebug() {
|
||||
for (auto* elf : elf_list_) {
|
||||
|
|
@ -165,6 +165,11 @@ void JitDebug::SetArch(ArchEnum arch) {
|
|||
}
|
||||
}
|
||||
|
||||
bool JitDebug::ReadVariableData(uint64_t ptr) {
|
||||
entry_addr_ = (this->*read_descriptor_func_)(ptr);
|
||||
return entry_addr_ != 0;
|
||||
}
|
||||
|
||||
void JitDebug::Init(Maps* maps) {
|
||||
if (initialized_) {
|
||||
return;
|
||||
|
|
@ -172,36 +177,7 @@ void JitDebug::Init(Maps* maps) {
|
|||
// Regardless of what happens below, consider the init finished.
|
||||
initialized_ = true;
|
||||
|
||||
const std::string descriptor_name("__jit_debug_descriptor");
|
||||
for (MapInfo* info : *maps) {
|
||||
if (!(info->flags & PROT_READ) || info->offset != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!search_libs_.empty()) {
|
||||
bool found = false;
|
||||
const char* lib = basename(info->name.c_str());
|
||||
for (std::string& name : search_libs_) {
|
||||
if (strcmp(name.c_str(), lib) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Elf* elf = info->GetElf(memory_, true);
|
||||
uint64_t descriptor_addr;
|
||||
// Find first non-empty entry (libart might be loaded multiple times).
|
||||
if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr) && descriptor_addr != 0) {
|
||||
entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr + info->start);
|
||||
if (entry_addr_ != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
FindAndReadVariable(maps, "__jit_debug_descriptor");
|
||||
}
|
||||
|
||||
Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
|
||||
|
|
|
|||
|
|
@ -25,16 +25,18 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Global.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class DexFile;
|
||||
class Maps;
|
||||
struct MapInfo;
|
||||
class Memory;
|
||||
enum ArchEnum : uint8_t;
|
||||
|
||||
class DexFiles {
|
||||
class DexFiles : public Global {
|
||||
public:
|
||||
explicit DexFiles(std::shared_ptr<Memory>& memory);
|
||||
DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
|
||||
|
|
@ -60,8 +62,7 @@ class DexFiles {
|
|||
|
||||
bool ReadEntry64();
|
||||
|
||||
std::shared_ptr<Memory> memory_;
|
||||
std::vector<std::string> search_libs_;
|
||||
bool ReadVariableData(uint64_t ptr_offset) override;
|
||||
|
||||
std::mutex lock_;
|
||||
bool initialized_ = false;
|
||||
|
|
|
|||
54
libunwindstack/include/unwindstack/Global.h
Normal file
54
libunwindstack/include/unwindstack/Global.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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_GLOBAL_H
|
||||
#define _LIBUNWINDSTACK_GLOBAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Maps;
|
||||
struct MapInfo;
|
||||
|
||||
class Global {
|
||||
public:
|
||||
explicit Global(std::shared_ptr<Memory>& memory);
|
||||
Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
|
||||
virtual ~Global() = default;
|
||||
|
||||
protected:
|
||||
uint64_t GetVariableOffset(MapInfo* info, const std::string& variable);
|
||||
void FindAndReadVariable(Maps* maps, const char* variable);
|
||||
|
||||
virtual bool ReadVariableData(uint64_t offset) = 0;
|
||||
|
||||
std::shared_ptr<Memory> memory_;
|
||||
std::vector<std::string> search_libs_;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_GLOBAL_H
|
||||
|
|
@ -24,15 +24,17 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Global.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Elf;
|
||||
class Maps;
|
||||
class Memory;
|
||||
enum ArchEnum : uint8_t;
|
||||
|
||||
class JitDebug {
|
||||
class JitDebug : public Global {
|
||||
public:
|
||||
explicit JitDebug(std::shared_ptr<Memory>& memory);
|
||||
JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
|
||||
|
|
@ -45,11 +47,9 @@ class JitDebug {
|
|||
private:
|
||||
void Init(Maps* maps);
|
||||
|
||||
std::shared_ptr<Memory> memory_;
|
||||
uint64_t entry_addr_ = 0;
|
||||
bool initialized_ = false;
|
||||
std::vector<Elf*> elf_list_;
|
||||
std::vector<std::string> search_libs_;
|
||||
|
||||
std::mutex lock_;
|
||||
|
||||
|
|
@ -62,6 +62,8 @@ class JitDebug {
|
|||
uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size);
|
||||
uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size);
|
||||
uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
|
||||
|
||||
bool ReadVariableData(uint64_t ptr_offset) override;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
|||
|
|
@ -44,15 +44,15 @@ class DexFilesTest : public ::testing::Test {
|
|||
dex_files_->SetArch(ARCH_ARM);
|
||||
|
||||
maps_.reset(
|
||||
new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
|
||||
"4000-6000 r--s 00000000 00:00 0\n"
|
||||
"6000-8000 -wxs 00000000 00:00 0\n"
|
||||
"a000-c000 r--p 00000000 00:00 0\n"
|
||||
"c000-f000 rw-p 00000000 00:00 0\n"
|
||||
"f000-11000 r--p 00000000 00:00 0\n"
|
||||
"100000-110000 rw-p 0000000 00:00 0\n"
|
||||
"200000-210000 rw-p 0000000 00:00 0\n"
|
||||
"300000-400000 rw-p 0000000 00:00 0\n"));
|
||||
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
|
||||
"4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
|
||||
"6000-8000 -wxs 00000000 00:00 0 /fake/elf\n"
|
||||
"a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
|
||||
"c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
|
||||
"f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
|
||||
"100000-110000 rw-p 0001000 00:00 0 /fake/elf3\n"
|
||||
"200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
|
||||
"300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"));
|
||||
ASSERT_TRUE(maps_->Parse());
|
||||
|
||||
// Global variable in a section that is not readable.
|
||||
|
|
@ -96,8 +96,9 @@ class DexFilesTest : public ::testing::Test {
|
|||
void WriteDex(uint64_t dex_file);
|
||||
|
||||
static constexpr size_t kMapGlobalNonReadable = 2;
|
||||
static constexpr size_t kMapGlobalSetToZero = 4;
|
||||
static constexpr size_t kMapGlobalSetToZero = 3;
|
||||
static constexpr size_t kMapGlobal = 5;
|
||||
static constexpr size_t kMapGlobalRw = 6;
|
||||
static constexpr size_t kMapDexFileEntries = 7;
|
||||
static constexpr size_t kMapDexFiles = 8;
|
||||
|
||||
|
|
@ -256,6 +257,9 @@ TEST_F(DexFilesTest, get_method_information_search_libs) {
|
|||
map_info->name = "/system/lib/libart.so";
|
||||
dex_files_.reset(new DexFiles(process_memory_, libs));
|
||||
dex_files_->SetArch(ARCH_ARM);
|
||||
// Set the rw map to the same name or this will not scan this entry.
|
||||
map_info = maps_->Get(kMapGlobalRw);
|
||||
map_info->name = "/system/lib/libart.so";
|
||||
// Make sure that clearing out copy of the libs doesn't affect the
|
||||
// DexFiles object.
|
||||
libs.clear();
|
||||
|
|
@ -271,7 +275,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
|
|||
MapInfo* info = maps_->Get(kMapDexFiles);
|
||||
|
||||
// First global variable found, but value is zero.
|
||||
WriteDescriptor32(0xc800, 0);
|
||||
WriteDescriptor32(0xa800, 0);
|
||||
|
||||
WriteDescriptor32(0xf800, 0x200000);
|
||||
WriteEntry32(0x200000, 0, 0, 0x300000);
|
||||
|
|
@ -286,7 +290,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
|
|||
dex_files_->SetArch(ARCH_ARM);
|
||||
method_name = "fail";
|
||||
method_offset = 0x123;
|
||||
WriteDescriptor32(0xc800, 0x100000);
|
||||
WriteDescriptor32(0xa800, 0x100000);
|
||||
dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
|
||||
EXPECT_EQ("fail", method_name);
|
||||
EXPECT_EQ(0x123U, method_offset);
|
||||
|
|
@ -298,7 +302,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
|
|||
MapInfo* info = maps_->Get(kMapDexFiles);
|
||||
|
||||
// First global variable found, but value is zero.
|
||||
WriteDescriptor64(0xc800, 0);
|
||||
WriteDescriptor64(0xa800, 0);
|
||||
|
||||
WriteDescriptor64(0xf800, 0x200000);
|
||||
WriteEntry64(0x200000, 0, 0, 0x300000);
|
||||
|
|
@ -314,7 +318,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
|
|||
dex_files_->SetArch(ARCH_ARM64);
|
||||
method_name = "fail";
|
||||
method_offset = 0x123;
|
||||
WriteDescriptor64(0xc800, 0x100000);
|
||||
WriteDescriptor64(0xa800, 0x100000);
|
||||
dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
|
||||
EXPECT_EQ("fail", method_name);
|
||||
EXPECT_EQ(0x123U, method_offset);
|
||||
|
|
|
|||
|
|
@ -43,15 +43,16 @@ class JitDebugTest : public ::testing::Test {
|
|||
jit_debug_->SetArch(ARCH_ARM);
|
||||
|
||||
maps_.reset(
|
||||
new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
|
||||
"4000-6000 r--s 00000000 00:00 0\n"
|
||||
"6000-8000 -wxs 00000000 00:00 0\n"
|
||||
"a000-c000 --xp 00000000 00:00 0\n"
|
||||
"c000-f000 rw-p 00000000 00:00 0\n"
|
||||
"f000-11000 r--p 00000000 00:00 0\n"
|
||||
"12000-14000 r--p 00000000 00:00 0\n"
|
||||
"100000-110000 rw-p 0000000 00:00 0\n"
|
||||
"200000-210000 rw-p 0000000 00:00 0\n"));
|
||||
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
|
||||
"4000-6000 r--s 00000000 00:00 0 /fake/elf1\n"
|
||||
"6000-8000 -wxs 00000000 00:00 0 /fake/elf1\n"
|
||||
"a000-c000 --xp 00000000 00:00 0 /fake/elf2\n"
|
||||
"c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
|
||||
"f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
|
||||
"11000-12000 rw-p 00001000 00:00 0 /fake/elf3\n"
|
||||
"12000-14000 r--p 00000000 00:00 0 /fake/elf4\n"
|
||||
"100000-110000 rw-p 0001000 00:00 0 /fake/elf4\n"
|
||||
"200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n"));
|
||||
ASSERT_TRUE(maps_->Parse());
|
||||
|
||||
MapInfo* map_info = maps_->Get(3);
|
||||
|
|
@ -74,7 +75,7 @@ class JitDebugTest : public ::testing::Test {
|
|||
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
||||
map_info->elf.reset(elf);
|
||||
|
||||
map_info = maps_->Get(6);
|
||||
map_info = maps_->Get(7);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
memory = new MemoryFake;
|
||||
elf = new ElfFake(memory);
|
||||
|
|
@ -397,6 +398,8 @@ TEST_F(JitDebugTest, get_elf_search_libs) {
|
|||
// Change the name of the map that includes the value and verify this works.
|
||||
MapInfo* map_info = maps_->Get(5);
|
||||
map_info->name = "/system/lib/libart.so";
|
||||
map_info = maps_->Get(6);
|
||||
map_info->name = "/system/lib/libart.so";
|
||||
jit_debug_.reset(new JitDebug(process_memory_, libs));
|
||||
// Make sure that clearing our copy of the libs doesn't affect the
|
||||
// JitDebug object.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
d0250000-d2600000 r-xp 0 00:00 0 <anonymous:d0250000>
|
||||
e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
|
||||
e4ae8000-e4ae9000 rw-p 1000 00:00 0 libart.so
|
||||
e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ ab0d3000-ab0d8000 r-xp 0 00:00 0 dalvikvm32
|
|||
dfe4e000-dfe7b000 r-xp 0 00:00 0 libarttestd.so
|
||||
e0447000-e0448000 r-xp 2000 00:00 0 137-cfi.odex
|
||||
e2796000-e4796000 r-xp 0 00:00 0 anonymous:e2796000
|
||||
e648e000-e690f000 r-xp 00000000 00:00 0 libart.so
|
||||
e648e000-e690f000 r-xp 0 00:00 0 libart.so
|
||||
e690f000-e6910000 rw-p 1000 00:00 0 libart.so
|
||||
ed306000-ed801000 r-xp 0 00:00 0 libartd.so
|
||||
ed801000-ed802000 rw-p 1000 00:00 0 libartd.so
|
||||
eda88000-edb23000 r-xp 0 00:00 0 libc.so
|
||||
ede4e000-ede50000 r-xp 0 00:00 0 anonymous:ede4e000
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ eb833000-eb8cc000 r-xp 0 00:00 0 libarttestd.so
|
|||
ec606000-ec607000 r-xp 2000 00:00 0 137-cfi.odex
|
||||
ee74c000-f074c000 r-xp 0 00:00 0 anonymous:ee74c000
|
||||
f6be1000-f732b000 r-xp 0 00:00 0 libartd.so
|
||||
f732b000-f732c000 rw-p 1000 00:00 0 libartd.so
|
||||
f734b000-f74fc000 r-xp 0 00:00 0 libc.so
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue