Loading libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -191,6 +191,7 @@ cc_test { "tests/LocalUnwinderTest.cpp", "tests/LogFake.cpp", "tests/MapInfoCreateMemoryTest.cpp", "tests/MapInfoGetBuildIDTest.cpp", "tests/MapInfoGetElfTest.cpp", "tests/MapInfoGetLoadBiasTest.cpp", "tests/MapInfoTest.cpp", Loading Loading @@ -343,6 +344,7 @@ cc_benchmark { ], shared_libs: [ "libbase", "libunwindstack", ], } Loading libunwindstack/Elf.cpp +23 −2 Original line number Diff line number Diff line Loading @@ -140,8 +140,11 @@ bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) { return true; } bool Elf::GetBuildID(std::string* build_id) { return valid_ && interface_->GetBuildID(build_id); std::string Elf::GetBuildID() { if (!valid_) { return ""; } return interface_->GetBuildID(); } void Elf::GetLastError(ErrorData* data) { Loading Loading @@ -384,4 +387,22 @@ bool Elf::CacheGet(MapInfo* info) { return false; } std::string Elf::GetBuildID(Memory* memory) { if (!IsValidElf(memory)) { return ""; } uint8_t class_type; if (!memory->Read(EI_CLASS, &class_type, 1)) { return ""; } if (class_type == ELFCLASS32) { return ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(memory); } else if (class_type == ELFCLASS64) { return ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(memory); } return ""; } } // namespace unwindstack libunwindstack/ElfInterface.cpp +118 −14 Original line number Diff line number Diff line Loading @@ -238,31 +238,31 @@ void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) } template <typename NhdrType> bool ElfInterface::ReadBuildID(std::string* build_id) { std::string ElfInterface::ReadBuildID() { // Ensure there is no overflow in any of the calulations below. uint64_t tmp; if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) { return false; return ""; } uint64_t offset = 0; while (offset < gnu_build_id_size_) { if (gnu_build_id_size_ - offset < sizeof(NhdrType)) { return false; return ""; } NhdrType hdr; if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) { return false; return ""; } offset += sizeof(hdr); if (gnu_build_id_size_ - offset < hdr.n_namesz) { return false; return ""; } if (hdr.n_namesz > 0) { std::string name(hdr.n_namesz, '\0'); if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) { return false; return ""; } // Trim trailing \0 as GNU is stored as a C string in the ELF file. Loading @@ -273,18 +273,20 @@ bool ElfInterface::ReadBuildID(std::string* build_id) { offset += (hdr.n_namesz + 3) & ~3; if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) { if (gnu_build_id_size_ - offset < hdr.n_descsz) { return false; if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) { return ""; } std::string build_id(hdr.n_descsz - 1, '\0'); if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) { return build_id; } build_id->resize(hdr.n_descsz); return memory_->ReadFully(gnu_build_id_offset_ + offset, &(*build_id)[0], hdr.n_descsz); return ""; } } // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. offset += (hdr.n_descsz + 3) & ~3; } return false; return ""; } template <typename EhdrType, typename ShdrType> Loading Loading @@ -536,6 +538,103 @@ void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) { *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum; } template <typename EhdrType, typename ShdrType> bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_id_size) { EhdrType ehdr; if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) { return false; } uint64_t offset = ehdr.e_shoff; uint64_t sec_offset; uint64_t sec_size; ShdrType shdr; if (ehdr.e_shstrndx >= ehdr.e_shnum) { return false; } uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize; if (!memory->ReadFully(sh_offset, &shdr, sizeof(shdr))) { return false; } sec_offset = shdr.sh_offset; sec_size = shdr.sh_size; // Skip the first header, it's always going to be NULL. offset += ehdr.e_shentsize; for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { if (!memory->ReadFully(offset, &shdr, sizeof(shdr))) { return false; } std::string name; if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size && memory->ReadString(sec_offset + shdr.sh_name, &name) && name == ".note.gnu.build-id") { *build_id_offset = shdr.sh_offset; *build_id_size = shdr.sh_size; return true; } } return false; } template <typename EhdrType, typename ShdrType, typename NhdrType> std::string ElfInterface::ReadBuildIDFromMemory(Memory* memory) { uint64_t note_offset; uint64_t note_size; if (!GetBuildIDInfo<EhdrType, ShdrType>(memory, ¬e_offset, ¬e_size)) { return ""; } // Ensure there is no overflow in any of the calculations below. uint64_t tmp; if (__builtin_add_overflow(note_offset, note_size, &tmp)) { return ""; } uint64_t offset = 0; while (offset < note_size) { if (note_size - offset < sizeof(NhdrType)) { return ""; } NhdrType hdr; if (!memory->ReadFully(note_offset + offset, &hdr, sizeof(hdr))) { return ""; } offset += sizeof(hdr); if (note_size - offset < hdr.n_namesz) { return ""; } if (hdr.n_namesz > 0) { std::string name(hdr.n_namesz, '\0'); if (!memory->ReadFully(note_offset + offset, &(name[0]), hdr.n_namesz)) { return ""; } // Trim trailing \0 as GNU is stored as a C string in the ELF file. if (name.back() == '\0') name.resize(name.size() - 1); // Align hdr.n_namesz to next power multiple of 4. See man 5 elf. offset += (hdr.n_namesz + 3) & ~3; if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) { if (note_size - offset < hdr.n_descsz || hdr.n_descsz == 0) { return ""; } std::string build_id(hdr.n_descsz - 1, '\0'); if (memory->ReadFully(note_offset + offset, &build_id[0], hdr.n_descsz)) { return build_id; } return ""; } } // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. offset += (hdr.n_descsz + 3) & ~3; } return ""; } // Instantiate all of the needed template functions. template void ElfInterface::InitHeadersWithTemplate<uint32_t>(uint64_t); template void ElfInterface::InitHeadersWithTemplate<uint64_t>(uint64_t); Loading @@ -551,8 +650,8 @@ template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&); template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&); template bool ElfInterface::ReadBuildID<Elf32_Nhdr>(std::string*); template bool ElfInterface::ReadBuildID<Elf64_Nhdr>(std::string*); template std::string ElfInterface::ReadBuildID<Elf32_Nhdr>(); template std::string ElfInterface::ReadBuildID<Elf64_Nhdr>(); template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); Loading @@ -571,4 +670,9 @@ template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t template uint64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*); template uint64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*); template std::string ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>( Memory*); template std::string ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>( Memory*); } // namespace unwindstack libunwindstack/MapInfo.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,10 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { } } if (process_memory == nullptr) { return nullptr; } // Need to verify that this elf is valid. It's possible that // only part of the elf file to be mapped into memory is in the executable // map. In this case, there will be another read-only map that includes the Loading Loading @@ -263,4 +267,48 @@ uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) { return cur_load_bias; } MapInfo::~MapInfo() { uintptr_t id = build_id.load(); if (id != 0) { delete reinterpret_cast<std::string*>(id); } } std::string MapInfo::GetBuildID() { uintptr_t id = build_id.load(); if (build_id != 0) { return *reinterpret_cast<std::string*>(id); } // No need to lock, at worst if multiple threads do this at the same // time it should be detected and only one thread should win and // save the data. std::unique_ptr<std::string> cur_build_id(new std::string); // Now need to see if the elf object exists. // Make sure no other thread is trying to add the elf to this map. mutex_.lock(); Elf* elf_obj = elf.get(); mutex_.unlock(); if (elf_obj != nullptr) { *cur_build_id = elf_obj->GetBuildID(); } else { // This will only work if we can get the file associated with this memory. // If this is only available in memory, then the section name information // is not present and we will not be able to find the build id info. std::unique_ptr<Memory> memory(GetFileMemory()); if (memory != nullptr) { *cur_build_id = Elf::GetBuildID(memory.get()); } } id = reinterpret_cast<uintptr_t>(cur_build_id.get()); uintptr_t expected_id = 0; if (build_id.compare_exchange_weak(expected_id, id)) { // Value saved, so make sure the memory is not freed. cur_build_id.release(); } return *reinterpret_cast<std::string*>(id); } } // namespace unwindstack libunwindstack/benchmarks/unwind_benchmarks.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ #include <benchmark/benchmark.h> #include <android-base/strings.h> #include <unwindstack/Elf.h> #include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> Loading Loading @@ -80,4 +83,63 @@ static void BM_cached_unwind(benchmark::State& state) { } BENCHMARK(BM_cached_unwind); static void Initialize(benchmark::State& state, unwindstack::Maps& maps, unwindstack::MapInfo** build_id_map_info) { if (!maps.Parse()) { state.SkipWithError("Failed to parse local maps."); return; } // Find the libc.so share library and use that for benchmark purposes. *build_id_map_info = nullptr; for (unwindstack::MapInfo* map_info : maps) { if (map_info->offset == 0 && map_info->GetBuildID() != "") { *build_id_map_info = map_info; break; } } if (*build_id_map_info == nullptr) { state.SkipWithError("Failed to find a map with a BuildID."); } } static void BM_get_build_id_from_elf(benchmark::State& state) { unwindstack::LocalMaps maps; unwindstack::MapInfo* build_id_map_info; Initialize(state, maps, &build_id_map_info); unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(), unwindstack::Regs::CurrentArch()); if (!elf->valid()) { state.SkipWithError("Cannot get valid elf from map."); } for (auto _ : state) { uintptr_t id = build_id_map_info->build_id; if (id != 0) { delete reinterpret_cast<std::string*>(id); build_id_map_info->build_id = 0; } benchmark::DoNotOptimize(build_id_map_info->GetBuildID()); } } BENCHMARK(BM_get_build_id_from_elf); static void BM_get_build_id_from_file(benchmark::State& state) { unwindstack::LocalMaps maps; unwindstack::MapInfo* build_id_map_info; Initialize(state, maps, &build_id_map_info); for (auto _ : state) { uintptr_t id = build_id_map_info->build_id; if (id != 0) { delete reinterpret_cast<std::string*>(id); build_id_map_info->build_id = 0; } benchmark::DoNotOptimize(build_id_map_info->GetBuildID()); } } BENCHMARK(BM_get_build_id_from_file); BENCHMARK_MAIN(); Loading
libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -191,6 +191,7 @@ cc_test { "tests/LocalUnwinderTest.cpp", "tests/LogFake.cpp", "tests/MapInfoCreateMemoryTest.cpp", "tests/MapInfoGetBuildIDTest.cpp", "tests/MapInfoGetElfTest.cpp", "tests/MapInfoGetLoadBiasTest.cpp", "tests/MapInfoTest.cpp", Loading Loading @@ -343,6 +344,7 @@ cc_benchmark { ], shared_libs: [ "libbase", "libunwindstack", ], } Loading
libunwindstack/Elf.cpp +23 −2 Original line number Diff line number Diff line Loading @@ -140,8 +140,11 @@ bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) { return true; } bool Elf::GetBuildID(std::string* build_id) { return valid_ && interface_->GetBuildID(build_id); std::string Elf::GetBuildID() { if (!valid_) { return ""; } return interface_->GetBuildID(); } void Elf::GetLastError(ErrorData* data) { Loading Loading @@ -384,4 +387,22 @@ bool Elf::CacheGet(MapInfo* info) { return false; } std::string Elf::GetBuildID(Memory* memory) { if (!IsValidElf(memory)) { return ""; } uint8_t class_type; if (!memory->Read(EI_CLASS, &class_type, 1)) { return ""; } if (class_type == ELFCLASS32) { return ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(memory); } else if (class_type == ELFCLASS64) { return ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(memory); } return ""; } } // namespace unwindstack
libunwindstack/ElfInterface.cpp +118 −14 Original line number Diff line number Diff line Loading @@ -238,31 +238,31 @@ void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) } template <typename NhdrType> bool ElfInterface::ReadBuildID(std::string* build_id) { std::string ElfInterface::ReadBuildID() { // Ensure there is no overflow in any of the calulations below. uint64_t tmp; if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) { return false; return ""; } uint64_t offset = 0; while (offset < gnu_build_id_size_) { if (gnu_build_id_size_ - offset < sizeof(NhdrType)) { return false; return ""; } NhdrType hdr; if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) { return false; return ""; } offset += sizeof(hdr); if (gnu_build_id_size_ - offset < hdr.n_namesz) { return false; return ""; } if (hdr.n_namesz > 0) { std::string name(hdr.n_namesz, '\0'); if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) { return false; return ""; } // Trim trailing \0 as GNU is stored as a C string in the ELF file. Loading @@ -273,18 +273,20 @@ bool ElfInterface::ReadBuildID(std::string* build_id) { offset += (hdr.n_namesz + 3) & ~3; if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) { if (gnu_build_id_size_ - offset < hdr.n_descsz) { return false; if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) { return ""; } std::string build_id(hdr.n_descsz - 1, '\0'); if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) { return build_id; } build_id->resize(hdr.n_descsz); return memory_->ReadFully(gnu_build_id_offset_ + offset, &(*build_id)[0], hdr.n_descsz); return ""; } } // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. offset += (hdr.n_descsz + 3) & ~3; } return false; return ""; } template <typename EhdrType, typename ShdrType> Loading Loading @@ -536,6 +538,103 @@ void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) { *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum; } template <typename EhdrType, typename ShdrType> bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_id_size) { EhdrType ehdr; if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) { return false; } uint64_t offset = ehdr.e_shoff; uint64_t sec_offset; uint64_t sec_size; ShdrType shdr; if (ehdr.e_shstrndx >= ehdr.e_shnum) { return false; } uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize; if (!memory->ReadFully(sh_offset, &shdr, sizeof(shdr))) { return false; } sec_offset = shdr.sh_offset; sec_size = shdr.sh_size; // Skip the first header, it's always going to be NULL. offset += ehdr.e_shentsize; for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { if (!memory->ReadFully(offset, &shdr, sizeof(shdr))) { return false; } std::string name; if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size && memory->ReadString(sec_offset + shdr.sh_name, &name) && name == ".note.gnu.build-id") { *build_id_offset = shdr.sh_offset; *build_id_size = shdr.sh_size; return true; } } return false; } template <typename EhdrType, typename ShdrType, typename NhdrType> std::string ElfInterface::ReadBuildIDFromMemory(Memory* memory) { uint64_t note_offset; uint64_t note_size; if (!GetBuildIDInfo<EhdrType, ShdrType>(memory, ¬e_offset, ¬e_size)) { return ""; } // Ensure there is no overflow in any of the calculations below. uint64_t tmp; if (__builtin_add_overflow(note_offset, note_size, &tmp)) { return ""; } uint64_t offset = 0; while (offset < note_size) { if (note_size - offset < sizeof(NhdrType)) { return ""; } NhdrType hdr; if (!memory->ReadFully(note_offset + offset, &hdr, sizeof(hdr))) { return ""; } offset += sizeof(hdr); if (note_size - offset < hdr.n_namesz) { return ""; } if (hdr.n_namesz > 0) { std::string name(hdr.n_namesz, '\0'); if (!memory->ReadFully(note_offset + offset, &(name[0]), hdr.n_namesz)) { return ""; } // Trim trailing \0 as GNU is stored as a C string in the ELF file. if (name.back() == '\0') name.resize(name.size() - 1); // Align hdr.n_namesz to next power multiple of 4. See man 5 elf. offset += (hdr.n_namesz + 3) & ~3; if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) { if (note_size - offset < hdr.n_descsz || hdr.n_descsz == 0) { return ""; } std::string build_id(hdr.n_descsz - 1, '\0'); if (memory->ReadFully(note_offset + offset, &build_id[0], hdr.n_descsz)) { return build_id; } return ""; } } // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. offset += (hdr.n_descsz + 3) & ~3; } return ""; } // Instantiate all of the needed template functions. template void ElfInterface::InitHeadersWithTemplate<uint32_t>(uint64_t); template void ElfInterface::InitHeadersWithTemplate<uint64_t>(uint64_t); Loading @@ -551,8 +650,8 @@ template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&); template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&); template bool ElfInterface::ReadBuildID<Elf32_Nhdr>(std::string*); template bool ElfInterface::ReadBuildID<Elf64_Nhdr>(std::string*); template std::string ElfInterface::ReadBuildID<Elf32_Nhdr>(); template std::string ElfInterface::ReadBuildID<Elf64_Nhdr>(); template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); Loading @@ -571,4 +670,9 @@ template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t template uint64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*); template uint64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*); template std::string ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>( Memory*); template std::string ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>( Memory*); } // namespace unwindstack
libunwindstack/MapInfo.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,10 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { } } if (process_memory == nullptr) { return nullptr; } // Need to verify that this elf is valid. It's possible that // only part of the elf file to be mapped into memory is in the executable // map. In this case, there will be another read-only map that includes the Loading Loading @@ -263,4 +267,48 @@ uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) { return cur_load_bias; } MapInfo::~MapInfo() { uintptr_t id = build_id.load(); if (id != 0) { delete reinterpret_cast<std::string*>(id); } } std::string MapInfo::GetBuildID() { uintptr_t id = build_id.load(); if (build_id != 0) { return *reinterpret_cast<std::string*>(id); } // No need to lock, at worst if multiple threads do this at the same // time it should be detected and only one thread should win and // save the data. std::unique_ptr<std::string> cur_build_id(new std::string); // Now need to see if the elf object exists. // Make sure no other thread is trying to add the elf to this map. mutex_.lock(); Elf* elf_obj = elf.get(); mutex_.unlock(); if (elf_obj != nullptr) { *cur_build_id = elf_obj->GetBuildID(); } else { // This will only work if we can get the file associated with this memory. // If this is only available in memory, then the section name information // is not present and we will not be able to find the build id info. std::unique_ptr<Memory> memory(GetFileMemory()); if (memory != nullptr) { *cur_build_id = Elf::GetBuildID(memory.get()); } } id = reinterpret_cast<uintptr_t>(cur_build_id.get()); uintptr_t expected_id = 0; if (build_id.compare_exchange_weak(expected_id, id)) { // Value saved, so make sure the memory is not freed. cur_build_id.release(); } return *reinterpret_cast<std::string*>(id); } } // namespace unwindstack
libunwindstack/benchmarks/unwind_benchmarks.cpp +62 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ #include <benchmark/benchmark.h> #include <android-base/strings.h> #include <unwindstack/Elf.h> #include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> Loading Loading @@ -80,4 +83,63 @@ static void BM_cached_unwind(benchmark::State& state) { } BENCHMARK(BM_cached_unwind); static void Initialize(benchmark::State& state, unwindstack::Maps& maps, unwindstack::MapInfo** build_id_map_info) { if (!maps.Parse()) { state.SkipWithError("Failed to parse local maps."); return; } // Find the libc.so share library and use that for benchmark purposes. *build_id_map_info = nullptr; for (unwindstack::MapInfo* map_info : maps) { if (map_info->offset == 0 && map_info->GetBuildID() != "") { *build_id_map_info = map_info; break; } } if (*build_id_map_info == nullptr) { state.SkipWithError("Failed to find a map with a BuildID."); } } static void BM_get_build_id_from_elf(benchmark::State& state) { unwindstack::LocalMaps maps; unwindstack::MapInfo* build_id_map_info; Initialize(state, maps, &build_id_map_info); unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(), unwindstack::Regs::CurrentArch()); if (!elf->valid()) { state.SkipWithError("Cannot get valid elf from map."); } for (auto _ : state) { uintptr_t id = build_id_map_info->build_id; if (id != 0) { delete reinterpret_cast<std::string*>(id); build_id_map_info->build_id = 0; } benchmark::DoNotOptimize(build_id_map_info->GetBuildID()); } } BENCHMARK(BM_get_build_id_from_elf); static void BM_get_build_id_from_file(benchmark::State& state) { unwindstack::LocalMaps maps; unwindstack::MapInfo* build_id_map_info; Initialize(state, maps, &build_id_map_info); for (auto _ : state) { uintptr_t id = build_id_map_info->build_id; if (id != 0) { delete reinterpret_cast<std::string*>(id); build_id_map_info->build_id = 0; } benchmark::DoNotOptimize(build_id_map_info->GetBuildID()); } } BENCHMARK(BM_get_build_id_from_file); BENCHMARK_MAIN();