From 174639b7f06ec9e5f09dfa7f59dc5b62d2940fc6 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 16 May 2019 17:18:25 +0200 Subject: [PATCH] Kernel: Symbolicate userspace backtraces using ELFLoader. Stash away the ELFLoader used to load an executable in Process so we can use it for symbolicating userspace addresses later on. This will make debugging userspace programs a lot nicer. :^) --- Kernel/ELF/ELFImage.h | 2 +- Kernel/ELF/ELFLoader.cpp | 31 ++++++++++++++++++++++++++++--- Kernel/ELF/ELFLoader.h | 8 ++++++++ Kernel/KSyms.cpp | 7 ++++++- Kernel/Process.cpp | 15 +++++++++------ Kernel/Process.h | 4 ++++ 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Kernel/ELF/ELFImage.h b/Kernel/ELF/ELFImage.h index 7ad336fa9d..4574f4d0fd 100644 --- a/Kernel/ELF/ELFImage.h +++ b/Kernel/ELF/ELFImage.h @@ -212,7 +212,7 @@ template inline void ELFImage::for_each_symbol(F func) const { for (unsigned i = 0; i < symbol_count(); ++i) { - if (!func(symbol(i))) + if (func(symbol(i)) == IterationDecision::Abort) break; } } diff --git a/Kernel/ELF/ELFLoader.cpp b/Kernel/ELF/ELFLoader.cpp index 10544be44d..85a863b761 100644 --- a/Kernel/ELF/ELFLoader.cpp +++ b/Kernel/ELF/ELFLoader.cpp @@ -1,5 +1,6 @@ #include "ELFLoader.h" #include +#include //#define ELFLOADER_DEBUG //#define SUPPORT_RELOCATIONS @@ -162,9 +163,9 @@ char* ELFLoader::symbol_ptr(const char* name) char* found_ptr = nullptr; m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) { if (symbol.type() != STT_FUNC) - return true; + return IterationDecision::Continue; if (strcmp(symbol.name(), name)) - return true; + return IterationDecision::Continue; if (m_image.is_executable()) found_ptr = (char*)symbol.value(); #ifdef SUPPORT_RELOCATIONS @@ -173,7 +174,31 @@ char* ELFLoader::symbol_ptr(const char* name) #endif else ASSERT_NOT_REACHED(); - return false; + return IterationDecision::Abort; }); return found_ptr; } + +String ELFLoader::symbolicate(dword address) const +{ + if (m_sorted_symbols.is_empty()) { + m_sorted_symbols.ensure_capacity(m_image.symbol_count()); + m_image.for_each_symbol([this] (auto& symbol) { + m_sorted_symbols.append({ symbol.value(), symbol.name() }); + return IterationDecision::Continue; + }); + quick_sort(m_sorted_symbols.begin(), m_sorted_symbols.end(), [] (auto& a, auto& b) { + return a.address < b.address; + }); + } + + for (int i = 0; i < m_sorted_symbols.size(); ++i) { + if (m_sorted_symbols[i].address > address) { + if (i == 0) + return "!!"; + auto& symbol = m_sorted_symbols[i - 1]; + return String::format("%s +%u", symbol.name, address - symbol.address); + } + } + return "??"; +} diff --git a/Kernel/ELF/ELFLoader.h b/Kernel/ELF/ELFLoader.h index 25f47bce45..957185b76e 100644 --- a/Kernel/ELF/ELFLoader.h +++ b/Kernel/ELF/ELFLoader.h @@ -18,6 +18,8 @@ public: char* symbol_ptr(const char* name); LinearAddress entry() const { return m_image.entry(); } + String symbolicate(dword address) const; + private: bool layout(); bool perform_relocations(); @@ -39,5 +41,11 @@ private: ELFImage m_image; HashMap m_sections; + + struct SortedSymbol { + dword address; + const char* name; + }; + mutable Vector m_sorted_symbols; }; diff --git a/Kernel/KSyms.cpp b/Kernel/KSyms.cpp index 16c4fc538f..1dc7830a3b 100644 --- a/Kernel/KSyms.cpp +++ b/Kernel/KSyms.cpp @@ -2,6 +2,7 @@ #include "Process.h" #include "Scheduler.h" #include +#include static KSym* s_ksyms; dword ksym_lowest_address; @@ -114,7 +115,11 @@ static void load_ksyms_from_data(const ByteBuffer& buffer) if (!symbol.address) break; if (!symbol.ksym) { - dbgprintf("%p\n", symbol.address); + if (current->process().elf_loader()) { + dbgprintf("%p %s\n", symbol.address, current->process().elf_loader()->symbolicate(symbol.address).characters()); + } else { + dbgprintf("%p (no ELF loader for process)\n", symbol.address); + } continue; } unsigned offset = symbol.address - symbol.ksym->address; diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 98be49edf6..c6e8ea4949 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -327,19 +327,20 @@ int Process::do_exec(String path, Vector arguments, Vector envir bool success = region->page_in(); ASSERT(success); } + OwnPtr loader; { // Okay, here comes the sleight of hand, pay close attention.. auto old_regions = move(m_regions); m_regions.append(*region); - ELFLoader loader(region->laddr().as_ptr()); - loader.map_section_hook = [&] (LinearAddress laddr, size_t size, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable, const String& name) { + loader = make(region->laddr().as_ptr()); + loader->map_section_hook = [&] (LinearAddress laddr, size_t size, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable, const String& name) { ASSERT(size); ASSERT(alignment == PAGE_SIZE); size = ceil_div(size, PAGE_SIZE) * PAGE_SIZE; (void) allocate_region_with_vmo(laddr, size, vmo.copy_ref(), offset_in_image, String(name), is_readable, is_writable); return laddr.as_ptr(); }; - loader.alloc_section_hook = [&] (LinearAddress laddr, size_t size, size_t alignment, bool is_readable, bool is_writable, const String& name) { + loader->alloc_section_hook = [&] (LinearAddress laddr, size_t size, size_t alignment, bool is_readable, bool is_writable, const String& name) { ASSERT(size); ASSERT(alignment == PAGE_SIZE); size += laddr.get() & 0xfff; @@ -348,8 +349,8 @@ int Process::do_exec(String path, Vector arguments, Vector envir (void) allocate_region(laddr, size, String(name), is_readable, is_writable); return laddr.as_ptr(); }; - bool success = loader.load(); - if (!success || !loader.entry().get()) { + bool success = loader->load(); + if (!success || !loader->entry().get()) { m_page_directory = move(old_page_directory); // FIXME: RAII this somehow instead. ASSERT(¤t->process() == this); @@ -359,9 +360,11 @@ int Process::do_exec(String path, Vector arguments, Vector envir return -ENOEXEC; } - entry_eip = loader.entry().get(); + entry_eip = loader->entry().get(); } + m_elf_loader = move(loader); + current->m_kernel_stack_for_signal_handler_region = nullptr; current->m_signal_stack_user_region = nullptr; current->set_default_signal_dispositions(); diff --git a/Kernel/Process.h b/Kernel/Process.h index 613c003ff7..a158ccd460 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -14,6 +14,7 @@ #include #include +class ELFLoader; class FileDescriptor; class PageDirectory; class Region; @@ -248,6 +249,8 @@ public: unsigned syscall_count() const { return m_syscall_count; } void did_syscall() { ++m_syscall_count; } + const ELFLoader* elf_loader() const { return m_elf_loader.ptr(); } + private: friend class MemoryManager; friend class Scheduler; @@ -327,6 +330,7 @@ private: unsigned m_syscall_count { 0 }; RetainPtr m_tracer; + OwnPtr m_elf_loader; Lock m_big_lock { "Process" }; };