1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 13:15:07 +00:00

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. :^)
This commit is contained in:
Andreas Kling 2019-05-16 17:18:25 +02:00
parent e20aecefba
commit 174639b7f0
6 changed files with 56 additions and 11 deletions

View file

@ -212,7 +212,7 @@ template<typename F>
inline void ELFImage::for_each_symbol(F func) const inline void ELFImage::for_each_symbol(F func) const
{ {
for (unsigned i = 0; i < symbol_count(); ++i) { for (unsigned i = 0; i < symbol_count(); ++i) {
if (!func(symbol(i))) if (func(symbol(i)) == IterationDecision::Abort)
break; break;
} }
} }

View file

@ -1,5 +1,6 @@
#include "ELFLoader.h" #include "ELFLoader.h"
#include <AK/kstdio.h> #include <AK/kstdio.h>
#include <AK/QuickSort.h>
//#define ELFLOADER_DEBUG //#define ELFLOADER_DEBUG
//#define SUPPORT_RELOCATIONS //#define SUPPORT_RELOCATIONS
@ -162,9 +163,9 @@ char* ELFLoader::symbol_ptr(const char* name)
char* found_ptr = nullptr; char* found_ptr = nullptr;
m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) { m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
if (symbol.type() != STT_FUNC) if (symbol.type() != STT_FUNC)
return true; return IterationDecision::Continue;
if (strcmp(symbol.name(), name)) if (strcmp(symbol.name(), name))
return true; return IterationDecision::Continue;
if (m_image.is_executable()) if (m_image.is_executable())
found_ptr = (char*)symbol.value(); found_ptr = (char*)symbol.value();
#ifdef SUPPORT_RELOCATIONS #ifdef SUPPORT_RELOCATIONS
@ -173,7 +174,31 @@ char* ELFLoader::symbol_ptr(const char* name)
#endif #endif
else else
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
return false; return IterationDecision::Abort;
}); });
return found_ptr; 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 "??";
}

View file

@ -18,6 +18,8 @@ public:
char* symbol_ptr(const char* name); char* symbol_ptr(const char* name);
LinearAddress entry() const { return m_image.entry(); } LinearAddress entry() const { return m_image.entry(); }
String symbolicate(dword address) const;
private: private:
bool layout(); bool layout();
bool perform_relocations(); bool perform_relocations();
@ -39,5 +41,11 @@ private:
ELFImage m_image; ELFImage m_image;
HashMap<String, char*> m_sections; HashMap<String, char*> m_sections;
struct SortedSymbol {
dword address;
const char* name;
};
mutable Vector<SortedSymbol> m_sorted_symbols;
}; };

View file

@ -2,6 +2,7 @@
#include "Process.h" #include "Process.h"
#include "Scheduler.h" #include "Scheduler.h"
#include <Kernel/FileSystem/FileDescriptor.h> #include <Kernel/FileSystem/FileDescriptor.h>
#include <Kernel/ELF/ELFLoader.h>
static KSym* s_ksyms; static KSym* s_ksyms;
dword ksym_lowest_address; dword ksym_lowest_address;
@ -114,7 +115,11 @@ static void load_ksyms_from_data(const ByteBuffer& buffer)
if (!symbol.address) if (!symbol.address)
break; break;
if (!symbol.ksym) { 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; continue;
} }
unsigned offset = symbol.address - symbol.ksym->address; unsigned offset = symbol.address - symbol.ksym->address;

View file

@ -327,19 +327,20 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
bool success = region->page_in(); bool success = region->page_in();
ASSERT(success); ASSERT(success);
} }
OwnPtr<ELFLoader> loader;
{ {
// Okay, here comes the sleight of hand, pay close attention.. // Okay, here comes the sleight of hand, pay close attention..
auto old_regions = move(m_regions); auto old_regions = move(m_regions);
m_regions.append(*region); m_regions.append(*region);
ELFLoader loader(region->laddr().as_ptr()); loader = make<ELFLoader>(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->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(size);
ASSERT(alignment == PAGE_SIZE); ASSERT(alignment == PAGE_SIZE);
size = ceil_div(size, PAGE_SIZE) * 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); (void) allocate_region_with_vmo(laddr, size, vmo.copy_ref(), offset_in_image, String(name), is_readable, is_writable);
return laddr.as_ptr(); 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(size);
ASSERT(alignment == PAGE_SIZE); ASSERT(alignment == PAGE_SIZE);
size += laddr.get() & 0xfff; size += laddr.get() & 0xfff;
@ -348,8 +349,8 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
(void) allocate_region(laddr, size, String(name), is_readable, is_writable); (void) allocate_region(laddr, size, String(name), is_readable, is_writable);
return laddr.as_ptr(); return laddr.as_ptr();
}; };
bool success = loader.load(); bool success = loader->load();
if (!success || !loader.entry().get()) { if (!success || !loader->entry().get()) {
m_page_directory = move(old_page_directory); m_page_directory = move(old_page_directory);
// FIXME: RAII this somehow instead. // FIXME: RAII this somehow instead.
ASSERT(&current->process() == this); ASSERT(&current->process() == this);
@ -359,9 +360,11 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
return -ENOEXEC; 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_kernel_stack_for_signal_handler_region = nullptr;
current->m_signal_stack_user_region = nullptr; current->m_signal_stack_user_region = nullptr;
current->set_default_signal_dispositions(); current->set_default_signal_dispositions();

View file

@ -14,6 +14,7 @@
#include <Kernel/Thread.h> #include <Kernel/Thread.h>
#include <Kernel/Lock.h> #include <Kernel/Lock.h>
class ELFLoader;
class FileDescriptor; class FileDescriptor;
class PageDirectory; class PageDirectory;
class Region; class Region;
@ -248,6 +249,8 @@ public:
unsigned syscall_count() const { return m_syscall_count; } unsigned syscall_count() const { return m_syscall_count; }
void did_syscall() { ++m_syscall_count; } void did_syscall() { ++m_syscall_count; }
const ELFLoader* elf_loader() const { return m_elf_loader.ptr(); }
private: private:
friend class MemoryManager; friend class MemoryManager;
friend class Scheduler; friend class Scheduler;
@ -327,6 +330,7 @@ private:
unsigned m_syscall_count { 0 }; unsigned m_syscall_count { 0 };
RetainPtr<ProcessTracer> m_tracer; RetainPtr<ProcessTracer> m_tracer;
OwnPtr<ELFLoader> m_elf_loader;
Lock m_big_lock { "Process" }; Lock m_big_lock { "Process" };
}; };