Add caching of build id in MapInfo object.
Change the GetBuildID function to return a std::string.
Added benchmark to check how long it takes to get the build id from
a file versus an elf object.
Added a way to get an elf without passing in a valid process_memory and
added tests for this.
Test: New unit tests.
Change-Id: I3029019767e0181c758d611fe635bc1bf72d6e8e
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index b9d8b3d..f319971 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -146,6 +146,10 @@
}
}
+ 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
@@ -263,4 +267,48 @@
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