From d89858f42ab78aee60842bc3c71f09d4594572d1 Mon Sep 17 00:00:00 2001 From: Itamar Date: Sat, 14 Nov 2020 12:13:59 +0200 Subject: [PATCH] Profiler: Symbolicate samples using coredump file --- DevTools/Profiler/CMakeLists.txt | 2 +- DevTools/Profiler/Profile.cpp | 77 +++++++++++++++++++++++++++++--- DevTools/Profiler/main.cpp | 4 ++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/DevTools/Profiler/CMakeLists.txt b/DevTools/Profiler/CMakeLists.txt index 9e224d3ae4..a5d78d7ae6 100644 --- a/DevTools/Profiler/CMakeLists.txt +++ b/DevTools/Profiler/CMakeLists.txt @@ -7,4 +7,4 @@ set(SOURCES ) serenity_bin(Profiler) -target_link_libraries(Profiler LibGUI LibX86) +target_link_libraries(Profiler LibGUI LibX86 LibCoreDump) diff --git a/DevTools/Profiler/Profile.cpp b/DevTools/Profiler/Profile.cpp index 8e5a7892f1..ee458c2b75 100644 --- a/DevTools/Profiler/Profile.cpp +++ b/DevTools/Profiler/Profile.cpp @@ -32,8 +32,10 @@ #include #include #include +#include #include #include +#include static void sort_profile_nodes(Vector>& nodes) { @@ -45,6 +47,71 @@ static void sort_profile_nodes(Vector>& nodes) child->sort_children(); } +static String object_name(StringView memory_region_name) +{ + if (memory_region_name.contains("Loader.so")) + return "Loader.so"; + if (!memory_region_name.contains(":")) + return {}; + return memory_region_name.substring_view(0, memory_region_name.find_first_of(":").value()).to_string(); +} + +struct CachedLibData { + OwnPtr file; + NonnullRefPtr lib_elf; +}; + +static String symbolicate(FlatPtr eip, const ELF::Core::MemoryRegionInfo* region, u32& offset) +{ + + static HashMap> cached_libs; + + StringView region_name { region->region_name }; + + auto name = object_name(region_name); + + String path; + if (name.contains(".so")) + path = String::format("/usr/lib/%s", name.characters()); + else { + path = name; + } + + struct stat st; + if (stat(path.characters(), &st)) { + return {}; + } + + if (!cached_libs.contains(path)) { + auto lib_file = make(path); + if (!lib_file->is_valid()) + return {}; + auto loader = ELF::Loader::create((const u8*)lib_file->data(), lib_file->size()); + cached_libs.set(path, make(move(lib_file), loader)); + } + + auto lib_data = cached_libs.get(path).value(); + + return String::format("[%s] %s", name.characters(), lib_data->lib_elf->symbolicate(eip - region->region_start, &offset).characters()); +} + +static String symbolicate_from_coredump(CoreDumpReader& coredump, u32 ptr, u32& offset) +{ + (void)offset; + auto* region = coredump.region_containing((FlatPtr)ptr); + if (!region) { + dbgln("did not find region for eip: {:p}", ptr); + return "??"; + } + + auto name = symbolicate((FlatPtr)ptr, region, offset); + if (name.is_null()) { + dbgln("could not symbolicate: {:p}", ptr); + return "??"; + } + return name; +} + Profile::Profile(String executable_path, Vector events) : m_executable_path(move(executable_path)) , m_events(move(events)) @@ -215,14 +282,12 @@ OwnPtr Profile::load_from_perfcore_file(const StringView& path) auto& object = json.value().as_object(); auto executable_path = object.get("executable").to_string(); - MappedFile elf_file(executable_path); - if (!elf_file.is_valid()) { - warnln("Unable to open executable '{}' for symbolication.", executable_path); + auto coredump = CoreDumpReader::create(String::format("/tmp/profiler_coredumps/%d", object.get("pid").as_u32())); + if (!coredump) { + warnln("Could not open coredump"); return nullptr; } - auto elf_loader = ELF::Loader::create(static_cast(elf_file.data()), elf_file.size()); - MappedFile kernel_elf_file("/boot/Kernel"); RefPtr kernel_elf_loader; if (kernel_elf_file.is_valid()) @@ -267,7 +332,7 @@ OwnPtr Profile::load_from_perfcore_file(const StringView& path) symbol = "??"; } } else { - symbol = elf_loader->symbolicate(ptr, &offset); + symbol = symbolicate_from_coredump(*coredump, ptr, offset); } event.frames.append({ symbol, ptr, offset }); diff --git a/DevTools/Profiler/main.cpp b/DevTools/Profiler/main.cpp index 5181a95316..90d505ab0a 100644 --- a/DevTools/Profiler/main.cpp +++ b/DevTools/Profiler/main.cpp @@ -198,5 +198,9 @@ bool generate_profile(pid_t pid) if (!prompt_to_stop_profiling()) return false; + if (profiling_disable(pid) < 0) { + return false; + } + return true; }