diff options
author | Christopher Ferris | 2017-08-30 15:15:19 -0500 |
---|---|---|
committer | Christopher Ferris | 2017-08-30 17:50:11 -0500 |
commit | 3f805ac3f8e61489f66a54bbdb1a8dd541c043d1 (patch) | |
tree | 5392038e32942faed35a0b94fd821e3dc3c887fe | |
parent | e1f9a58c8649136af7578b01c3f224ea4b88b555 (diff) | |
download | platform-system-core-3f805ac3f8e61489f66a54bbdb1a8dd541c043d1.tar.gz platform-system-core-3f805ac3f8e61489f66a54bbdb1a8dd541c043d1.tar.xz platform-system-core-3f805ac3f8e61489f66a54bbdb1a8dd541c043d1.zip |
Add proper support for embedded elf files.
- Add a method to get the max size of an elf file by reading the
section header offset + size. This will properly map an elf
file embedded into an apk, instead of just mapping in what is done
by the dynamic linker. It does assume that the section headers are
at the end of the elf file.
- Add new tests for the above functionality.
- Update the unwind_symbols tool to take an address for finding a
function instead of dumping the entire symbol table.
Bug: 23762183
Test: Unit tests pass, unwind through the camera process and verify
Test: the GoogleCamera.apk shows some function names.
Change-Id: I00c021680fe1d43b60d652bf91bbf6667d9617be
-rw-r--r-- | libunwindstack/Elf.cpp | 22 | ||||
-rw-r--r-- | libunwindstack/ElfInterface.cpp | 19 | ||||
-rw-r--r-- | libunwindstack/MapInfo.cpp | 77 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Elf.h | 2 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/ElfInterface.h | 11 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/MapInfo.h | 1 | ||||
-rw-r--r-- | libunwindstack/tests/MapInfoCreateMemoryTest.cpp | 84 | ||||
-rw-r--r-- | libunwindstack/tools/unwind_symbols.cpp | 34 |
8 files changed, 210 insertions, 40 deletions
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 4fc7c679f..4f7476d92 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp | |||
@@ -124,6 +124,28 @@ bool Elf::IsValidElf(Memory* memory) { | |||
124 | return true; | 124 | return true; |
125 | } | 125 | } |
126 | 126 | ||
127 | void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) { | ||
128 | if (!IsValidElf(memory)) { | ||
129 | *valid = false; | ||
130 | return; | ||
131 | } | ||
132 | *size = 0; | ||
133 | *valid = true; | ||
134 | |||
135 | // Now read the section header information. | ||
136 | uint8_t class_type; | ||
137 | if (!memory->Read(EI_CLASS, &class_type, 1)) { | ||
138 | return; | ||
139 | } | ||
140 | if (class_type == ELFCLASS32) { | ||
141 | ElfInterface32::GetMaxSize(memory, size); | ||
142 | } else if (class_type == ELFCLASS64) { | ||
143 | ElfInterface64::GetMaxSize(memory, size); | ||
144 | } else { | ||
145 | *valid = false; | ||
146 | } | ||
147 | } | ||
148 | |||
127 | ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { | 149 | ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { |
128 | if (!IsValidElf(memory)) { | 150 | if (!IsValidElf(memory)) { |
129 | return nullptr; | 151 | return nullptr; |
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 75abc85f7..be4f88a26 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp | |||
@@ -370,6 +370,22 @@ bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) { | |||
370 | return false; | 370 | return false; |
371 | } | 371 | } |
372 | 372 | ||
373 | // This is an estimation of the size of the elf file using the location | ||
374 | // of the section headers and size. This assumes that the section headers | ||
375 | // are at the end of the elf file. If the elf has a load bias, the size | ||
376 | // will be too large, but this is acceptable. | ||
377 | template <typename EhdrType> | ||
378 | void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) { | ||
379 | EhdrType ehdr; | ||
380 | if (!memory->Read(0, &ehdr, sizeof(ehdr))) { | ||
381 | return; | ||
382 | } | ||
383 | if (ehdr.e_shnum == 0) { | ||
384 | return; | ||
385 | } | ||
386 | *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum; | ||
387 | } | ||
388 | |||
373 | // Instantiate all of the needed template functions. | 389 | // Instantiate all of the needed template functions. |
374 | template void ElfInterface::InitHeadersWithTemplate<uint32_t>(); | 390 | template void ElfInterface::InitHeadersWithTemplate<uint32_t>(); |
375 | template void ElfInterface::InitHeadersWithTemplate<uint64_t>(); | 391 | template void ElfInterface::InitHeadersWithTemplate<uint64_t>(); |
@@ -391,4 +407,7 @@ template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std | |||
391 | template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, | 407 | template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, |
392 | uint64_t*); | 408 | uint64_t*); |
393 | 409 | ||
410 | template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*); | ||
411 | template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*); | ||
412 | |||
394 | } // namespace unwindstack | 413 | } // namespace unwindstack |
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index d0e1216f3..32722154a 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp | |||
@@ -27,6 +27,55 @@ | |||
27 | 27 | ||
28 | namespace unwindstack { | 28 | namespace unwindstack { |
29 | 29 | ||
30 | Memory* MapInfo::GetFileMemory() { | ||
31 | std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset); | ||
32 | if (offset == 0) { | ||
33 | if (memory->Init(name, 0)) { | ||
34 | return memory.release(); | ||
35 | } | ||
36 | return nullptr; | ||
37 | } | ||
38 | |||
39 | // There are two possibilities when the offset is non-zero. | ||
40 | // - There is an elf file embedded in a file. | ||
41 | // - The whole file is an elf file, and the offset needs to be saved. | ||
42 | // | ||
43 | // Map in just the part of the file for the map. If this is not | ||
44 | // a valid elf, then reinit as if the whole file is an elf file. | ||
45 | // If the offset is a valid elf, then determine the size of the map | ||
46 | // and reinit to that size. This is needed because the dynamic linker | ||
47 | // only maps in a portion of the original elf, and never the symbol | ||
48 | // file data. | ||
49 | uint64_t map_size = end - start; | ||
50 | if (!memory->Init(name, offset, map_size)) { | ||
51 | return nullptr; | ||
52 | } | ||
53 | |||
54 | bool valid; | ||
55 | uint64_t max_size; | ||
56 | Elf::GetInfo(memory.get(), &valid, &max_size); | ||
57 | if (!valid) { | ||
58 | // Init as if the whole file is an elf. | ||
59 | if (memory->Init(name, 0)) { | ||
60 | elf_offset = offset; | ||
61 | return memory.release(); | ||
62 | } | ||
63 | return nullptr; | ||
64 | } | ||
65 | |||
66 | if (max_size > map_size) { | ||
67 | if (memory->Init(name, offset, max_size)) { | ||
68 | return memory.release(); | ||
69 | } | ||
70 | // Try to reinit using the default map_size. | ||
71 | if (memory->Init(name, offset, map_size)) { | ||
72 | return memory.release(); | ||
73 | } | ||
74 | return nullptr; | ||
75 | } | ||
76 | return memory.release(); | ||
77 | } | ||
78 | |||
30 | Memory* MapInfo::CreateMemory(pid_t pid) { | 79 | Memory* MapInfo::CreateMemory(pid_t pid) { |
31 | if (end <= start) { | 80 | if (end <= start) { |
32 | return nullptr; | 81 | return nullptr; |
@@ -40,33 +89,13 @@ Memory* MapInfo::CreateMemory(pid_t pid) { | |||
40 | if (flags & MAPS_FLAGS_DEVICE_MAP) { | 89 | if (flags & MAPS_FLAGS_DEVICE_MAP) { |
41 | return nullptr; | 90 | return nullptr; |
42 | } | 91 | } |
43 | 92 | Memory* memory = GetFileMemory(); | |
44 | std::unique_ptr<MemoryFileAtOffset> file_memory(new MemoryFileAtOffset); | 93 | if (memory != nullptr) { |
45 | uint64_t map_size; | 94 | return memory; |
46 | if (offset != 0) { | ||
47 | // Only map in a piece of the file. | ||
48 | map_size = end - start; | ||
49 | } else { | ||
50 | map_size = UINT64_MAX; | ||
51 | } | ||
52 | if (file_memory->Init(name, offset, map_size)) { | ||
53 | // It's possible that a non-zero offset might not be pointing to | ||
54 | // valid elf data. Check if this is a valid elf, and if not assume | ||
55 | // that this was meant to incorporate the entire file. | ||
56 | if (offset != 0 && !Elf::IsValidElf(file_memory.get())) { | ||
57 | // Don't bother checking the validity that will happen on the elf init. | ||
58 | if (file_memory->Init(name, 0)) { | ||
59 | elf_offset = offset; | ||
60 | return file_memory.release(); | ||
61 | } | ||
62 | // Fall through if the init fails. | ||
63 | } else { | ||
64 | return file_memory.release(); | ||
65 | } | ||
66 | } | 95 | } |
67 | } | 96 | } |
68 | 97 | ||
69 | Memory* memory = nullptr; | 98 | Memory* memory; |
70 | if (pid == getpid()) { | 99 | if (pid == getpid()) { |
71 | memory = new MemoryLocal(); | 100 | memory = new MemoryLocal(); |
72 | } else { | 101 | } else { |
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index d89a7464a..4e7eb3447 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h | |||
@@ -70,6 +70,8 @@ class Elf { | |||
70 | 70 | ||
71 | static bool IsValidElf(Memory* memory); | 71 | static bool IsValidElf(Memory* memory); |
72 | 72 | ||
73 | static void GetInfo(Memory* memory, bool* valid, uint64_t* size); | ||
74 | |||
73 | protected: | 75 | protected: |
74 | bool valid_ = false; | 76 | bool valid_ = false; |
75 | std::unique_ptr<ElfInterface> interface_; | 77 | std::unique_ptr<ElfInterface> interface_; |
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 5cac0d358..142a6259e 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h | |||
@@ -102,6 +102,9 @@ class ElfInterface { | |||
102 | 102 | ||
103 | virtual bool HandleType(uint64_t, uint32_t) { return false; } | 103 | virtual bool HandleType(uint64_t, uint32_t) { return false; } |
104 | 104 | ||
105 | template <typename EhdrType> | ||
106 | static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size); | ||
107 | |||
105 | Memory* memory_; | 108 | Memory* memory_; |
106 | std::unordered_map<uint64_t, LoadInfo> pt_loads_; | 109 | std::unordered_map<uint64_t, LoadInfo> pt_loads_; |
107 | uint64_t load_bias_ = 0; | 110 | uint64_t load_bias_ = 0; |
@@ -146,6 +149,10 @@ class ElfInterface32 : public ElfInterface { | |||
146 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { | 149 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { |
147 | return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); | 150 | return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); |
148 | } | 151 | } |
152 | |||
153 | static void GetMaxSize(Memory* memory, uint64_t* size) { | ||
154 | GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size); | ||
155 | } | ||
149 | }; | 156 | }; |
150 | 157 | ||
151 | class ElfInterface64 : public ElfInterface { | 158 | class ElfInterface64 : public ElfInterface { |
@@ -166,6 +173,10 @@ class ElfInterface64 : public ElfInterface { | |||
166 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { | 173 | bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { |
167 | return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); | 174 | return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); |
168 | } | 175 | } |
176 | |||
177 | static void GetMaxSize(Memory* memory, uint64_t* size) { | ||
178 | GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size); | ||
179 | } | ||
169 | }; | 180 | }; |
170 | 181 | ||
171 | } // namespace unwindstack | 182 | } // namespace unwindstack |
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index 185476799..b8ba92576 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h | |||
@@ -40,6 +40,7 @@ struct MapInfo { | |||
40 | // instead of a portion of the file. | 40 | // instead of a portion of the file. |
41 | uint64_t elf_offset; | 41 | uint64_t elf_offset; |
42 | 42 | ||
43 | Memory* GetFileMemory(); | ||
43 | Memory* CreateMemory(pid_t pid); | 44 | Memory* CreateMemory(pid_t pid); |
44 | // This function guarantees it will never return nullptr. | 45 | // This function guarantees it will never return nullptr. |
45 | Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false); | 46 | Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false); |
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 9e45e7812..2aab9c652 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp | |||
@@ -38,30 +38,50 @@ namespace unwindstack { | |||
38 | 38 | ||
39 | class MapInfoCreateMemoryTest : public ::testing::Test { | 39 | class MapInfoCreateMemoryTest : public ::testing::Test { |
40 | protected: | 40 | protected: |
41 | template <typename Ehdr, typename Shdr> | ||
42 | static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) { | ||
43 | std::vector<uint8_t> buffer(20000); | ||
44 | memset(buffer.data(), 0, buffer.size()); | ||
45 | |||
46 | Ehdr ehdr; | ||
47 | memset(&ehdr, 0, sizeof(ehdr)); | ||
48 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG); | ||
49 | ehdr.e_ident[EI_CLASS] = class_type; | ||
50 | ehdr.e_shoff = sh_offset; | ||
51 | ehdr.e_shentsize = sizeof(Shdr) + 100; | ||
52 | ehdr.e_shnum = 4; | ||
53 | memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr)); | ||
54 | |||
55 | ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size())); | ||
56 | } | ||
57 | |||
41 | static void SetUpTestCase() { | 58 | static void SetUpTestCase() { |
42 | std::vector<uint8_t> buffer(1024); | 59 | std::vector<uint8_t> buffer(1024); |
60 | memset(buffer.data(), 0, buffer.size()); | ||
43 | memcpy(buffer.data(), ELFMAG, SELFMAG); | 61 | memcpy(buffer.data(), ELFMAG, SELFMAG); |
44 | for (size_t i = SELFMAG; i < buffer.size(); i++) { | 62 | buffer[EI_CLASS] = ELFCLASS32; |
45 | buffer[i] = i / 256 + 1; | ||
46 | } | ||
47 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); | 63 | ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); |
48 | 64 | ||
49 | for (size_t i = 0; i < 0x100; i++) { | 65 | memset(buffer.data(), 0, buffer.size()); |
50 | buffer[i] = i / 256 + 1; | ||
51 | } | ||
52 | memcpy(&buffer[0x100], ELFMAG, SELFMAG); | 66 | memcpy(&buffer[0x100], ELFMAG, SELFMAG); |
53 | for (size_t i = 0x100 + SELFMAG; i < buffer.size(); i++) { | 67 | buffer[0x100 + EI_CLASS] = ELFCLASS64; |
54 | buffer[i] = i / 256 + 1; | ||
55 | } | ||
56 | ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); | 68 | ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); |
69 | |||
70 | InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32); | ||
71 | InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64); | ||
57 | } | 72 | } |
58 | 73 | ||
59 | static TemporaryFile elf_; | 74 | static TemporaryFile elf_; |
60 | 75 | ||
61 | static TemporaryFile elf_at_100_; | 76 | static TemporaryFile elf_at_100_; |
77 | |||
78 | static TemporaryFile elf32_at_map_; | ||
79 | static TemporaryFile elf64_at_map_; | ||
62 | }; | 80 | }; |
63 | TemporaryFile MapInfoCreateMemoryTest::elf_; | 81 | TemporaryFile MapInfoCreateMemoryTest::elf_; |
64 | TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; | 82 | TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; |
83 | TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_; | ||
84 | TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; | ||
65 | 85 | ||
66 | TEST_F(MapInfoCreateMemoryTest, end_le_start) { | 86 | TEST_F(MapInfoCreateMemoryTest, end_le_start) { |
67 | MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path}; | 87 | MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path}; |
@@ -93,8 +113,9 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { | |||
93 | std::vector<uint8_t> buffer(1024); | 113 | std::vector<uint8_t> buffer(1024); |
94 | ASSERT_TRUE(memory->Read(0, buffer.data(), 1024)); | 114 | ASSERT_TRUE(memory->Read(0, buffer.data(), 1024)); |
95 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); | 115 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); |
96 | for (size_t i = SELFMAG; i < buffer.size(); i++) { | 116 | ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]); |
97 | ASSERT_EQ(i / 256 + 1, buffer[i]) << "Failed at byte " << i; | 117 | for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) { |
118 | ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; | ||
98 | } | 119 | } |
99 | 120 | ||
100 | ASSERT_FALSE(memory->Read(1024, buffer.data(), 1)); | 121 | ASSERT_FALSE(memory->Read(1024, buffer.data(), 1)); |
@@ -113,13 +134,50 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { | |||
113 | std::vector<uint8_t> buffer(0x100); | 134 | std::vector<uint8_t> buffer(0x100); |
114 | ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100)); | 135 | ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100)); |
115 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); | 136 | ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); |
116 | for (size_t i = SELFMAG; i < buffer.size(); i++) { | 137 | ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]); |
117 | ASSERT_EQ(2, buffer[i]) << "Failed at byte " << i; | 138 | for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) { |
139 | ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; | ||
118 | } | 140 | } |
119 | 141 | ||
120 | ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1)); | 142 | ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1)); |
121 | } | 143 | } |
122 | 144 | ||
145 | // Verify that if the offset is non-zero and there is an elf at that | ||
146 | // offset, that only part of the file is used. Further verify that if the | ||
147 | // embedded elf is bigger than the initial map, the new object is larger | ||
148 | // than the original map size. Do this for a 32 bit elf and a 64 bit elf. | ||
149 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) { | ||
150 | MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path}; | ||
151 | |||
152 | std::unique_ptr<Memory> memory(info.CreateMemory(getpid())); | ||
153 | ASSERT_TRUE(memory.get() != nullptr); | ||
154 | ASSERT_EQ(0U, info.elf_offset); | ||
155 | |||
156 | // Verify the memory is a valid elf. | ||
157 | uint8_t e_ident[SELFMAG + 1]; | ||
158 | ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG)); | ||
159 | ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG)); | ||
160 | |||
161 | // Read past the end of what would normally be the size of the map. | ||
162 | ASSERT_TRUE(memory->Read(0x1000, e_ident, 1)); | ||
163 | } | ||
164 | |||
165 | TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) { | ||
166 | MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path}; | ||
167 | |||
168 | std::unique_ptr<Memory> memory(info.CreateMemory(getpid())); | ||
169 | ASSERT_TRUE(memory.get() != nullptr); | ||
170 | ASSERT_EQ(0U, info.elf_offset); | ||
171 | |||
172 | // Verify the memory is a valid elf. | ||
173 | uint8_t e_ident[SELFMAG + 1]; | ||
174 | ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG)); | ||
175 | ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG)); | ||
176 | |||
177 | // Read past the end of what would normally be the size of the map. | ||
178 | ASSERT_TRUE(memory->Read(0x1000, e_ident, 1)); | ||
179 | } | ||
180 | |||
123 | // Verify that device file names will never result in Memory object creation. | 181 | // Verify that device file names will never result in Memory object creation. |
124 | TEST_F(MapInfoCreateMemoryTest, check_device_maps) { | 182 | TEST_F(MapInfoCreateMemoryTest, check_device_maps) { |
125 | // Set up some memory so that a valid local memory object would | 183 | // Set up some memory so that a valid local memory object would |
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp index b757c1e56..dc9ae5a06 100644 --- a/libunwindstack/tools/unwind_symbols.cpp +++ b/libunwindstack/tools/unwind_symbols.cpp | |||
@@ -28,8 +28,11 @@ | |||
28 | #include <unwindstack/Memory.h> | 28 | #include <unwindstack/Memory.h> |
29 | 29 | ||
30 | int main(int argc, char** argv) { | 30 | int main(int argc, char** argv) { |
31 | if (argc != 2) { | 31 | if (argc != 2 && argc != 3) { |
32 | printf("Need to pass the name of an elf file to the program.\n"); | 32 | printf("Usage: unwind_symbols <ELF_FILE> [<FUNC_ADDRESS>]\n"); |
33 | printf(" Dump all function symbols in ELF_FILE. If FUNC_ADDRESS is\n"); | ||
34 | printf(" specified, then get the function at that address.\n"); | ||
35 | printf(" FUNC_ADDRESS must be a hex number.\n"); | ||
33 | return 1; | 36 | return 1; |
34 | } | 37 | } |
35 | 38 | ||
@@ -43,6 +46,16 @@ int main(int argc, char** argv) { | |||
43 | return 1; | 46 | return 1; |
44 | } | 47 | } |
45 | 48 | ||
49 | uint64_t func_addr; | ||
50 | if (argc == 3) { | ||
51 | char* name; | ||
52 | func_addr = strtoull(argv[2], &name, 16); | ||
53 | if (*name != '\0') { | ||
54 | printf("%s is not a hex number.\n", argv[2]); | ||
55 | return 1; | ||
56 | } | ||
57 | } | ||
58 | |||
46 | // Send all log messages to stdout. | 59 | // Send all log messages to stdout. |
47 | unwindstack::log_to_stdout(true); | 60 | unwindstack::log_to_stdout(true); |
48 | 61 | ||
@@ -76,9 +89,24 @@ int main(int argc, char** argv) { | |||
76 | return 1; | 89 | return 1; |
77 | } | 90 | } |
78 | 91 | ||
79 | // This is a crude way to get the symbols in order. | ||
80 | std::string name; | 92 | std::string name; |
81 | uint64_t load_bias = elf.interface()->load_bias(); | 93 | uint64_t load_bias = elf.interface()->load_bias(); |
94 | if (argc == 3) { | ||
95 | std::string cur_name; | ||
96 | uint64_t func_offset; | ||
97 | if (!elf.GetFunctionName(func_addr, &cur_name, &func_offset)) { | ||
98 | printf("No known function at 0x%" PRIx64 "\n", func_addr); | ||
99 | return 1; | ||
100 | } | ||
101 | printf("<0x%" PRIx64 ">", func_addr - func_offset); | ||
102 | if (func_offset != 0) { | ||
103 | printf("+%" PRId64, func_offset); | ||
104 | } | ||
105 | printf(": %s\n", cur_name.c_str()); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | // This is a crude way to get the symbols in order. | ||
82 | for (const auto& entry : elf.interface()->pt_loads()) { | 110 | for (const auto& entry : elf.interface()->pt_loads()) { |
83 | uint64_t start = entry.second.offset + load_bias; | 111 | uint64_t start = entry.second.offset + load_bias; |
84 | uint64_t end = entry.second.table_size + load_bias; | 112 | uint64_t end = entry.second.table_size + load_bias; |