diff options
-rw-r--r-- | Kconfig | 19 | ||||
-rw-r--r-- | Makefile | 51 | ||||
-rw-r--r-- | arch/x86/machine/boot.c | 2 | ||||
-rw-r--r-- | arch/x86/machine/strace.c | 212 | ||||
-rw-r--r-- | arch/x86/machine/strace.h | 25 | ||||
-rw-r--r-- | arch/x86/x15.lds.S | 17 | ||||
-rw-r--r-- | kern/Makefile | 1 | ||||
-rw-r--r-- | kern/macros.h | 4 | ||||
-rw-r--r-- | kern/panic.c | 3 | ||||
-rw-r--r-- | kern/symbol.c | 49 | ||||
-rw-r--r-- | kern/symbol.h | 45 | ||||
-rwxr-xr-x | tools/gen_symtab.py | 30 |
12 files changed, 227 insertions, 231 deletions
@@ -26,13 +26,16 @@ config CFLAGS menu "Build options" -config CC_EXE +config COMPILER string "Compiler executable" default CC ---help--- Name of the compiler executable -config CC_OPTIONS + This includes any toolchain prefix, and must be a file name, + not a path. + +config COMPILER_OPTIONS string "Compilation options" default CFLAGS ---help--- @@ -44,6 +47,18 @@ config ASSERT ---help--- Enable assert() code generation. +config SYMTAB + bool "Build symbol table" + default y + ---help--- + Build and embed a symbol table in the kernel. + + This option allows the kernel to perform symbolic address + resolutions which are very convenient for debugging, at the + cost of additional data memory. + + If unsure, enable. + endmenu source "arch/$ARCH/Kconfig" @@ -85,9 +85,19 @@ define xbuild_link $(COMPILE) -o $@ $(1) $(XBUILD_LDFLAGS) endef +XBUILD_GEN_SYMTAB = $(SRCDIR)/tools/gen_symtab.py +XBUILD_GEN_SYMTAB_DEPS = $(XBUILD_GEN_SYMTAB) + +# $(call xbuild_gen_symtab) +define xbuild_gen_symtab + $(call xbuild_action,GEN,$@) \ + $(NM) -S -n $< | $(XBUILD_GEN_SYMTAB) > $@ +endef + define xbuild_clean - $(Q)rm -f x15 \ + $(Q)rm -f x15 $(x15_NO_SYMTAB) \ $(x15_OBJDEPS) $(x15_OBJECTS) \ + $(x15_SYMTAB_C) $(x15_SYMTAB_D) $(x15_SYMTAB_O) \ $(x15_LDS_D) $(x15_LDS) endef @@ -207,17 +217,24 @@ include/generated/autoconf.h: .config $(ALL_MAKEFILES) -include .config -ifdef CONFIG_CC_EXE +ifdef CONFIG_COMPILER # Use printf to remove quotes -CC := $(shell printf -- $(CONFIG_CC_EXE)) +CC := $(shell printf -- $(CONFIG_COMPILER)) else CC := gcc endif -# Export to CONFIG_CC +# The CC variable is used by Kconfig to set the value of CONFIG_COMPILER. export CC -CPP = $(CC) -E +TOOLCHAIN_NAME = $(shell printf "%s" $(CC) | rev | cut -s -d - -f 2- | rev) + +ifneq ($(TOOLCHAIN_NAME),) +TOOLCHAIN_PREFIX = $(TOOLCHAIN_NAME)- +endif + +CPP := $(CC) -E +NM := $(TOOLCHAIN_PREFIX)nm CFLAGS ?= -O2 -g @@ -281,18 +298,22 @@ include $(MAKEFILE_INCLUDES) # Must be defined by the architecture-specific Makefile. export KCONFIG_DEFCONFIG -ifdef CONFIG_CC_OPTIONS +ifdef CONFIG_COMPILER_OPTIONS # Use printf to remove quotes -XBUILD_CFLAGS += $(shell printf -- $(CONFIG_CC_OPTIONS)) +XBUILD_CFLAGS += $(shell printf -- $(CONFIG_COMPILER_OPTIONS)) endif COMPILE := $(CC) $(XBUILD_CPPFLAGS) $(XBUILD_CFLAGS) # Don't change preprocessor and compiler flags from this point +x15_NO_SYMTAB := .x15.no_symtab x15_SOURCES := $(x15_SOURCES-y) x15_OBJDEPS := $(call xbuild_replace_source_suffix,d,$(x15_SOURCES)) x15_OBJECTS := $(call xbuild_replace_source_suffix,o,$(x15_SOURCES)) +x15_SYMTAB_C := .symtab.c +x15_SYMTAB_D := $(call xbuild_replace_source_suffix,d,$(x15_SYMTAB_C)) +x15_SYMTAB_O := $(call xbuild_replace_source_suffix,o,$(x15_SYMTAB_C)) x15_LDS := $(basename $(x15_LDS_S)) x15_LDS_D := $(x15_LDS).d @@ -324,9 +345,23 @@ x15_DEPS := $(x15_LDS) .x15.sorted_init_ops %.lds: %.lds.S include/generated/autoconf.h $(xbuild_gen_linker_script) -x15: $(x15_OBJECTS) $(x15_DEPS) +ifeq ($(CONFIG_SYMTAB),y) +x15_FIRST_PASS := $(x15_NO_SYMTAB) +else +x15_FIRST_PASS := x15 +endif + +$(x15_FIRST_PASS): $(x15_OBJECTS) $(x15_DEPS) $(call xbuild_link,$(x15_OBJECTS)) +ifeq ($(CONFIG_SYMTAB),y) +$(x15_SYMTAB_C): $(x15_FIRST_PASS) $(XBUILD_GEN_SYMTAB_DEPS) + $(call xbuild_gen_symtab) + +x15: $(x15_NO_SYMTAB) $(x15_SYMTAB_O) + $(call xbuild_link,$(x15_OBJECTS) $(x15_SYMTAB_O)) +endif + .PHONY: install-x15 install-x15: install -D -m 644 x15 $(DESTDIR)/boot/x15 diff --git a/arch/x86/machine/boot.c b/arch/x86/machine/boot.c index d540d8d8..c1970f5d 100644 --- a/arch/x86/machine/boot.c +++ b/arch/x86/machine/boot.c @@ -70,7 +70,6 @@ #include <machine/pmap.h> #include <machine/pmu_amd.h> #include <machine/pmu_intel.h> -#include <machine/strace.h> #include <machine/uart.h> #include <vm/vm_kmem.h> @@ -495,7 +494,6 @@ void __init boot_main(void) { arg_set_cmdline(boot_tmp_cmdline); - strace_set_mbi(&boot_raw_mbi); kernel_main(); /* Never reached */ diff --git a/arch/x86/machine/strace.c b/arch/x86/machine/strace.c index cfb237e1..3031e544 100644 --- a/arch/x86/machine/strace.c +++ b/arch/x86/machine/strace.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2014 Richard Braun. + * Copyright (c) 2018 Agustina Arzille. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,15 +17,10 @@ */ #include <stddef.h> +#include <stdint.h> #include <stdio.h> -#include <string.h> -#include <kern/init.h> -#include <kern/kmem.h> -#include <kern/log.h> -#include <kern/macros.h> -#include <machine/elf.h> -#include <machine/multiboot.h> +#include <kern/symbol.h> #include <machine/pmap.h> #include <machine/strace.h> #include <machine/types.h> @@ -36,56 +32,26 @@ #define STRACE_ADDR_FORMAT "%#010lx" #endif /* __LP64__ */ -static const struct multiboot_raw_info *strace_mbi __initdata; - -static struct elf_sym *strace_symtab __read_mostly; -static struct elf_sym *strace_symtab_end __read_mostly; -static char *strace_strtab __read_mostly; - -static const char * -strace_lookup(uintptr_t addr, uintptr_t *offset, uintptr_t *size) -{ - struct elf_sym *sym; - - for (sym = strace_symtab; sym < strace_symtab_end; sym++) { - if ((sym->size != 0) - && (addr >= sym->value) - && (addr <= (sym->value + sym->size))) { - break; - } - } - - if (sym >= strace_symtab_end) { - return NULL; - } - - if (sym->name == 0) { - return NULL; - } - - *offset = addr - sym->value; - *size = sym->size; - return &strace_strtab[sym->name]; -} - static void -strace_show_one(unsigned int index, unsigned long ip) +strace_show_one(unsigned int index, uintptr_t ip) { - uintptr_t offset, size; - const char *name; + const struct symbol *symbol; + uintptr_t offset; - name = strace_lookup(ip, &offset, &size); + symbol = symbol_lookup(ip); - if (name == NULL) { - printf("#%u [" STRACE_ADDR_FORMAT "]\n", index, ip); + if (!symbol) { + printf("#%u [" STRACE_ADDR_FORMAT "]\n", index, (unsigned long)ip); } else { + offset = ip - symbol->addr; printf("#%u [" STRACE_ADDR_FORMAT "] %s+%#lx/%#lx\n", - index, ip, name, (unsigned long)offset, (unsigned long)size); + index, (unsigned long)ip, symbol->name, + (unsigned long)offset, (unsigned long)symbol->size); } } void -strace_show(unsigned long ip, unsigned long bp) +strace_show(uintptr_t ip, uintptr_t bp) { phys_addr_t pa; void **frame; @@ -109,7 +75,7 @@ strace_show(unsigned long ip, unsigned long bp) break; } - strace_show_one(i, (unsigned long)frame[1]); + strace_show_one(i, (uintptr_t)frame[1]); error = pmap_kextract((uintptr_t)frame, &pa); if (error) { @@ -121,153 +87,3 @@ strace_show(unsigned long ip, unsigned long bp) frame = frame[0]; } } - -static void * __init -strace_copy_section(const struct elf_shdr *shdr) -{ - uintptr_t map_addr; - size_t map_size; - const void *src; - void *copy; - - src = vm_kmem_map_pa(shdr->addr, shdr->size, &map_addr, &map_size); - - if (src == NULL) { - log_err("strace: unable to map section"); - goto error_map; - } - - copy = kmem_alloc(shdr->size); - - if (copy == NULL) { - log_err("strace: unable to allocate section copy"); - goto error_copy; - } - - memcpy(copy, src, shdr->size); - vm_kmem_unmap_pa(map_addr, map_size); - return copy; - -error_copy: - vm_kmem_unmap_pa(map_addr, map_size); -error_map: - return NULL; -} - -static const struct elf_shdr * __init -strace_lookup_section(const struct multiboot_raw_info *mbi, const void *table, - const char *shstrtab, const char *name) -{ - const struct elf_shdr *shdr; - unsigned int i; - const char *shdr_name; - - for (i = 0; i < mbi->shdr_num; i++) { - shdr = table + (i * mbi->shdr_size); - shdr_name = &shstrtab[shdr->name]; - - if (strcmp(shdr_name, name) == 0) { - return shdr; - } - } - - return NULL; -} - -void __init -strace_set_mbi(const struct multiboot_raw_info *mbi) -{ - strace_mbi = mbi; -} - -static int __init -strace_setup(void) -{ - const struct elf_shdr *shstrtab_hdr, *symtab_hdr, *strtab_hdr; - const struct multiboot_raw_info *mbi; - uintptr_t map_addr, shstrtab_map_addr; - size_t size, map_size, shstrtab_map_size; - const char *shstrtab; - const void *table; - - mbi = strace_mbi; - - if (!(mbi->flags & MULTIBOOT_LOADER_SHDR) || (mbi->shdr_num == 0)) { - goto no_syms; - } - - size = mbi->shdr_num * mbi->shdr_size; - table = vm_kmem_map_pa(mbi->shdr_addr, size, &map_addr, &map_size); - - if (table == NULL) { - log_err("strace: unable to map section headers table"); - goto no_syms; - } - - if (mbi->shdr_strndx >= mbi->shdr_num) { - log_err("strace: invalid section names index"); - goto error_shstrndx; - } - - shstrtab_hdr = table + (mbi->shdr_strndx * mbi->shdr_size); - shstrtab = vm_kmem_map_pa(shstrtab_hdr->addr, shstrtab_hdr->size, - &shstrtab_map_addr, &shstrtab_map_size); - - if (shstrtab == NULL) { - log_err("strace: unable to map section names"); - goto error_shstrtab; - } - - symtab_hdr = strace_lookup_section(mbi, table, shstrtab, ".symtab"); - - if (symtab_hdr == NULL) { - log_err("strace: unable to find symbol table"); - goto error_symtab_lookup; - } - - strtab_hdr = strace_lookup_section(mbi, table, shstrtab, ".strtab"); - - if (strtab_hdr == NULL) { - log_err("strace: unable to find symbol string table"); - goto error_strtab_lookup; - } - - strace_symtab = strace_copy_section(symtab_hdr); - - if (strace_symtab == NULL) { - goto error_symtab; - } - - strace_symtab_end = (void *)strace_symtab + symtab_hdr->size; - strace_strtab = strace_copy_section(strtab_hdr); - - if (strace_strtab == NULL) { - goto error_strtab; - } - - vm_kmem_unmap_pa(shstrtab_map_addr, shstrtab_map_size); - vm_kmem_unmap_pa(map_addr, map_size); - return 0; - -error_strtab: - kmem_free(strace_symtab, symtab_hdr->size); -error_symtab: -error_strtab_lookup: -error_symtab_lookup: - vm_kmem_unmap_pa(shstrtab_map_addr, shstrtab_map_size); -error_shstrtab: -error_shstrndx: - vm_kmem_unmap_pa(map_addr, map_size); -no_syms: - strace_symtab = NULL; - strace_symtab_end = NULL; - strace_strtab = NULL; - return 0; -} - -INIT_OP_DEFINE(strace_setup, - INIT_OP_DEP(kmem_setup, true), - INIT_OP_DEP(log_setup, true), - INIT_OP_DEP(pmap_bootstrap, true), - INIT_OP_DEP(printf_setup, true), - INIT_OP_DEP(vm_kmem_setup, true)); diff --git a/arch/x86/machine/strace.h b/arch/x86/machine/strace.h index 482768b9..a5de664f 100644 --- a/arch/x86/machine/strace.h +++ b/arch/x86/machine/strace.h @@ -23,9 +23,9 @@ #ifndef X86_STRACE_H #define X86_STRACE_H -#include <kern/init.h> +#include <stdint.h> + #include <kern/macros.h> -#include <machine/multiboot.h> /* * Display a call trace. @@ -33,7 +33,7 @@ * Attempt to resolve the given instruction pointer, then walk the calling * chain from the given frame pointer. */ -void strace_show(unsigned long ip, unsigned long bp); +void strace_show(uintptr_t ip, uintptr_t bp); /* * Display the current call trace. @@ -41,24 +41,11 @@ void strace_show(unsigned long ip, unsigned long bp); static __always_inline void strace_dump(void) { - unsigned long ip; + uintptr_t ip, bp; asm volatile("1: mov $1b, %0" : "=r" (ip)); - strace_show(ip, (unsigned long)__builtin_frame_address(0)); + bp = (uintptr_t)__builtin_frame_address(0); + strace_show(ip, bp); } -/* - * Pass the multiboot information structure. - * - * If available, the symbol table is extracted from the boot data, when - * the strace module is initialized. - */ -void strace_set_mbi(const struct multiboot_raw_info *mbi); - -/* - * This init operation provides : - * - module fully initialized - */ -INIT_OP_DECLARE(strace_setup); - #endif /* X86_STRACE_H */ diff --git a/arch/x86/x15.lds.S b/arch/x86/x15.lds.S index b896a5d6..260d230c 100644 --- a/arch/x86/x15.lds.S +++ b/arch/x86/x15.lds.S @@ -23,6 +23,10 @@ PHDRS text PT_LOAD FLAGS(5); rodata PT_LOAD FLAGS(4); data PT_LOAD FLAGS(6); + +#ifdef CONFIG_SYMTAB + symbol PT_LOAD FLAGS(6); +#endif } SECTIONS @@ -91,6 +95,19 @@ SECTIONS *(.bss*) } : data +#ifdef CONFIG_SYMTAB + /* + * Including the embedded symbol table last should reliably prevent + * the second link from changing the addresses of the kernel symbols. + * + * In addition, use a program header different from data to make + * sure the linker doesn't include the .bss section in the output file. + */ + .symbol ALIGN(PAGE_SIZE) : AT(BOOT_VTOP(ADDR(.symbol))) { + *(.symbol*) + } : symbol +#endif /* CONFIG_SYMTAB */ + . = ALIGN(PAGE_SIZE); _end = .; diff --git a/kern/Makefile b/kern/Makefile index 5b04fcb3..ea7e3bff 100644 --- a/kern/Makefile +++ b/kern/Makefile @@ -29,6 +29,7 @@ x15_SOURCES-y += \ kern/spinlock.c \ kern/sref.c \ kern/string.c \ + kern/symbol.c \ kern/syscnt.c \ kern/task.c \ kern/thread.c \ diff --git a/kern/macros.h b/kern/macros.h index 6d136e3e..ddd9e587 100644 --- a/kern/macros.h +++ b/kern/macros.h @@ -105,6 +105,10 @@ #define __used __attribute__((used)) #endif +#ifndef __weak +#define __weak __attribute__((weak)) +#endif + #ifndef __fallthrough #if __GNUC__ >= 7 #define __fallthrough __attribute__((fallthrough)) diff --git a/kern/panic.c b/kern/panic.c index c610e3fa..bd1f6658 100644 --- a/kern/panic.c +++ b/kern/panic.c @@ -64,5 +64,4 @@ panic_setup(void) INIT_OP_DEFINE(panic_setup, INIT_OP_DEP(cpu_setup, true), - INIT_OP_DEP(printf_setup, true), - INIT_OP_DEP(strace_setup, true)); + INIT_OP_DEP(printf_setup, true)); diff --git a/kern/symbol.c b/kern/symbol.c new file mode 100644 index 00000000..30df091e --- /dev/null +++ b/kern/symbol.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Agustina Arzille. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stddef.h> +#include <stdint.h> + +#include <kern/macros.h> +#include <kern/symbol.h> + +const size_t symbol_table_size __weak; +const struct symbol *symbol_table_ptr __weak; + +const struct symbol * +symbol_lookup(uintptr_t addr) +{ + const struct symbol *symbol; + uintptr_t start, end; + + for (size_t i = 0; i < symbol_table_size; i++) { + symbol = &symbol_table_ptr[i]; + + if (!symbol->name || (symbol->size == 0)) { + continue; + } + + start = symbol->addr; + end = symbol->addr + symbol->size; + + if ((addr >= start) && (addr < end)) { + return symbol; + } + } + + return NULL; +} diff --git a/kern/symbol.h b/kern/symbol.h new file mode 100644 index 00000000..61fbf3f0 --- /dev/null +++ b/kern/symbol.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Agustina Arzille. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KERN_SYMBOL_H +#define KERN_SYMBOL_H + +#include <stdint.h> + +#include <kern/macros.h> + +#define __symbol_table __section(".symbol") + +/* + * Symbol structure. + * + * This structure is public. + */ +struct symbol { + uintptr_t addr; + uintptr_t size; + const char *name; +}; + +/* + * Look up a symbol from an address. + * + * NULL is returned if no symbol was found for the given address. + */ +const struct symbol * symbol_lookup(uintptr_t addr); + +#endif /* KERN_SYMBOL_H */ diff --git a/tools/gen_symtab.py b/tools/gen_symtab.py new file mode 100755 index 00000000..b691da12 --- /dev/null +++ b/tools/gen_symtab.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +''' +Embedded symbol table generator. +''' + +import sys + +symtab_size = 0 +symtab = [] + +for line in sys.stdin: + line = line.strip() + parts = line.split(' ') + del parts[2] + + if len(parts) != 3 or parts[2].startswith("__func__."): + continue + + symtab.append("{ 0x%s, 0x%s, \"%s\" }" % tuple(parts)) + symtab_size += 1 + +print("#include <kern/symbol.h>") +print("const struct symbol symbol_table[] __symbol_table = {") + +for elem in symtab: + print(" " + elem + ",",) + +print("};") +print("const size_t symbol_table_size = %d;" % symtab_size) +print("const struct symbol *symbol_table_ptr = symbol_table;") |