Symbol tables, references to other mods, dependency checks
This commit is contained in:
parent
4ae2adb6df
commit
887ffb7e53
@ -10,6 +10,7 @@
|
||||
#include "sys/sched.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/syms.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
#define X86_EXCEPTION_DE 0
|
||||
@ -172,7 +173,7 @@ static void exc_dump(int level, struct amd64_exception_frame *frame) {
|
||||
(frame->rflags & X86_FLAGS_TF) ? 'T' : '-');
|
||||
uintptr_t sym_base;
|
||||
const char *sym_name;
|
||||
if (debug_symbol_find(frame->rip, &sym_name, &sym_base) == 0) {
|
||||
if (ksym_find_location(frame->rip, &sym_name, &sym_base) == 0) {
|
||||
debugf(level, " Backtrace:\n");
|
||||
debugf(level, "0: %p <%s + %04x>\n", frame->rip, sym_name, frame->rip - sym_base);
|
||||
debug_backtrace(DEBUG_FATAL, frame->rbp, 1, 10);
|
||||
|
@ -21,14 +21,11 @@
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/syms.h"
|
||||
#include "sys/attr.h"
|
||||
#include "sys/elf.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
__init(test) {
|
||||
*((uint16_t *) 0xB8000) = 'A' | 0x700;
|
||||
}
|
||||
|
||||
static uintptr_t multiboot_info_addr;
|
||||
static struct multiboot_tag_mmap *multiboot_tag_mmap;
|
||||
static struct multiboot_tag_module *multiboot_tag_initrd_module;
|
||||
@ -102,10 +99,6 @@ void kernel_early_init(void) {
|
||||
|
||||
cpuid_init();
|
||||
|
||||
if (multiboot_tag_sections) {
|
||||
debug_symbol_table_multiboot2(multiboot_tag_sections);
|
||||
}
|
||||
|
||||
if (multiboot_tag_cmdline) {
|
||||
// Set kernel command line
|
||||
kinfo("Provided command line: \"%s\"\n", multiboot_tag_cmdline->string);
|
||||
@ -123,6 +116,10 @@ void kernel_early_init(void) {
|
||||
|
||||
amd64_mm_init();
|
||||
|
||||
if (multiboot_tag_sections) {
|
||||
ksym_set_multiboot2(multiboot_tag_sections);
|
||||
}
|
||||
|
||||
if (rs232_avail & (1 << 0)) {
|
||||
rs232_add_tty(0);
|
||||
}
|
||||
|
@ -87,6 +87,8 @@ KERNEL_OBJ=$(O)/arch/amd64/entry.o \
|
||||
$(O)/sys/font/logo.o \
|
||||
$(O)/sys/font/default8x16.psfu.o \
|
||||
$(O)/sys/mod.o \
|
||||
$(O)/sys/hash.o \
|
||||
$(O)/sys/syms.o \
|
||||
$(O)/fs/vfs.o \
|
||||
$(O)/fs/vfs_ops.o \
|
||||
$(O)/fs/vfs_access.o \
|
||||
|
@ -38,12 +38,6 @@
|
||||
#define kfatal(f, ...) debugf(DEBUG_FATAL, "\033[41m" DEBUG_BASE_FMT f "\033[0m", DEBUG_BASE_ARGS, ##__VA_ARGS__)
|
||||
#define kprint(l, f, ...) debugf(l, DEBUG_BASE_FMT f, DEBUG_BASE_ARGS, ##__VA_ARGS__)
|
||||
|
||||
struct multiboot_tag_elf_sections;
|
||||
|
||||
void debug_symbol_table_set(uintptr_t symtab, uintptr_t strtab, size_t symtab_size, size_t strtab_size);
|
||||
void debug_symbol_table_multiboot2(struct multiboot_tag_elf_sections *tag);
|
||||
int debug_symbol_find(uintptr_t addr, const char **name, uintptr_t *base);
|
||||
int debug_symbol_find_by_name(const char *name, uintptr_t *value);
|
||||
void debug_backtrace(int level, uintptr_t rbp, int depth, int limit);
|
||||
|
||||
void fmtsiz(char *buf, size_t sz);
|
||||
|
33
include/sys/hash.h
Normal file
33
include/sys/hash.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
#include "sys/list.h"
|
||||
|
||||
struct hash_pair {
|
||||
void *key, *value;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
#define HASH_DEBUG
|
||||
|
||||
struct hash {
|
||||
size_t (*hash) (const void *);
|
||||
struct hash_pair *(*pair_new) (void *, void *);
|
||||
void (*pair_free) (struct hash_pair *);
|
||||
int (*keycmp) (const void *, const void *);
|
||||
#if defined(HASH_DEBUG)
|
||||
void (*pair_print) (int, struct hash_pair *);
|
||||
#endif
|
||||
|
||||
size_t bucket_count;
|
||||
struct list_head *buckets;
|
||||
};
|
||||
|
||||
int shash_init(struct hash *h, size_t cap);
|
||||
int hash_insert(struct hash *h, const void *key, void *value);
|
||||
struct hash_pair *hash_lookup(struct hash *h, const void *key);
|
||||
|
||||
#if defined(HASH_DEBUG)
|
||||
void hash_dump(struct hash *h);
|
||||
#else
|
||||
#define hash_dump(h)
|
||||
#endif
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
int sys_module_load(const char *path, const char *params);
|
||||
int sys_module_unload(const char *name);
|
||||
|
12
include/sys/syms.h
Normal file
12
include/sys/syms.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
#include "sys/elf.h"
|
||||
|
||||
struct multiboot_tag_elf_sections;
|
||||
|
||||
void ksym_set_tables(uintptr_t symtab, uintptr_t strtab, size_t symtab_size, size_t strtab_size);
|
||||
void ksym_set_multiboot2(struct multiboot_tag_elf_sections *tag);
|
||||
Elf64_Sym *ksym_lookup(const char *name);
|
||||
int ksym_find_location(uintptr_t addr, const char **name, uintptr_t *base);
|
||||
|
||||
int ksym_load(void);
|
@ -12,3 +12,6 @@ struct module_desc {
|
||||
.name = _name, \
|
||||
.version = _version, \
|
||||
}
|
||||
|
||||
#define MODULE_DEPS \
|
||||
static const char __mod_deps[] __attribute__((section(".deps,\"\",@progbits //"),used))
|
||||
|
109
sys/debug.c
109
sys/debug.c
@ -6,7 +6,7 @@
|
||||
#include "sys/attr.h"
|
||||
#include "sys/spin.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/elf.h"
|
||||
#include "sys/syms.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
@ -17,111 +17,6 @@
|
||||
#include "arch/amd64/hw/con.h"
|
||||
#endif
|
||||
|
||||
////
|
||||
|
||||
static uintptr_t g_symtab_ptr = 0;
|
||||
static uintptr_t g_strtab_ptr = 0;
|
||||
static size_t g_symtab_size = 0;
|
||||
static size_t g_strtab_size = 0;
|
||||
|
||||
// Multiboot2-loaded sections are misaligned for some reason
|
||||
void debug_symbol_table_multiboot2(struct multiboot_tag_elf_sections *tag) {
|
||||
kinfo("Loading kernel symbols\n");
|
||||
kinfo("%u section headers:\n", tag->num);
|
||||
size_t string_section_offset = tag->shndx * tag->entsize;
|
||||
Elf64_Shdr *string_section_hdr = (Elf64_Shdr *) &tag->sections[string_section_offset];
|
||||
const char *shstrtab = (const char *) MM_VIRTUALIZE(realigned(string_section_hdr, sh_addr));
|
||||
|
||||
Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;
|
||||
|
||||
for (size_t i = 0; i < tag->num; ++i) {
|
||||
Elf64_Shdr *shdr = (Elf64_Shdr *) &tag->sections[i * tag->entsize];
|
||||
const char *name = &shstrtab[realigned(shdr, sh_name)];
|
||||
|
||||
switch (realigned(shdr, sh_type)) {
|
||||
case SHT_SYMTAB:
|
||||
if (symtab_shdr) {
|
||||
panic("Kernel image has 2+ symbol tables\n");
|
||||
}
|
||||
symtab_shdr = shdr;
|
||||
break;
|
||||
case SHT_STRTAB:
|
||||
if (strcmp(name, ".strtab")) {
|
||||
break;
|
||||
}
|
||||
if (strtab_shdr) {
|
||||
panic("kernel image has 2+ string tables\n");
|
||||
}
|
||||
strtab_shdr = shdr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab_shdr && strtab_shdr) {
|
||||
uintptr_t symtab_ptr = MM_VIRTUALIZE(realigned(symtab_shdr, sh_addr));
|
||||
uintptr_t strtab_ptr = MM_VIRTUALIZE(realigned(strtab_shdr, sh_addr));
|
||||
|
||||
debug_symbol_table_set(symtab_ptr,
|
||||
strtab_ptr,
|
||||
realigned(symtab_shdr, sh_size),
|
||||
realigned(strtab_shdr, sh_size));
|
||||
}
|
||||
}
|
||||
|
||||
void debug_symbol_table_set(uintptr_t s0, uintptr_t s1, size_t z0, size_t z1) {
|
||||
g_symtab_ptr = s0;
|
||||
g_symtab_size = z0;
|
||||
g_strtab_ptr = s1;
|
||||
g_strtab_size = z1;
|
||||
}
|
||||
|
||||
int debug_symbol_find_by_name(const char *name, uintptr_t *value) {
|
||||
_assert(g_symtab_ptr && g_strtab_ptr);
|
||||
Elf64_Sym *symtab = (Elf64_Sym *) g_symtab_ptr;
|
||||
for (size_t i = 0; i < g_symtab_size / sizeof(Elf64_Sym); ++i) {
|
||||
Elf64_Sym *sym = &symtab[i];
|
||||
if (sym->st_name < g_strtab_size) {
|
||||
const char *r_name = (const char *) g_strtab_ptr + sym->st_name;
|
||||
|
||||
if (!strcmp(r_name, name)) {
|
||||
*value = sym->st_value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int debug_symbol_find(uintptr_t addr, const char **name, uintptr_t *base) {
|
||||
if (g_symtab_ptr && g_strtab_ptr) {
|
||||
size_t offset = 0;
|
||||
Elf64_Sym *sym;
|
||||
|
||||
while (offset < g_symtab_size) {
|
||||
sym = (Elf64_Sym *) (g_symtab_ptr + offset);
|
||||
|
||||
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) {
|
||||
if (sym->st_value <= addr && sym->st_value + sym->st_size >= addr) {
|
||||
*base = sym->st_value;
|
||||
if (sym->st_name < g_strtab_size) {
|
||||
*name = (const char *) (g_strtab_ptr + sym->st_name);
|
||||
} else {
|
||||
*name = "<invalid>";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
offset += sizeof(Elf64_Sym);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void debug_backtrace(int level, uintptr_t rbp, int depth, int limit) {
|
||||
// Typical layout:
|
||||
// rbp + 08 == rip
|
||||
@ -142,7 +37,7 @@ void debug_backtrace(int level, uintptr_t rbp, int depth, int limit) {
|
||||
uintptr_t base;
|
||||
const char *name;
|
||||
|
||||
if (debug_symbol_find(rip, &name, &base) == 0) {
|
||||
if (ksym_find_location(rip, &name, &base) == 0) {
|
||||
debugf(level, "%d: %p <%s + %04x>\n", depth, rip, name, rip - base);
|
||||
} else {
|
||||
debugf(level, "%d: %p (unknown)\n", depth, rip);
|
||||
|
117
sys/hash.c
Normal file
117
sys/hash.c
Normal file
@ -0,0 +1,117 @@
|
||||
#include <stddef.h>
|
||||
#include "sys/assert.h"
|
||||
#include "sys/string.h"
|
||||
#include "user/errno.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/heap.h"
|
||||
#include "sys/hash.h"
|
||||
#include "sys/mem/slab.h"
|
||||
|
||||
#define HASH_CHECK_DUP
|
||||
|
||||
static struct slab_cache *shash_cache;
|
||||
|
||||
static size_t shash_hash(const void *_s) {
|
||||
const char *s = _s;
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *s++)) {
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static struct hash_pair *shash_pair_new(void *key, void *value) {
|
||||
// Must fit into 128-sized block
|
||||
_assert(strlen(key) < 128 - sizeof(struct hash_pair));
|
||||
struct hash_pair *res;
|
||||
|
||||
if (!shash_cache) {
|
||||
shash_cache = slab_cache_get(128);
|
||||
_assert(shash_cache);
|
||||
}
|
||||
|
||||
res = slab_calloc(shash_cache);
|
||||
if (!res) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res->key = (void *) res + sizeof(struct hash_pair);
|
||||
res->value = value;
|
||||
strcpy((void *) res + sizeof(struct hash_pair), key);
|
||||
list_head_init(&res->link);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void shash_pair_free(struct hash_pair *pair) {
|
||||
_assert(shash_cache);
|
||||
slab_free(shash_cache, pair);
|
||||
}
|
||||
|
||||
#if defined(HASH_DEBUG)
|
||||
static void shash_pair_print(int level, struct hash_pair *pair) {
|
||||
debugf(level, "%s: %p\n", pair->key, pair->value);
|
||||
}
|
||||
#endif
|
||||
|
||||
int shash_init(struct hash *h, size_t cap) {
|
||||
h->hash = shash_hash;
|
||||
h->pair_new = shash_pair_new;
|
||||
h->pair_free = shash_pair_free;
|
||||
h->keycmp = (int (*) (const void *, const void *)) strcmp;
|
||||
#if defined(HASH_DEBUG)
|
||||
h->pair_print = shash_pair_print;
|
||||
#endif
|
||||
|
||||
h->bucket_count = cap;
|
||||
h->buckets = kmalloc(sizeof(struct list_head) * cap);
|
||||
|
||||
if (!h->buckets) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cap; ++i) {
|
||||
list_head_init(&h->buckets[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hash_insert(struct hash *h, const void *key, void *value) {
|
||||
#if defined(HASH_CHECK_DUP)
|
||||
_assert(!hash_lookup(h, key));
|
||||
#endif
|
||||
struct hash_pair *pair = h->pair_new((void *) key, value);
|
||||
if (!pair) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
size_t index = h->hash(key) % h->bucket_count;
|
||||
list_add(&pair->link, &h->buckets[index]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hash_pair *hash_lookup(struct hash *h, const void *key) {
|
||||
size_t index = h->hash(key) % h->bucket_count;
|
||||
struct hash_pair *pair;
|
||||
|
||||
list_for_each_entry(pair, &h->buckets[index], link) {
|
||||
if (!h->keycmp(pair->key, key)) {
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(HASH_DEBUG)
|
||||
void hash_dump(struct hash *h) {
|
||||
struct hash_pair *pair;
|
||||
for (size_t i = 0; i < h->bucket_count; ++i) {
|
||||
list_for_each_entry(pair, &h->buckets[i], link) {
|
||||
h->pair_print(DEBUG_DEFAULT, pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
127
sys/mod.c
127
sys/mod.c
@ -5,6 +5,7 @@
|
||||
#include "sys/assert.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/elf.h"
|
||||
#include "user/module.h"
|
||||
#include "sys/mem/phys.h"
|
||||
#include "sys/mem/slab.h"
|
||||
#include "sys/mem/vmalloc.h"
|
||||
@ -12,6 +13,8 @@
|
||||
#include "sys/string.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/syms.h"
|
||||
#include "sys/hash.h"
|
||||
#include "user/errno.h"
|
||||
#include "user/fcntl.h"
|
||||
|
||||
@ -38,6 +41,9 @@ struct object {
|
||||
|
||||
struct object_image image;
|
||||
|
||||
// Symbol values
|
||||
struct hash export;
|
||||
|
||||
// In-memory object
|
||||
uintptr_t object_base;
|
||||
size_t object_page_count;
|
||||
@ -45,15 +51,49 @@ struct object {
|
||||
// PLT and GOT
|
||||
void *gotplt;
|
||||
size_t gotplt_size;
|
||||
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
static struct slab_cache *g_object_cache;
|
||||
static LIST_HEAD(g_module_list);
|
||||
|
||||
static int mod_sym_lookup(const char *name, void **value) {
|
||||
struct object *mod;
|
||||
struct hash_pair *pair;
|
||||
|
||||
list_for_each_entry(mod, &g_module_list, link) {
|
||||
pair = hash_lookup(&mod->export, name);
|
||||
if (pair) {
|
||||
*value = pair->value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mod_loaded(const char *name) {
|
||||
struct object *mod;
|
||||
list_for_each_entry(mod, &g_module_list, link) {
|
||||
//kinfo("STRCMP %s, %s\n", mod->module_desc->name, name);
|
||||
if (!strcmp(mod->module_desc->name, name)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct object *object_create(void) {
|
||||
if (!g_object_cache) {
|
||||
g_object_cache = slab_cache_get(sizeof(struct object));
|
||||
}
|
||||
return slab_calloc(g_object_cache);
|
||||
struct object *r = slab_calloc(g_object_cache);
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
_assert(shash_init(&r->export, 16) == 0);
|
||||
list_head_init(&r->link);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void object_free(struct object *obj) {
|
||||
@ -155,6 +195,25 @@ static int object_reloc(struct object *obj) {
|
||||
_assert(mm_map_single(mm_kernel, (uintptr_t) plt + i, page_phys, MM_PAGE_WRITE, 0) == 0);
|
||||
}
|
||||
|
||||
// Export global symbols
|
||||
shdr = obj->image.sh_symtab;
|
||||
for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i) {
|
||||
Elf64_Sym *sym = obj->image.base + shdr->sh_offset + i * shdr->sh_entsize;
|
||||
Elf64_Word type = ELF64_ST_TYPE(sym->st_info);
|
||||
Elf64_Word bind = ELF64_ST_BIND(sym->st_info);
|
||||
Elf64_Shdr *sym_section;
|
||||
|
||||
if (bind == STB_GLOBAL && type != STT_SECTION) {
|
||||
name = &obj->image.symstrtab[sym->st_name];
|
||||
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_COMMON) {
|
||||
sym_section = object_shdr(obj, sym->st_shndx);
|
||||
void *value = (void *) (sym_section->sh_addr + obj->object_base + sym->st_value);
|
||||
|
||||
_assert(hash_insert(&obj->export, name, value) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find relocation sections
|
||||
for (size_t i = 0; i < ehdr->e_shnum; ++i) {
|
||||
shdr = object_shdr(obj, i);
|
||||
@ -180,8 +239,19 @@ static int object_reloc(struct object *obj) {
|
||||
// symbol
|
||||
name = &obj->image.symstrtab[sym->st_name];
|
||||
|
||||
if (debug_symbol_find_by_name(name, &value) != 0) {
|
||||
panic("Undefined reference to %s\n", name);
|
||||
// 1. Try to lookup kernel symbol
|
||||
sym = ksym_lookup(name);
|
||||
if (!sym) {
|
||||
// 2. Try to lookup symbol in other modules
|
||||
void *r;
|
||||
|
||||
if (mod_sym_lookup(name, &r) != 0) {
|
||||
panic("Undefined reference to %s\n", name);
|
||||
}
|
||||
|
||||
value = (uintptr_t) r;
|
||||
} else {
|
||||
value = sym->st_value;
|
||||
}
|
||||
kdebug("Resolved %s: %p\n", name, value);
|
||||
} else if (sym->st_shndx == SHN_COMMON) {
|
||||
@ -334,7 +404,8 @@ static int object_extract_info(struct object *obj) {
|
||||
|
||||
if (type == STT_FUNC || type == STT_OBJECT || type == STT_NOTYPE) {
|
||||
name = &obj->image.symstrtab[sym->st_name];
|
||||
void *value = (void *) (sym->st_value + obj->object_base);
|
||||
Elf64_Shdr *sym_shdr = object_shdr(obj, sym->st_shndx);
|
||||
void *value = (void *) (sym->st_value + obj->object_base + sym_shdr->sh_addr);
|
||||
|
||||
if (!strcmp(name, SYM_MOD_ENTER)) {
|
||||
obj->module_enter = value;
|
||||
@ -444,6 +515,49 @@ static int object_load(struct object *obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int object_check_deps(struct object *obj) {
|
||||
Elf64_Ehdr *ehdr;
|
||||
Elf64_Shdr *shdr;
|
||||
const char *shstrtab, *name;
|
||||
char depname[64];
|
||||
const char *p, *e;
|
||||
|
||||
ehdr = obj->image.base;
|
||||
shstrtab = obj->image.base + object_shdr(obj, ehdr->e_shstrndx)->sh_offset;
|
||||
|
||||
for (size_t i = 0; i < ehdr->e_shnum; ++i) {
|
||||
shdr = object_shdr(obj, i);
|
||||
name = &shstrtab[shdr->sh_name];
|
||||
|
||||
if (!strcmp(name, ".deps")) {
|
||||
p = obj->image.base + shdr->sh_offset;
|
||||
while (1) {
|
||||
e = strchr(p, ',');
|
||||
if (e) {
|
||||
_assert((size_t) (e - p) < sizeof(depname));
|
||||
strncpy(depname, p, e - p);
|
||||
depname[e - p] = 0;
|
||||
} else {
|
||||
_assert(strlen(p) < sizeof(depname));
|
||||
strcpy(depname, p);
|
||||
}
|
||||
|
||||
if (!mod_loaded(depname)) {
|
||||
kwarn("unresolved dependency: %s\n", depname);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!e) {
|
||||
break;
|
||||
}
|
||||
p = e + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_module_unload(const char *name) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
@ -476,11 +590,16 @@ int sys_module_load(const char *_path, const char *params) {
|
||||
asm volatile ("movq %0, %%cr3"::"r"(cr3):"memory");
|
||||
asm volatile ("cli");
|
||||
|
||||
if ((res = object_check_deps(obj)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((res = object_load(obj)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
object_finalize_load(obj);
|
||||
list_add(&obj->link, &g_module_list);
|
||||
|
||||
debug_dump(DEBUG_DEFAULT, (void *) (obj->object_base + 0x1d), 64);
|
||||
|
||||
|
155
sys/syms.c
Normal file
155
sys/syms.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include "sys/syms.h"
|
||||
#include "sys/mm.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/hash.h"
|
||||
#include "arch/amd64/multiboot2.h"
|
||||
|
||||
////
|
||||
|
||||
static uintptr_t g_symtab_ptr = 0;
|
||||
static uintptr_t g_strtab_ptr = 0;
|
||||
static size_t g_symtab_size = 0;
|
||||
static size_t g_strtab_size = 0;
|
||||
static struct hash g_symtab_hash;
|
||||
|
||||
// Multiboot2-loaded sections are misaligned for some reason
|
||||
void ksym_set_multiboot2(struct multiboot_tag_elf_sections *tag) {
|
||||
kinfo("Loading kernel symbols\n");
|
||||
kinfo("%u section headers:\n", tag->num);
|
||||
size_t string_section_offset = tag->shndx * tag->entsize;
|
||||
Elf64_Shdr *string_section_hdr = (Elf64_Shdr *) &tag->sections[string_section_offset];
|
||||
const char *shstrtab = (const char *) MM_VIRTUALIZE(realigned(string_section_hdr, sh_addr));
|
||||
|
||||
Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;
|
||||
|
||||
for (size_t i = 0; i < tag->num; ++i) {
|
||||
Elf64_Shdr *shdr = (Elf64_Shdr *) &tag->sections[i * tag->entsize];
|
||||
const char *name = &shstrtab[realigned(shdr, sh_name)];
|
||||
|
||||
switch (realigned(shdr, sh_type)) {
|
||||
case SHT_SYMTAB:
|
||||
if (symtab_shdr) {
|
||||
panic("Kernel image has 2+ symbol tables\n");
|
||||
}
|
||||
symtab_shdr = shdr;
|
||||
break;
|
||||
case SHT_STRTAB:
|
||||
if (strcmp(name, ".strtab")) {
|
||||
break;
|
||||
}
|
||||
if (strtab_shdr) {
|
||||
panic("kernel image has 2+ string tables\n");
|
||||
}
|
||||
strtab_shdr = shdr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab_shdr && strtab_shdr) {
|
||||
uintptr_t symtab_ptr = MM_VIRTUALIZE(realigned(symtab_shdr, sh_addr));
|
||||
uintptr_t strtab_ptr = MM_VIRTUALIZE(realigned(strtab_shdr, sh_addr));
|
||||
|
||||
ksym_set_tables(symtab_ptr,
|
||||
strtab_ptr,
|
||||
realigned(symtab_shdr, sh_size),
|
||||
realigned(strtab_shdr, sh_size));
|
||||
}
|
||||
}
|
||||
|
||||
void ksym_set_tables(uintptr_t s0, uintptr_t s1, size_t z0, size_t z1) {
|
||||
Elf64_Sym *sym;
|
||||
Elf64_Word type, bind;
|
||||
const char *name;
|
||||
|
||||
_assert(shash_init(&g_symtab_hash, 32) == 0);
|
||||
|
||||
// TODO: entsize?
|
||||
for (size_t i = 0; i < z0 / sizeof(Elf64_Sym); ++i) {
|
||||
sym = (Elf64_Sym *) (s0 + i * sizeof(Elf64_Sym));
|
||||
type = ELF64_ST_TYPE(sym->st_info);
|
||||
bind = ELF64_ST_BIND(sym->st_info);
|
||||
if (type != STT_SECTION && bind == STB_GLOBAL) {
|
||||
name = (const char *) s1 + sym->st_name;
|
||||
_assert(hash_insert(&g_symtab_hash, name, sym) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
g_symtab_ptr = s0;
|
||||
g_symtab_size = z0;
|
||||
g_strtab_ptr = s1;
|
||||
g_strtab_size = z1;
|
||||
}
|
||||
|
||||
static Elf64_Sym *ksym_lookup_fast(const char *name) {
|
||||
struct hash_pair *p = hash_lookup(&g_symtab_hash, name);
|
||||
if (p) {
|
||||
return p->value;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Elf64_Sym *ksym_lookup(const char *name) {
|
||||
Elf64_Sym *res = ksym_lookup_fast(name);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!g_symtab_ptr) {
|
||||
kwarn("no symbol table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Elf64_Sym *symtab = (Elf64_Sym *) g_symtab_ptr;
|
||||
for (size_t i = 0; i < g_symtab_size / sizeof(Elf64_Sym); ++i) {
|
||||
Elf64_Sym *sym = &symtab[i];
|
||||
if (sym->st_name < g_strtab_size) {
|
||||
const char *r_name = (const char *) g_strtab_ptr + sym->st_name;
|
||||
if (!strcmp(r_name, name)) {
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ksym_find_location(uintptr_t addr, const char **name, uintptr_t *base) {
|
||||
if (!g_symtab_ptr) {
|
||||
kwarn("no symbol table\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g_symtab_ptr && g_strtab_ptr) {
|
||||
size_t offset = 0;
|
||||
Elf64_Sym *sym;
|
||||
|
||||
while (offset < g_symtab_size) {
|
||||
sym = (Elf64_Sym *) (g_symtab_ptr + offset);
|
||||
|
||||
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) {
|
||||
if (sym->st_value <= addr && sym->st_value + sym->st_size >= addr) {
|
||||
*base = sym->st_value;
|
||||
if (sym->st_name < g_strtab_size) {
|
||||
*name = (const char *) (g_strtab_ptr + sym->st_name);
|
||||
} else {
|
||||
*name = "<invalid>";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
offset += sizeof(Elf64_Sym);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user