diff --git a/arch/amd64/hw/exc.c b/arch/amd64/hw/exc.c index 3d67c9c..27f4224 100644 --- a/arch/amd64/hw/exc.c +++ b/arch/amd64/hw/exc.c @@ -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); diff --git a/arch/amd64/kernel.c b/arch/amd64/kernel.c index fcc4fb4..02d8827 100644 --- a/arch/amd64/kernel.c +++ b/arch/amd64/kernel.c @@ -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); } diff --git a/etc/Kernel.makefile b/etc/Kernel.makefile index a8f9a6c..b06f558 100644 --- a/etc/Kernel.makefile +++ b/etc/Kernel.makefile @@ -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 \ diff --git a/include/sys/debug.h b/include/sys/debug.h index 2dcc3da..954cbc1 100644 --- a/include/sys/debug.h +++ b/include/sys/debug.h @@ -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); diff --git a/include/sys/hash.h b/include/sys/hash.h new file mode 100644 index 0000000..b65de25 --- /dev/null +++ b/include/sys/hash.h @@ -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 diff --git a/include/sys/mod.h b/include/sys/mod.h index 049cd37..ad85033 100644 --- a/include/sys/mod.h +++ b/include/sys/mod.h @@ -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); diff --git a/include/sys/syms.h b/include/sys/syms.h new file mode 100644 index 0000000..05ae1b7 --- /dev/null +++ b/include/sys/syms.h @@ -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); diff --git a/include/user/module.h b/include/user/module.h index 3edfa2e..5c0d5cc 100644 --- a/include/user/module.h +++ b/include/user/module.h @@ -12,3 +12,6 @@ struct module_desc { .name = _name, \ .version = _version, \ } + +#define MODULE_DEPS \ + static const char __mod_deps[] __attribute__((section(".deps,\"\",@progbits //"),used)) diff --git a/sys/debug.c b/sys/debug.c index 8edce21..cf21b8a 100644 --- a/sys/debug.c +++ b/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 = ""; - } - 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); diff --git a/sys/hash.c b/sys/hash.c new file mode 100644 index 0000000..addc89c --- /dev/null +++ b/sys/hash.c @@ -0,0 +1,117 @@ +#include +#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 diff --git a/sys/mod.c b/sys/mod.c index ad5dd0a..65de195 100644 --- a/sys/mod.c +++ b/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); diff --git a/sys/syms.c b/sys/syms.c new file mode 100644 index 0000000..0cfc2a9 --- /dev/null +++ b/sys/syms.c @@ -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 = ""; + } + return 0; + } + } + + offset += sizeof(Elf64_Sym); + } + } + + return -1; +} +