[kernel] Use symbol table in stack traces

Now using the symbol table built by build_symbol_table.py in the kernel
when printing stack traces.
This commit is contained in:
2020-08-09 17:27:51 -07:00
parent 0d94776c46
commit bbb9aae198
12 changed files with 137 additions and 12 deletions

View File

@@ -15,6 +15,7 @@ source = "../assets/fonts/tamsyn8x16r.psf"
[[files]] [[files]]
dest = "symbol_table.dat" dest = "symbol_table.dat"
source = "symbol_table.dat" source = "symbol_table.dat"
symbols = true
[[files]] [[files]]
dest = "nulldrv1" dest = "nulldrv1"

View File

@@ -47,6 +47,7 @@ modules:
- src/kernel/screen.cpp - src/kernel/screen.cpp
- src/kernel/serial.cpp - src/kernel/serial.cpp
- src/kernel/stack_cache.cpp - src/kernel/stack_cache.cpp
- src/kernel/symbol_table.cpp
- src/kernel/syscall.cpp - src/kernel/syscall.cpp
- src/kernel/syscall.s - src/kernel/syscall.s
- src/kernel/syscalls/channel.cpp - src/kernel/syscalls/channel.cpp

View File

@@ -5,6 +5,7 @@
#include "objects/process.h" #include "objects/process.h"
#include "objects/thread.h" #include "objects/thread.h"
#include "page_manager.h" #include "page_manager.h"
#include "symbol_table.h"
size_t __counter_syscall_enter = 0; size_t __counter_syscall_enter = 0;
size_t __counter_syscall_sysret = 0; size_t __counter_syscall_sysret = 0;
@@ -59,14 +60,26 @@ void
print_stacktrace(int skip) print_stacktrace(int skip)
{ {
console *cons = console::get(); console *cons = console::get();
symbol_table *syms = symbol_table::get();
frame *fp = nullptr; frame *fp = nullptr;
int fi = -skip; int fi = -skip;
__asm__ __volatile__ ( "mov %%rbp, %0" : "=r" (fp) ); __asm__ __volatile__ ( "mov %%rbp, %0" : "=r" (fp) );
while (fp && fp->return_addr) { while (fp && fp->return_addr) {
if (fi++ >= 0) if (fi++ >= 0) {
cons->printf(" frame %2d: %lx\n", fi-1, fp->return_addr); const symbol_table::entry *e = syms ? syms->find_symbol(fp->return_addr) : nullptr;
const char *name = e ? e->name : "";
cons->printf(" frame %2d:", fi-1);
cons->set_color(5);
cons->printf(" %016llx", fp->return_addr);
cons->set_color();
cons->set_color(6);
cons->printf(" %s\n", name);
cons->set_color();
}
fp = fp->prev; fp = fp->prev;
} }
} }

View File

@@ -22,6 +22,7 @@
#include "page_manager.h" #include "page_manager.h"
#include "scheduler.h" #include "scheduler.h"
#include "serial.h" #include "serial.h"
#include "symbol_table.h"
#include "syscall.h" #include "syscall.h"
extern "C" { extern "C" {
@@ -121,8 +122,11 @@ kernel_main(args::header *header)
initrd::disk &ird = initrds.emplace(mod.location); initrd::disk &ird = initrds.emplace(mod.location);
log::info(logs::boot, "initrd loaded with %d files.", ird.files().count()); log::info(logs::boot, "initrd loaded with %d files.", ird.files().count());
for (auto &f : ird.files()) for (auto &f : ird.files()) {
log::info(logs::boot, " %s%s (%d bytes).", f.executable() ? "*" : "", f.name(), f.size()); char type = f.executable() ? '*' :
f.symbols() ? '+' : ' ';
log::info(logs::boot, " %c%s (%d bytes).", type, f.name(), f.size());
}
} }
/* /*
@@ -180,14 +184,16 @@ kernel_main(args::header *header)
for (auto &ird : initrds) { for (auto &ird : initrds) {
for (auto &f : ird.files()) { for (auto &f : ird.files()) {
if (f.executable()) if (f.executable()) {
sched->load_process(f.name(), f.data(), f.size()); sched->load_process(f.name(), f.data(), f.size());
} else if (f.symbols()) {
new symbol_table {f.data(), f.size()};
}
} }
} }
log::info(logs::objs, "Testing object system:");
/* /*
log::info(logs::objs, "Testing object system:");
test_observer obs1("event"); test_observer obs1("event");
test_observer obs2("no handles"); test_observer obs2("no handles");
{ {

View File

@@ -0,0 +1,49 @@
#include "kutil/assert.h"
#include "kutil/memory.h"
#include "log.h"
#include "symbol_table.h"
symbol_table * symbol_table::s_instance = nullptr;
symbol_table::symbol_table(const void *data, size_t size)
{
m_data = kutil::kalloc(size);
kassert(m_data, "Failed to allocate for symbol table");
kutil::memcpy(m_data, data, size);
uint64_t *values = reinterpret_cast<uint64_t*>(m_data);
m_entries = *values++;
m_index = reinterpret_cast<entry*>(values);
for (size_t i = 0; i < m_entries; ++i) {
uint64_t offset = reinterpret_cast<uint64_t>(m_index[i].name);
m_index[i].name = reinterpret_cast<char*>(m_data) + offset;
}
if (!s_instance)
s_instance = this;
log::info(logs::boot, "Loaded %d symbol table entries at %llx", m_entries, m_data);
}
symbol_table::~symbol_table()
{
kutil::kfree(m_data);
}
const symbol_table::entry *
symbol_table::find_symbol(uintptr_t addr) const
{
if (!m_entries)
return nullptr;
// TODO: binary search
for (size_t i = 0; i < m_entries; ++i) {
if (m_index[i].address > addr) {
return i ? &m_index[i - 1] : nullptr;
}
}
return &m_index[m_entries - 1];
}

34
src/kernel/symbol_table.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
class symbol_table
{
public:
struct entry
{
uintptr_t address;
char *name;
};
static symbol_table * get() { return s_instance; }
/// Constructor.
/// \arg data Pointer to the start of the symbol_table data.
/// \arg size Size of the data, in bytes
symbol_table(const void *data, size_t size);
~symbol_table();
/// Find the closest symbol address before the given address
/// \args addr Address to search for
/// \returns Actual address of the symbol
const entry * find_symbol(uintptr_t addr) const;
private:
size_t m_entries;
entry *m_index;
void *m_data;
static symbol_table *s_instance;
};

View File

@@ -21,7 +21,8 @@ struct disk_header
enum class file_flags : uint16_t enum class file_flags : uint16_t
{ {
executable = 0x01 executable = 0x01,
symbols = 0x02
}; };
struct file_header struct file_header

View File

@@ -36,6 +36,9 @@ public:
/// Whether this file is an executable /// Whether this file is an executable
bool executable() const; bool executable() const;
/// Whether this file is a symbol table
bool symbols() const;
private: private:
const file_header *m_header; const file_header *m_header;
void const *m_data; void const *m_data;

View File

@@ -22,6 +22,11 @@ file::executable() const {
return bitfield_has(m_header->flags, file_flags::executable); return bitfield_has(m_header->flags, file_flags::executable);
} }
bool
file::symbols() const {
return bitfield_has(m_header->flags, file_flags::symbols);
}
disk::disk(const void *start) disk::disk(const void *start)
{ {

View File

@@ -1,10 +1,12 @@
#include "entry.h" #include "entry.h"
entry::entry(const std::string &in, const std::string &out, bool executable) : entry::entry(const std::string &in, const std::string &out,
bool executable, bool symbols) :
m_in(in), m_in(in),
m_out(out), m_out(out),
m_file(in, std::ios_base::binary), m_file(in, std::ios_base::binary),
m_exec(executable) m_exec(executable),
m_syms(symbols)
{ {
m_file.seekg(0, std::ios_base::end); m_file.seekg(0, std::ios_base::end);
m_size = m_file.tellg(); m_size = m_file.tellg();

View File

@@ -5,13 +5,18 @@
class entry class entry
{ {
public: public:
entry(const std::string &in, const std::string &out, bool executable = false); entry(
const std::string &in,
const std::string &out,
bool executable = false,
bool symbols = false);
inline const std::string & in() const { return m_in; } inline const std::string & in() const { return m_in; }
inline const std::string & out() const { return m_out; } inline const std::string & out() const { return m_out; }
inline const std::ifstream & file() const { return m_file; } inline const std::ifstream & file() const { return m_file; }
inline bool executable() const { return m_exec; } inline bool executable() const { return m_exec; }
inline bool symbols() const { return m_syms; }
inline size_t size() const { return m_size; } inline size_t size() const { return m_size; }
inline bool good() const { return m_file.good(); } inline bool good() const { return m_file.good(); }
@@ -21,5 +26,6 @@ private:
std::ifstream m_file; std::ifstream m_file;
size_t m_size; size_t m_size;
bool m_exec; bool m_exec;
bool m_syms;
}; };

View File

@@ -44,8 +44,9 @@ int main(int argc, char **argv)
} }
auto exec = file->get_as<bool>("executable").value_or(false); auto exec = file->get_as<bool>("executable").value_or(false);
auto syms = file->get_as<bool>("symbols").value_or(false);
entries.emplace_back(*source, *dest, exec); entries.emplace_back(*source, *dest, exec, syms);
const entry &e = entries.back(); const entry &e = entries.back();
if (!e.good()) { if (!e.good()) {
@@ -96,6 +97,9 @@ int main(int argc, char **argv)
if (e.executable()) if (e.executable())
fheader.flags |= initrd::file_flags::executable; fheader.flags |= initrd::file_flags::executable;
if (e.symbols())
fheader.flags |= initrd::file_flags::symbols;
out.write( out.write(
reinterpret_cast<const char *>(&fheader), reinterpret_cast<const char *>(&fheader),
sizeof(fheader)); sizeof(fheader));