diff options
author | David Srbecky <dsrbecky@google.com> | 2021-05-13 23:46:18 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-05-13 23:46:18 +0000 |
commit | 67889d84f68c35575d083b85c4f894bf16ec5ec8 (patch) | |
tree | ccc0290608ce6e174caa46343e2ac214c628f85a | |
parent | 3fb6f21d3404125d8a32ba1110a340af14eee1ac (diff) | |
parent | 0f9a7e4f40c9e61423572a35e3938f47b09a6fbb (diff) | |
download | unwinding-67889d84f68c35575d083b85c4f894bf16ec5ec8.tar.gz |
Fix symbol look for ART's function end-marker. am: 2edcc18349 am: 2867719610 am: 0f9a7e4f40
Original change: https://android-review.googlesource.com/c/platform/system/unwinding/+/1706751
Change-Id: Ice43baf64ad9420aa6bed8122f307ee9196f2e37
-rw-r--r-- | libunwindstack/Symbols.cpp | 12 | ||||
-rw-r--r-- | libunwindstack/tests/SymbolsTest.cpp | 32 |
2 files changed, 39 insertions, 5 deletions
diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp index 26f893e..499cc31 100644 --- a/libunwindstack/Symbols.cpp +++ b/libunwindstack/Symbols.cpp @@ -70,13 +70,15 @@ Symbols::Info* Symbols::BinarySearch(uint64_t addr, Memory* elf_memory, uint64_t if (!elf_memory->ReadFully(offset_ + symbol_index * entry_size_, &sym, sizeof(sym))) { return nullptr; } - Info info{.size = static_cast<uint32_t>(sym.st_size), .index = current}; - it = symbols_.emplace(sym.st_value + sym.st_size, info).first; + // There shouldn't be multiple symbols with same end address, but in case there are, + // overwrite the cache with the last entry, so that 'sym' and 'info' are consistent. + Info& info = symbols_[sym.st_value + sym.st_size]; + info = {.size = static_cast<uint32_t>(sym.st_size), .index = current}; if (addr < sym.st_value) { last = current; } else if (addr < sym.st_value + sym.st_size) { *func_offset = addr - sym.st_value; - return &it->second; + return &info; } else { first = current + 1; } @@ -104,7 +106,9 @@ void Symbols::BuildRemapTable(Memory* elf_memory) { SymType sym; memcpy(&sym, &buffer[offset], sizeof(SymType)); // Copy to ensure alignment. addrs.push_back(sym.st_value); // Always insert so it is indexable by symbol index. - if (IsFunc(&sym)) { + // NB: It is important to filter our zero-sized symbols since otherwise we can get + // duplicate end addresses in the table (e.g. if there is custom "end" symbol marker). + if (IsFunc(&sym) && sym.st_size != 0) { remap_->push_back(symbol_idx); // Indices of function symbols only. } } diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp index bae4e28..89147a2 100644 --- a/libunwindstack/tests/SymbolsTest.cpp +++ b/libunwindstack/tests/SymbolsTest.cpp @@ -307,6 +307,36 @@ TYPED_TEST_P(SymbolsTest, symtab_read_cached) { ASSERT_EQ(3U, func_offset); } +TYPED_TEST_P(SymbolsTest, symtab_end_marker) { + Symbols symbols(0x1000, 3 * sizeof(TypeParam), sizeof(TypeParam), 0xa000, 0x1000); + + TypeParam sym; + uint64_t offset = 0x1000; + + // Add normal symbol function: Let's say this could be symbol from hand written assembly. + this->InitSym(&sym, 0x1000, 0x500, 0x100); + this->memory_.SetMemory(offset, &sym, sizeof(sym)); + offset += sizeof(sym); + + // And zero-sized symbol: A programmer might do that to label the end of assembly method. + // This might be a challenge for booking since both symbols end at the same address. + this->InitSym(&sym, 0x1500, 0x000, 0x200); + this->memory_.SetMemory(offset, &sym, sizeof(sym)); + offset += sizeof(sym); + + std::string fake_name; + fake_name = "entry"; + this->memory_.SetMemory(0xa100, fake_name.c_str(), fake_name.size() + 1); + fake_name = "entry_end"; + this->memory_.SetMemory(0xa200, fake_name.c_str(), fake_name.size() + 1); + + SharedString name; + uint64_t func_offset; + ASSERT_TRUE(symbols.GetName<TypeParam>(0x1250, &this->memory_, &name, &func_offset)); + ASSERT_EQ("entry", name); + ASSERT_EQ(0x250U, func_offset); +} + TYPED_TEST_P(SymbolsTest, get_global) { uint64_t start_offset = 0x1000; uint64_t str_offset = 0xa000; @@ -377,7 +407,7 @@ TYPED_TEST_P(SymbolsTest, get_global) { REGISTER_TYPED_TEST_SUITE_P(SymbolsTest, function_bounds_check, no_symbol, multiple_entries, multiple_entries_nonstandard_size, symtab_value_out_of_bounds, - symtab_read_cached, get_global); + symtab_read_cached, get_global, symtab_end_marker); typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes; INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, SymbolsTest, SymbolsTestTypes); |