Fix handling of ro segments for embedded libs.
When a shared library is loaded directly from an apk, the new way the linker splits a shared library into a read-only and execute segment broke unwinding. Modify the code to handle this case. Other changes: - Modify the algorithm for finding read-only map entries. Before, the code would search the entire map for the closest offset. Now it simply looks at the previous map. I did this because the old code was too lenient and might still work even if the linker changes. I want this to break if the linker behavior changes so that I can analyze the change. - Update the tools to use PTRACE_SEIZE instead of PTRACE_ATTACH since PTRACE_ATTACH doesn't work in all cases. - Small refactor of the GetFileMemory function. - Add new unit test cases and new offline unwind test cases. Bug: 120618231 Test: Ran new unit tests, ran original failing test. Change-Id: I4bade55cf33220d52f1d5e9b0cbbbcc8419669d4
This commit is contained in:
parent
1fcf7f7d1f
commit
01040b10b2
|
@ -235,6 +235,8 @@ cc_test {
|
|||
"tests/files/offline/jit_map_arm/*",
|
||||
"tests/files/offline/gnu_debugdata_arm/*",
|
||||
"tests/files/offline/offset_arm/*",
|
||||
"tests/files/offline/shared_lib_in_apk_arm64/*",
|
||||
"tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
|
||||
"tests/files/offline/straddle_arm/*",
|
||||
"tests/files/offline/straddle_arm64/*",
|
||||
],
|
||||
|
|
|
@ -29,6 +29,38 @@
|
|||
|
||||
namespace unwindstack {
|
||||
|
||||
bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
|
||||
// One last attempt, see if the previous map is read-only with the
|
||||
// same name and stretches across this map.
|
||||
for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
|
||||
if (*iter == this) {
|
||||
if (iter == maps_->begin()) {
|
||||
return false;
|
||||
}
|
||||
--iter;
|
||||
MapInfo* prev_map = *iter;
|
||||
// Make sure this is a read-only map.
|
||||
if (prev_map->flags != PROT_READ) {
|
||||
return false;
|
||||
}
|
||||
uint64_t map_size = end - prev_map->end;
|
||||
if (!memory->Init(name, prev_map->offset, map_size)) {
|
||||
return false;
|
||||
}
|
||||
uint64_t max_size;
|
||||
if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
|
||||
return false;
|
||||
}
|
||||
if (!memory->Init(name, prev_map->offset, max_size)) {
|
||||
return false;
|
||||
}
|
||||
elf_offset = offset - prev_map->offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Memory* MapInfo::GetFileMemory() {
|
||||
std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
|
||||
if (offset == 0) {
|
||||
|
@ -38,8 +70,12 @@ Memory* MapInfo::GetFileMemory() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// There are two possibilities when the offset is non-zero.
|
||||
// - There is an elf file embedded in a file.
|
||||
// These are the possibilities when the offset is non-zero.
|
||||
// - There is an elf file embedded in a file, and the offset is the
|
||||
// the start of the elf in the file.
|
||||
// - There is an elf file embedded in a file, and the offset is the
|
||||
// the start of the executable part of the file. The actual start
|
||||
// of the elf is in the read-only segment preceeding this map.
|
||||
// - The whole file is an elf file, and the offset needs to be saved.
|
||||
//
|
||||
// Map in just the part of the file for the map. If this is not
|
||||
|
@ -53,27 +89,41 @@ Memory* MapInfo::GetFileMemory() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t max_size;
|
||||
if (!Elf::GetInfo(memory.get(), &max_size)) {
|
||||
// Init as if the whole file is an elf.
|
||||
if (memory->Init(name, 0)) {
|
||||
elf_offset = offset;
|
||||
return memory.release();
|
||||
// Check if the start of this map is an embedded elf.
|
||||
uint64_t max_size = 0;
|
||||
uint64_t file_offset = offset;
|
||||
if (Elf::GetInfo(memory.get(), &max_size)) {
|
||||
if (max_size > map_size) {
|
||||
if (memory->Init(name, file_offset, max_size)) {
|
||||
return memory.release();
|
||||
}
|
||||
// Try to reinit using the default map_size.
|
||||
if (memory->Init(name, file_offset, map_size)) {
|
||||
return memory.release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
return memory.release();
|
||||
}
|
||||
|
||||
if (max_size > map_size) {
|
||||
if (memory->Init(name, offset, max_size)) {
|
||||
return memory.release();
|
||||
}
|
||||
// Try to reinit using the default map_size.
|
||||
if (memory->Init(name, offset, map_size)) {
|
||||
return memory.release();
|
||||
}
|
||||
return nullptr;
|
||||
// No elf at offset, try to init as if the whole file is an elf.
|
||||
if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
|
||||
elf_offset = offset;
|
||||
return memory.release();
|
||||
}
|
||||
return memory.release();
|
||||
|
||||
// See if the map previous to this one contains a read-only map
|
||||
// that represents the real start of the elf data.
|
||||
if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) {
|
||||
return memory.release();
|
||||
}
|
||||
|
||||
// Failed to find elf at start of file or at read-only map, return
|
||||
// file object from the current map.
|
||||
if (memory->Init(name, offset, map_size)) {
|
||||
return memory.release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
|
||||
|
@ -110,29 +160,27 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Find the read-only map that has the same name and has an offset closest
|
||||
// to the current offset but less than the offset of the current map.
|
||||
// For shared libraries, there should be a r-x map that has a non-zero
|
||||
// offset and then a r-- map that has a zero offset.
|
||||
// For shared libraries loaded from an apk, there should be a r-x map that
|
||||
// has a non-zero offset and then a r-- map that has a non-zero offset less
|
||||
// than the offset from the r-x map.
|
||||
uint64_t closest_offset = 0;
|
||||
// Find the read-only map by looking at the previous map. The linker
|
||||
// doesn't guarantee that this invariant will always be true. However,
|
||||
// if that changes, there is likely something else that will change and
|
||||
// break something.
|
||||
MapInfo* ro_map_info = nullptr;
|
||||
for (auto map_info : *maps_) {
|
||||
if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset &&
|
||||
map_info->offset >= closest_offset) {
|
||||
ro_map_info = map_info;
|
||||
closest_offset = ro_map_info->offset;
|
||||
for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
|
||||
if (*iter == this) {
|
||||
if (iter != maps_->begin()) {
|
||||
--iter;
|
||||
ro_map_info = *iter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ro_map_info == nullptr) {
|
||||
if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure that relative pc values are corrected properly.
|
||||
elf_offset = offset - closest_offset;
|
||||
elf_offset = offset - ro_map_info->offset;
|
||||
|
||||
MemoryRanges* ranges = new MemoryRanges;
|
||||
ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
|
||||
|
|
|
@ -83,6 +83,7 @@ struct MapInfo {
|
|||
void operator=(const MapInfo&) = delete;
|
||||
|
||||
Memory* GetFileMemory();
|
||||
bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory);
|
||||
|
||||
// Protect the creation of the elf object.
|
||||
std::mutex mutex_;
|
||||
|
|
|
@ -59,16 +59,16 @@ class MapInfoCreateMemoryTest : public ::testing::Test {
|
|||
}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
std::vector<uint8_t> buffer(1024);
|
||||
memset(buffer.data(), 0, buffer.size());
|
||||
std::vector<uint8_t> buffer(12288, 0);
|
||||
memcpy(buffer.data(), ELFMAG, SELFMAG);
|
||||
buffer[EI_CLASS] = ELFCLASS32;
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), 1024));
|
||||
|
||||
memset(buffer.data(), 0, buffer.size());
|
||||
memcpy(&buffer[0x100], ELFMAG, SELFMAG);
|
||||
buffer[0x100 + EI_CLASS] = ELFCLASS64;
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size()));
|
||||
memcpy(&buffer[0x1000], ELFMAG, SELFMAG);
|
||||
buffer[0x1000 + EI_CLASS] = ELFCLASS64;
|
||||
buffer[0x2000] = 0xff;
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, buffer.data(), buffer.size()));
|
||||
|
||||
InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
|
||||
InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
|
||||
|
@ -84,13 +84,13 @@ class MapInfoCreateMemoryTest : public ::testing::Test {
|
|||
|
||||
static TemporaryFile elf_;
|
||||
|
||||
static TemporaryFile elf_at_100_;
|
||||
static TemporaryFile elf_at_1000_;
|
||||
|
||||
static TemporaryFile elf32_at_map_;
|
||||
static TemporaryFile elf64_at_map_;
|
||||
};
|
||||
TemporaryFile MapInfoCreateMemoryTest::elf_;
|
||||
TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
|
||||
TemporaryFile MapInfoCreateMemoryTest::elf_at_1000_;
|
||||
TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_;
|
||||
TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
|
||||
|
||||
|
@ -134,7 +134,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
|
|||
// Verify that if the offset is non-zero and there is an elf at that
|
||||
// offset, that only part of the file is used.
|
||||
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
|
||||
MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path);
|
||||
MapInfo info(nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path);
|
||||
|
||||
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
||||
ASSERT_TRUE(memory.get() != nullptr);
|
||||
|
@ -312,4 +312,43 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
|
||||
Maps maps;
|
||||
maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
|
||||
maps.Add(0x1000, 0x2000, 0x1000, PROT_READ, elf_at_1000_.path, 0);
|
||||
maps.Add(0x2000, 0x3000, 0x2000, PROT_READ | PROT_EXEC, elf_at_1000_.path, 0);
|
||||
|
||||
MapInfo* map_info = maps.Find(0x2000);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
|
||||
// Set up the size
|
||||
Elf64_Ehdr ehdr;
|
||||
ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
|
||||
ASSERT_TRUE(android::base::ReadFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
|
||||
|
||||
// Will not give the elf memory, because the read-only entry does not
|
||||
// extend over the executable segment.
|
||||
std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
|
||||
ASSERT_TRUE(memory.get() != nullptr);
|
||||
std::vector<uint8_t> buffer(0x100);
|
||||
EXPECT_EQ(0x2000U, map_info->offset);
|
||||
EXPECT_EQ(0U, map_info->elf_offset);
|
||||
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
|
||||
EXPECT_EQ(0xffU, buffer[0]);
|
||||
|
||||
// Now init the elf data enough so that the file memory object will be used.
|
||||
ehdr.e_shoff = 0x4000;
|
||||
ehdr.e_shnum = 1;
|
||||
ehdr.e_shentsize = 0x100;
|
||||
ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
|
||||
|
||||
memory.reset(map_info->CreateMemory(process_memory_));
|
||||
EXPECT_EQ(0x2000U, map_info->offset);
|
||||
EXPECT_EQ(0x1000U, map_info->elf_offset);
|
||||
Elf64_Ehdr ehdr_mem;
|
||||
ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem)));
|
||||
EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0);
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -1239,4 +1239,79 @@ TEST_F(UnwindOfflineTest, debug_frame_load_bias_arm) {
|
|||
EXPECT_EQ(0xffd4a718U, unwinder.frames()[7].sp);
|
||||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) {
|
||||
ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_arm64/", ARCH_ARM64));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
|
||||
EXPECT_EQ(
|
||||
" #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n"
|
||||
" #01 pc 000000000005426c (offset 0x39000) linker64 "
|
||||
"(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
|
||||
" #02 pc 00000000000008bc vdso.so\n"
|
||||
" #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n"
|
||||
" #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n"
|
||||
" #05 pc 000000000003d5b4 (offset 0x40000) ANGLEPrebuilt.apk (ANGLEGetUtilityAPI+56)\n"
|
||||
" #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n",
|
||||
frame_info);
|
||||
|
||||
EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
|
||||
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
|
||||
EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
|
||||
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
|
||||
EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
|
||||
EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
|
||||
EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
|
||||
EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
|
||||
EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc);
|
||||
EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp);
|
||||
EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc);
|
||||
EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp);
|
||||
EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc);
|
||||
EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp);
|
||||
// Ignore top frame since the test code was modified to end in __libc_init.
|
||||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) {
|
||||
ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_memory_only_arm64/", ARCH_ARM64));
|
||||
// Add the memory that represents the shared library.
|
||||
MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory_.get());
|
||||
AddMemory(dir_ + "lib_mem.data", memory);
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
|
||||
EXPECT_EQ(
|
||||
" #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n"
|
||||
" #01 pc 000000000005426c (offset 0x39000) linker64 "
|
||||
"(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
|
||||
" #02 pc 00000000000008bc vdso.so\n"
|
||||
" #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n"
|
||||
" #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n"
|
||||
" #05 pc 000000000003d5b4 (offset 0x2211000) ANGLEPrebuilt.apk\n"
|
||||
" #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n",
|
||||
frame_info);
|
||||
|
||||
EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
|
||||
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
|
||||
EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
|
||||
EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
|
||||
EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
|
||||
EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
|
||||
EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
|
||||
EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
|
||||
EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc);
|
||||
EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp);
|
||||
EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc);
|
||||
EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp);
|
||||
EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc);
|
||||
EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp);
|
||||
// Ignore top frame since the test code was modified to end in __libc_init.
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
7dabc03000-7dabc3f000 r--p 4000 00:00 0 ANGLEPrebuilt.apk
|
||||
7dabc3f000-7dabcf0000 r-xp 40000 00:00 0 ANGLEPrebuilt.apk
|
||||
7e7ee48000-7e7ee88000 r--p 0 00:00 0 libc.so
|
||||
7e7ee88000-7e7ef32000 r-xp 40000 00:00 0 libc.so
|
||||
7e82b01000-7e82b03000 r-xp 0 00:00 0 vdso.so
|
||||
7e82b03000-7e82b3c000 r--p 0 00:00 0 linker64
|
||||
7e82b3c000-7e82c77000 r-xp 39000 00:00 0 linker64
|
|
@ -0,0 +1,33 @@
|
|||
x0: 7df8ca3c24
|
||||
x1: 0
|
||||
x2: ffffffff
|
||||
x3: 0
|
||||
x4: 0
|
||||
x5: 0
|
||||
x6: 0
|
||||
x7: 7f7f7f7f7f7f7f7f
|
||||
x8: 62
|
||||
x9: 20dd5829922a93ac
|
||||
x10: 7e82b57420
|
||||
x11: 4100
|
||||
x12: 7df8ca3b70
|
||||
x13: 7df8ca3b98
|
||||
x14: 73d015e5
|
||||
x15: 39a36122467299
|
||||
x16: 76ac
|
||||
x17: 0
|
||||
x18: 7df8cfc000
|
||||
x19: 7dabf3e7a0
|
||||
x20: 7df8ca3da0
|
||||
x21: 59616d61
|
||||
x22: 1
|
||||
x23: 7df8ca3c24
|
||||
x24: 1894
|
||||
x25: 62
|
||||
x26: 2
|
||||
x27: 0
|
||||
x28: 7dabf3e790
|
||||
x29: 7df8ca3d90
|
||||
sp: 7df8ca3bf0
|
||||
lr: 7e82b57270
|
||||
pc: 7e82c4fcbc
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
7dabc03000-7dabc3f000 r--p 21d5000 00:00 0 ANGLEPrebuilt.apk
|
||||
7dabc3f000-7dabcf0000 r-xp 2211000 00:00 0 ANGLEPrebuilt.apk
|
||||
7e7ee48000-7e7ee88000 r--p 0 00:00 0 libc.so
|
||||
7e7ee88000-7e7ef32000 r-xp 40000 00:00 0 libc.so
|
||||
7e82b01000-7e82b03000 r-xp 0 00:00 0 vdso.so
|
||||
7e82b03000-7e82b3c000 r--p 0 00:00 0 linker64
|
||||
7e82b3c000-7e82c77000 r-xp 39000 00:00 0 linker64
|
|
@ -0,0 +1,33 @@
|
|||
x0: 7df8ca3c24
|
||||
x1: 0
|
||||
x2: ffffffff
|
||||
x3: 0
|
||||
x4: 0
|
||||
x5: 0
|
||||
x6: 0
|
||||
x7: 7f7f7f7f7f7f7f7f
|
||||
x8: 62
|
||||
x9: 20dd5829922a93ac
|
||||
x10: 7e82b57420
|
||||
x11: 4100
|
||||
x12: 7df8ca3b70
|
||||
x13: 7df8ca3b98
|
||||
x14: 73d015e5
|
||||
x15: 39a36122467299
|
||||
x16: 76ac
|
||||
x17: 0
|
||||
x18: 7df8cfc000
|
||||
x19: 7dabf3e7a0
|
||||
x20: 7df8ca3da0
|
||||
x21: 59616d61
|
||||
x22: 1
|
||||
x23: 7df8ca3c24
|
||||
x24: 1894
|
||||
x25: 62
|
||||
x26: 2
|
||||
x27: 0
|
||||
x28: 7dabf3e790
|
||||
x29: 7df8ca3d90
|
||||
sp: 7df8ca3bf0
|
||||
lr: 7e82b57270
|
||||
pc: 7e82c4fcbc
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -35,7 +35,12 @@
|
|||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
static bool Attach(pid_t pid) {
|
||||
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
|
||||
if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
|
||||
ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,12 @@ struct map_info_t {
|
|||
};
|
||||
|
||||
static bool Attach(pid_t pid) {
|
||||
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
|
||||
if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
|
||||
ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue