svn commit: r272098 - in head/sys: amd64/amd64 arm/arm ddb i386/i386 mips/mips pc98/pc98 powerpc/aim powerpc/booke sparc64/sparc64 x86/xen

Roger Pau Monné royger at FreeBSD.org
Thu Sep 25 08:28:14 UTC 2014


Author: royger
Date: Thu Sep 25 08:28:10 2014
New Revision: 272098
URL: http://svnweb.freebsd.org/changeset/base/272098

Log:
  ddb: allow specifying the exact address of the symtab and strtab
  
  When the FreeBSD kernel is loaded from Xen the symtab and strtab are
  not loaded the same way as the native boot loader. This patch adds
  three new global variables to ddb that can be used to specify the
  exact position and size of those tables, so they can be directly used
  as parameters to db_add_symbol_table. A new helper is introduced, so callers
  that used to set ksym_start and ksym_end can use this helper to set the new
  variables.
  
  It also adds support for loading them from the Xen PVH port, that was
  previously missing those tables.
  
  Sponsored by: Citrix Systems R&D
  Reviewed by:	kib
  
  ddb/db_main.c:
   - Add three new global variables: ksymtab, kstrtab, ksymtab_size that
     can be used to specify the position and size of the symtab and
     strtab.
   - Use those new variables in db_init in order to call db_add_symbol_table.
   - Move the logic in db_init to db_fetch_symtab in order to set ksymtab,
     kstrtab, ksymtab_size from ksym_start and ksym_end.
  
  ddb/ddb.h:
   - Add prototype for db_fetch_ksymtab.
   - Declate the extern variables ksymtab, kstrtab and ksymtab_size.
  
  x86/xen/pv.c:
   - Add support for finding the symtab and strtab when booted as a Xen
     PVH guest. Since Xen loads the symtab and strtab as NetBSD expects
     to find them we have to adapt and use the same method.
  
  amd64/amd64/machdep.c:
  arm/arm/machdep.c:
  i386/i386/machdep.c:
  mips/mips/machdep.c:
  pc98/pc98/machdep.c:
  powerpc/aim/machdep.c:
  powerpc/booke/machdep.c:
  sparc64/sparc64/machdep.c:
   - Use the newly introduced db_fetch_ksymtab in order to set ksymtab,
     kstrtab and ksymtab_size.

Modified:
  head/sys/amd64/amd64/machdep.c
  head/sys/arm/arm/machdep.c
  head/sys/ddb/db_main.c
  head/sys/ddb/ddb.h
  head/sys/i386/i386/machdep.c
  head/sys/mips/mips/machdep.c
  head/sys/pc98/pc98/machdep.c
  head/sys/powerpc/aim/machdep.c
  head/sys/powerpc/booke/machdep.c
  head/sys/sparc64/sparc64/machdep.c
  head/sys/x86/xen/pv.c

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/amd64/amd64/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -184,9 +184,6 @@ struct init_ops init_ops = {
  * the physical address at which the kernel is loaded.
  */
 extern char kernphys[];
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
 
 struct msgbuf *msgbufp;
 
@@ -1823,6 +1820,10 @@ static caddr_t
 native_parse_preload_data(u_int64_t modulep)
 {
 	caddr_t kmdp;
+#ifdef DDB
+	vm_offset_t ksym_start;
+	vm_offset_t ksym_end;
+#endif
 
 	preload_metadata = (caddr_t)(uintptr_t)(modulep + KERNBASE);
 	preload_bootstrap_relocate(KERNBASE);
@@ -1834,6 +1835,7 @@ native_parse_preload_data(u_int64_t modu
 #ifdef DDB
 	ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
 	ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+	db_fetch_ksymtab(ksym_start, ksym_end);
 #endif
 
 	return (kmdp);

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/arm/arm/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -111,6 +111,10 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/openfirm.h>
 #endif
 
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
 #ifdef DEBUG
 #define	debugf(fmt, args...) printf(fmt, ##args)
 #else
@@ -131,9 +135,6 @@ int _min_memcpy_size = 0;
 int _min_bzero_size = 0;
 
 extern int *end;
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
 
 #ifdef FDT
 /*
@@ -817,8 +818,7 @@ fake_preload_metadata(struct arm_boot_pa
 		lastaddr = *(uint32_t *)(KERNVIRTADDR + 8);
 		zend = lastaddr;
 		zstart = *(uint32_t *)(KERNVIRTADDR + 4);
-		ksym_start = zstart;
-		ksym_end = zend;
+		db_fetch_ksymtab(zstart, zend);
 	} else
 #endif
 		lastaddr = (vm_offset_t)&end;
@@ -912,6 +912,10 @@ freebsd_parse_boot_param(struct arm_boot
 	vm_offset_t lastaddr = 0;
 	void *mdp;
 	void *kmdp;
+#ifdef DDB
+	vm_offset_t ksym_start;
+	vm_offset_t ksym_end;
+#endif
 
 	/*
 	 * Mask metadata pointer: it is supposed to be on page boundary. If
@@ -934,6 +938,7 @@ freebsd_parse_boot_param(struct arm_boot
 #ifdef DDB
 	ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
 	ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+	db_fetch_ksymtab(ksym_start, ksym_end);
 #endif
 	preload_addr_relocate = KERNVIRTADDR - abp->abp_physaddr;
 	return lastaddr;

Modified: head/sys/ddb/db_main.c
==============================================================================
--- head/sys/ddb/db_main.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/ddb/db_main.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -56,7 +56,12 @@ static dbbe_trace_thread_f db_trace_thre
 KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper,
     db_trap);
 
-vm_offset_t ksym_start, ksym_end;
+/*
+ * Symbols can be loaded by specifying the exact addresses of
+ * the symtab and strtab in memory. This is used when loaded from
+ * boot loaders different than the native one (like Xen).
+ */
+vm_offset_t ksymtab, kstrtab, ksymtab_size;
 
 boolean_t
 X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
@@ -168,24 +173,39 @@ X_db_symbol_values(db_symtab_t *symtab, 
 	}
 }
 
+int
+db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end)
+{
+	Elf_Size strsz;
+
+	if (ksym_end > ksym_start && ksym_start != 0) {
+		ksymtab = ksym_start;
+		ksymtab_size = *(Elf_Size*)ksymtab;
+		ksymtab += sizeof(Elf_Size);
+		kstrtab = ksymtab + ksymtab_size;
+		strsz = *(Elf_Size*)kstrtab;
+		kstrtab += sizeof(Elf_Size);
+		if (kstrtab + strsz > ksym_end) {
+			/* Sizes doesn't match, unset everything. */
+			ksymtab = ksymtab_size = kstrtab = 0;
+		}
+	}
+
+	if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0)
+		return (-1);
+
+	return (0);
+}
+
 static int
 db_init(void)
 {
-	uintptr_t symtab, strtab;
-	Elf_Size tabsz, strsz;
 
 	db_command_init();
-	if (ksym_end > ksym_start && ksym_start != 0) {
-		symtab = ksym_start;
-		tabsz = *((Elf_Size*)symtab);
-		symtab += sizeof(Elf_Size);
-		strtab = symtab + tabsz;
-		strsz = *((Elf_Size*)strtab);
-		strtab += sizeof(Elf_Size);
-		if (strtab + strsz <= ksym_end) {
-			db_add_symbol_table((char *)symtab,
-			    (char *)(symtab + tabsz), "elf", (char *)strtab);
-		}
+
+	if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) {
+		db_add_symbol_table((char *)ksymtab,
+		    (char *)(ksymtab + ksymtab_size), "elf", (char *)kstrtab);
 	}
 	db_add_symbol_table(NULL, NULL, "kld", NULL);
 	return (1);	/* We're the default debugger. */

Modified: head/sys/ddb/ddb.h
==============================================================================
--- head/sys/ddb/ddb.h	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/ddb/ddb.h	Thu Sep 25 08:28:10 2014	(r272098)
@@ -77,6 +77,13 @@ int	DB_CALL(db_expr_t, db_expr_t *, int,
 #endif
 
 /*
+ * Extern variables to set the address and size of the symtab and strtab.
+ * Most users should use db_fetch_symtab in order to set them from the
+ * boot loader provided values.
+ */
+extern vm_offset_t ksymtab, kstrtab, ksymtab_size;
+
+/*
  * There are three "command tables":
  * - One for simple commands; a list of these is displayed
  *   by typing 'help' at the debugger prompt.
@@ -218,6 +225,7 @@ int		db_value_of_name_vnet(const char *n
 int		db_write_bytes(vm_offset_t addr, size_t size, char *data);
 void		db_command_register(struct command_table *, struct command *);
 void		db_command_unregister(struct command_table *, struct command *);
+int		db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end);
 
 db_cmdfcn_t	db_breakpoint_cmd;
 db_cmdfcn_t	db_capture_cmd;

Modified: head/sys/i386/i386/machdep.c
==============================================================================
--- head/sys/i386/i386/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/i386/i386/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -197,10 +197,6 @@ static void fill_fpregs_xmm(struct savex
 #endif /* CPU_ENABLE_SSE */
 SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
 
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
-
 /* Intel ICH registers */
 #define ICH_PMBASE	0x400
 #define ICH_SMI_EN	ICH_PMBASE + 0x30
@@ -2736,8 +2732,7 @@ init386(first)
 #endif
 
 #ifdef DDB
-	ksym_start = bootinfo.bi_symtab;
-	ksym_end = bootinfo.bi_esymtab;
+	db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab);
 #endif
 
 	kdb_init();
@@ -3013,8 +3008,7 @@ init386(first)
 #endif
 
 #ifdef DDB
-	ksym_start = bootinfo.bi_symtab;
-	ksym_end = bootinfo.bi_esymtab;
+	db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab);
 #endif
 
 	kdb_init();

Modified: head/sys/mips/mips/machdep.c
==============================================================================
--- head/sys/mips/mips/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/mips/mips/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -167,9 +167,6 @@ extern char MipsCache[], MipsCacheEnd[];
 extern char MipsWaitStart[], MipsWaitEnd[];
 
 extern char edata[], end[];
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
 
 u_int32_t bootdev;
 struct bootinfo bootinfo;
@@ -434,6 +431,8 @@ mips_postboot_fixup(void)
 #ifdef DDB
 	Elf_Size *trampoline_data = (Elf_Size*)kernel_kseg0_end;
 	Elf_Size symtabsize = 0;
+	vm_offset_t ksym_start;
+	vm_offset_t ksym_end;
 
 	if (trampoline_data[0] == SYMTAB_MAGIC) {
 		symtabsize = trampoline_data[1];
@@ -443,6 +442,7 @@ mips_postboot_fixup(void)
 		kernel_kseg0_end += symtabsize;
 		/* end of .strtab */
 		ksym_end = kernel_kseg0_end;
+		db_fetch_ksymtab(ksym_start, ksym_end);
 	}
 #endif
 }

Modified: head/sys/pc98/pc98/machdep.c
==============================================================================
--- head/sys/pc98/pc98/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/pc98/pc98/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -169,10 +169,6 @@ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST,
 int	need_pre_dma_flush;	/* If 1, use wbinvd befor DMA transfer. */
 int	need_post_dma_flush;	/* If 1, use invd after DMA transfer. */
 
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
-
 int	_udatasel, _ucodesel;
 u_int	basemem;
 
@@ -2298,8 +2294,7 @@ init386(first)
 #endif
 
 #ifdef DDB
-	ksym_start = bootinfo.bi_symtab;
-	ksym_end = bootinfo.bi_esymtab;
+	db_fetch_ksymtab(bootinfo.bi_symtab,bootinfo.bi_esymtab);
 #endif
 
 	kdb_init();

Modified: head/sys/powerpc/aim/machdep.c
==============================================================================
--- head/sys/powerpc/aim/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/powerpc/aim/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -129,10 +129,6 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/ofw/openfirm.h>
 
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
-
 int cold = 1;
 #ifdef __powerpc64__
 extern int n_slbs;
@@ -268,6 +264,10 @@ powerpc_init(vm_offset_t startkernel, vm
 	#ifndef __powerpc64__
 	int		ppc64;
 	#endif
+#ifdef DDB
+	vm_offset_t ksym_start;
+	vm_offset_t ksym_end;
+#endif
 
 	kmdp = NULL;
 	trap_offset = 0;
@@ -302,6 +302,7 @@ powerpc_init(vm_offset_t startkernel, vm
 #ifdef DDB
 			ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
 			ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+			db_fetch_ksymtab(ksym_start, ksym_end);
 #endif
 		}
 	}

Modified: head/sys/powerpc/booke/machdep.c
==============================================================================
--- head/sys/powerpc/booke/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/powerpc/booke/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -142,7 +142,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/openfirm.h>
 
 #ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
+#include <ddb/ddb.h>
 #endif
 
 #ifdef  DEBUG
@@ -300,6 +300,10 @@ booke_init(uint32_t arg1, uint32_t arg2)
 	struct pcpu *pc;
 	void *kmdp, *mdp;
 	vm_offset_t dtbp, end;
+#ifdef DDB
+	vm_offset_t ksym_start;
+	vm_offset_t ksym_end;
+#endif
 
 	kmdp = NULL;
 
@@ -360,6 +364,7 @@ booke_init(uint32_t arg1, uint32_t arg2)
 #ifdef DDB
 			ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
 			ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+			db_fetch_ksymtab(ksym_start, ksym_end);
 #endif
 		}
 	} else {

Modified: head/sys/sparc64/sparc64/machdep.c
==============================================================================
--- head/sys/sparc64/sparc64/machdep.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/sparc64/sparc64/machdep.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -114,10 +114,6 @@ __FBSDID("$FreeBSD$");
 
 typedef int ofw_vec_t(void *);
 
-#ifdef DDB
-extern vm_offset_t ksym_start, ksym_end;
-#endif
-
 int dtlb_slots;
 int itlb_slots;
 struct tlb_entry *kernel_tlbs;

Modified: head/sys/x86/xen/pv.c
==============================================================================
--- head/sys/x86/xen/pv.c	Thu Sep 25 07:37:41 2014	(r272097)
+++ head/sys/x86/xen/pv.c	Thu Sep 25 08:28:10 2014	(r272098)
@@ -29,12 +29,15 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_ddb.h"
+
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/reboot.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
+#include <sys/linker.h>
 #include <sys/lock.h>
 #include <sys/rwlock.h>
 #include <sys/boot.h>
@@ -66,6 +69,10 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/xen/timer/timer.h>
 
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
 /* Native initial function */
 extern u_int64_t hammer_time(u_int64_t, u_int64_t);
 /* Xen initial function */
@@ -93,6 +100,12 @@ extern int bootAP;
 extern char *bootSTK;
 #endif
 
+/*
+ * Placed by the linker at the end of the bss section, which is the last
+ * section loaded by Xen before loading the symtab and strtab.
+ */
+extern uint32_t end;
+
 /*-------------------------------- Global Data -------------------------------*/
 /* Xen init_ops implementation. */
 struct init_ops xen_init_ops = {
@@ -297,6 +310,68 @@ xen_pv_set_boothowto(void)
 	}
 }
 
+#ifdef DDB
+/*
+ * The way Xen loads the symtab is different from the native boot loader,
+ * because it's tailored for NetBSD. So we have to adapt and use the same
+ * method as NetBSD. Portions of the code below have been picked from NetBSD:
+ * sys/kern/kern_ksyms.c CVS Revision 1.71.
+ */
+static void
+xen_pv_parse_symtab(void)
+{
+	Elf_Ehdr *ehdr;
+	Elf_Shdr *shdr;
+	vm_offset_t sym_end;
+	uint32_t size;
+	int i, j;
+
+	size = end;
+	sym_end = HYPERVISOR_start_info->mod_start != 0 ?
+	    HYPERVISOR_start_info->mod_start :
+	    HYPERVISOR_start_info->mfn_list;
+
+	/*
+	 * Make sure the size is right headed, sym_end is just a
+	 * high boundary, but at least allows us to fail earlier.
+	 */
+	if ((vm_offset_t)&end + size > sym_end) {
+		xc_printf("Unable to load ELF symtab: size mismatch\n");
+		return;
+	}
+
+	ehdr = (Elf_Ehdr *)(&end + 1);
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
+	    ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+	    ehdr->e_version > 1) {
+		xc_printf("Unable to load ELF symtab: invalid symbol table\n");
+		return;
+	}
+
+	shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff);
+	/* Find the symbol table and the corresponding string table. */
+	for (i = 1; i < ehdr->e_shnum; i++) {
+		if (shdr[i].sh_type != SHT_SYMTAB)
+			continue;
+		if (shdr[i].sh_offset == 0)
+			continue;
+		ksymtab = (uintptr_t)((uint8_t *)ehdr + shdr[i].sh_offset);
+		ksymtab_size = shdr[i].sh_size;
+		j = shdr[i].sh_link;
+		if (shdr[j].sh_offset == 0)
+			continue; /* Can this happen? */
+		kstrtab = (uintptr_t)((uint8_t *)ehdr + shdr[j].sh_offset);
+		break;
+	}
+
+	if (ksymtab == 0 || kstrtab == 0) {
+		xc_printf(
+    "Unable to load ELF symtab: could not find symtab or strtab\n");
+		return;
+	}
+}
+#endif
+
 static caddr_t
 xen_pv_parse_preload_data(u_int64_t modulep)
 {
@@ -304,6 +379,10 @@ xen_pv_parse_preload_data(u_int64_t modu
 	xen_pv_set_env();
 	xen_pv_set_boothowto();
 
+#ifdef DDB
+	xen_pv_parse_symtab();
+#endif
+
 	return (NULL);
 }
 


More information about the svn-src-all mailing list