Profiler: Symbolicate samples using coredump file
This commit is contained in:
parent
5392f42731
commit
d89858f42a
Notes:
sideshowbarker
2024-07-19 00:50:27 +09:00
Author: https://github.com/itamar8910 Commit: https://github.com/SerenityOS/serenity/commit/d89858f42ab Pull-request: https://github.com/SerenityOS/serenity/pull/3738 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/alimpfard Reviewed-by: https://github.com/awesomekling
3 changed files with 76 additions and 7 deletions
DevTools/Profiler
|
@ -7,4 +7,4 @@ set(SOURCES
|
|||
)
|
||||
|
||||
serenity_bin(Profiler)
|
||||
target_link_libraries(Profiler LibGUI LibX86)
|
||||
target_link_libraries(Profiler LibGUI LibX86 LibCoreDump)
|
||||
|
|
|
@ -32,8 +32,10 @@
|
|||
#include <AK/QuickSort.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCoreDump/CoreDumpReader.h>
|
||||
#include <LibELF/Loader.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static void sort_profile_nodes(Vector<NonnullRefPtr<ProfileNode>>& nodes)
|
||||
{
|
||||
|
@ -45,6 +47,71 @@ static void sort_profile_nodes(Vector<NonnullRefPtr<ProfileNode>>& 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<MappedFile> file;
|
||||
NonnullRefPtr<ELF::Loader> lib_elf;
|
||||
};
|
||||
|
||||
static String symbolicate(FlatPtr eip, const ELF::Core::MemoryRegionInfo* region, u32& offset)
|
||||
{
|
||||
|
||||
static HashMap<String, OwnPtr<CachedLibData>> 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<MappedFile>(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<CachedLibData>(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<Event> events)
|
||||
: m_executable_path(move(executable_path))
|
||||
, m_events(move(events))
|
||||
|
@ -215,14 +282,12 @@ OwnPtr<Profile> 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<const u8*>(elf_file.data()), elf_file.size());
|
||||
|
||||
MappedFile kernel_elf_file("/boot/Kernel");
|
||||
RefPtr<ELF::Loader> kernel_elf_loader;
|
||||
if (kernel_elf_file.is_valid())
|
||||
|
@ -267,7 +332,7 @@ OwnPtr<Profile> 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 });
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue