Reflects symbol table into the kernel
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 17 Jul 2013 01:47:03 +0000 (18:47 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 17 Jul 2013 01:47:03 +0000 (18:47 -0700)
The symbol table is processed and dumped into a C file, which gets compiled
into the kernel.  It's similar to Linux's kallsyms, just not as efficient.  It
allows us to map to and from addresses and symbols (char *s).

Makefile
kern/include/kdebug.h
kern/src/kdebug.c
scripts/link-kernel.sh [new file with mode: 0755]

index 04fd2d4..0499737 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -464,15 +464,17 @@ endif
 $(ext2_bdev_obj): $(ext2-bdev)
        $(Q)$(OBJCOPY) -I binary -B $(ld_arch) -O $(ld_emulation) $< $@
 
+# Not the worlds most elegant link command.  link-kernel takes the obj output
+# name, then the linker script, then everything else you'd dump on the ld
+# command line, including linker options and objects to link together.
+# 
+# After the script is done, we run the arch-specific command directly.
 quiet_cmd_link-akaros = LINK    $@
-      cmd_link-akaros = $(LD) -T kern/arch/$(ARCH)/$(KERNEL_LD) -o $@ \
-                              $(LDFLAGS_KERNEL) \
-                              $(akaros-deps) \
-                              $(gcc-lib) \
-                              $(kern_cpio_obj) \
-                              $(ext2_bdev_obj) ; \
-                              $(OBJDUMP) -S $@ > $@.asm; \
-                              $(ARCH_POST_LINK_CMD)
+      cmd_link-akaros = $(CONFIG_SHELL) scripts/link-kernel.sh $@ \
+                        kern/arch/$(ARCH)/$(KERNEL_LD) $(LDFLAGS_KERNEL) \
+                        $(akaros-deps) $(gcc-lib) $(kern_cpio_obj) \
+                        $(ext2_bdev_obj); \
+                        $(ARCH_POST_LINK_CMD)
 
 # For some reason, the if_changed doesn't work with FORCE (like it does in
 # Linux).  It looks like it can't find the .cmd file or something (also
index a6b7613..478e2f8 100644 (file)
@@ -4,6 +4,11 @@
 #include <ros/common.h>
 #include <arch/kdebug.h>
 
+struct symtab_entry {
+       char *name;
+       uintptr_t addr;
+};
+
 // Debug information about a particular instruction pointer
 typedef struct eipdebuginfo {
        const char *eip_file;           // Source code filename for EIP
@@ -27,4 +32,7 @@ static inline uintptr_t get_caller_pc(void);
  * instruction pointer.  kfree() the result. */
 char *get_fn_name(uintptr_t pc);
 
+/* Returns the address of sym, or 0 if it does not exist */
+uintptr_t get_symbol_addr(char *sym);
+
 #endif /* ROS_KERN_KDEBUG_H */
index 26fc430..0086279 100644 (file)
@@ -9,19 +9,43 @@
 #include <string.h>
 #include <assert.h>
 
+struct symtab_entry gbl_symtab[1] __attribute__((weak)) = {{0, 0}};
+
 /* Returns a null-terminated string with the function name for a given PC /
  * instruction pointer.  kfree() the result. */
 char *get_fn_name(uintptr_t pc)
 {
-       struct eipdebuginfo debuginfo;
+       struct symtab_entry *i, *prev = 0, *found = 0;
        char *buf;
-       if (debuginfo_eip(pc, &debuginfo))
+       size_t name_len;
+       /* Table is in ascending order.  As soon as we get to an entry greater than
+        * us, we were in the previous one.  This is only true if we were given a
+        * good PC.  Random addresses will just find the previous symbol. */
+       for (i = &gbl_symtab[0]; i->name; i++) {
+               if (i->addr > pc) {
+                       found = prev;
+                       break;
+               }
+               prev = i;
+       }
+       if (!found)
                return 0;
-       buf = kmalloc(debuginfo.eip_fn_namelen + 1, 0);
+       assert(found->name);
+       name_len = strlen(found->name) + 1;
+       buf = kmalloc(name_len, 0);
        if (!buf)
                return 0;
-       assert(debuginfo.eip_fn_name);
-       strncpy(buf, debuginfo.eip_fn_name, debuginfo.eip_fn_namelen);
-       buf[debuginfo.eip_fn_namelen] = 0;
+       strncpy(buf, found->name, name_len);
+       buf[name_len] = 0;
        return buf;
 }
+
+uintptr_t get_symbol_addr(char *sym)
+{
+       struct symtab_entry *i;
+       for (i = &gbl_symtab[0]; i->name; i++) {
+               if (strcmp(i->name, sym) == 0)
+                       return i->addr;
+       }
+       return 0;
+}
diff --git a/scripts/link-kernel.sh b/scripts/link-kernel.sh
new file mode 100755 (executable)
index 0000000..629e88b
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/bash
+# Kernel linking script
+#
+# This isn't the worlds most elegant link command.  link-kernel takes the obj
+# output name, then the linker script, then everything else you'd dump on the
+# ld command line, including linker options and objects to link together.
+#
+# We link extra times to resolve the reflected symbol table addresses.  After
+# the first link, we can generate the reflected symbol table of the appropriate
+# size.  Once we link it into the kernel, some addresses may have shifted, so
+# we repeat the creation of the ksyms and relink.  For more info, check out
+# Linux's kallsyms, their build script, and
+# http://stackoverflow.com/questions/11254891/can-a-running-c-program-access-its-own-symbol-table
+
+gen_symtab_obj()
+{
+       $NM -n $KERNEL_OBJECT > $KSYM_MAP
+       awk 'BEGIN{ print "#include <kdebug.h>";
+                   print "struct symtab_entry gbl_symtab[]={" }
+            { if(NF==3){print "{\"" $3 "\", 0x" $1 "},"}}
+            END{print "{0,0} };"}' $KSYM_MAP > $KSYM_C
+       $CC $NOSTDINC_FLAGS $AKAROSINCLUDE $CFLAGS_KERNEL -o $KSYM_O -c $KSYM_C
+}
+
+KERNEL_OBJECT=$1
+shift
+LINKER_SCRIPT=$1
+shift
+REMAINING_ARGS=$@
+
+KSYM_MAP=$OBJDIR/kern/ksyms.map
+KSYM_C=$OBJDIR/kern/ksyms-refl.c
+KSYM_O=$OBJDIR/kern/ksyms-refl.o
+
+# Use "make V=1" to debug this script (from Linux)
+case "${KBUILD_VERBOSE}" in
+*1*)
+       set -x
+       ;;
+esac
+
+# Generates the first version of $KERNEL_OBJECT
+$LD -T $LINKER_SCRIPT -o $KERNEL_OBJECT $REMAINING_ARGS
+
+# Generates a C and obj file with a table of the correct size, with relocs
+gen_symtab_obj
+
+# Links the syms with the kernel and inserts the glb_symtab in the kernel.
+$LD -T $LINKER_SCRIPT -o $KERNEL_OBJECT $REMAINING_ARGS $KSYM_O
+
+# Need to recheck/compute the symbols (table size won't change)
+gen_symtab_obj
+
+# Final link
+$LD -T $LINKER_SCRIPT -o $KERNEL_OBJECT $REMAINING_ARGS $KSYM_O
+
+# And objdump for debugging
+$OBJDUMP -S $KERNEL_OBJECT > $KERNEL_OBJECT.asm