aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorRoger Pau Monné <royger@FreeBSD.org>2014-09-25 08:28:10 +0000
committerRoger Pau Monné <royger@FreeBSD.org>2014-09-25 08:28:10 +0000
commitc98a2727cc0905d5b478b577668222e8d5d32e81 (patch)
tree3abf237e04642b4e670e2e2b0e6e7072f1ee5524 /sys
parent5af6947046740202e589436161d76190377f8f90 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/amd64/machdep.c8
-rw-r--r--sys/arm/arm/machdep.c15
-rw-r--r--sys/ddb/db_main.c48
-rw-r--r--sys/ddb/ddb.h8
-rw-r--r--sys/i386/i386/machdep.c10
-rw-r--r--sys/mips/mips/machdep.c6
-rw-r--r--sys/pc98/pc98/machdep.c7
-rw-r--r--sys/powerpc/aim/machdep.c9
-rw-r--r--sys/powerpc/booke/machdep.c7
-rw-r--r--sys/sparc64/sparc64/machdep.c4
-rw-r--r--sys/x86/xen/pv.c79
11 files changed, 153 insertions, 48 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index c54b3b1660a3..278409dd0f40 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -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 modulep)
#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);
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
index 8a782325dcb1..98c424e21953 100644
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -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_params *abp __unused)
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_params *abp)
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_params *abp)
#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;
diff --git a/sys/ddb/db_main.c b/sys/ddb/db_main.c
index 6e9286cbc1c1..bee321cc34ed 100644
--- a/sys/ddb/db_main.c
+++ b/sys/ddb/db_main.c
@@ -56,7 +56,12 @@ static dbbe_trace_thread_f db_trace_thread_wrapper;
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, c_db_sym_t sym, const char **namep,
}
}
+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. */
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index 42fc9025954f..5aa646b3302a 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -77,6 +77,13 @@ int DB_CALL(db_expr_t, db_expr_t *, int, db_expr_t[]);
#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 *name, db_expr_t *valuep);
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;
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 94e9db4f0fd4..a3990ed63649 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -197,10 +197,6 @@ static void fill_fpregs_xmm(struct savexmm *, struct save87 *);
#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();
diff --git a/sys/mips/mips/machdep.c b/sys/mips/mips/machdep.c
index 6e9a4bdfb995..5d25d881fb6c 100644
--- a/sys/mips/mips/machdep.c
+++ b/sys/mips/mips/machdep.c
@@ -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
}
diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c
index c42b4ce4facb..848af79928b3 100644
--- a/sys/pc98/pc98/machdep.c
+++ b/sys/pc98/pc98/machdep.c
@@ -169,10 +169,6 @@ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
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();
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index 16b22904075e..17fc452f55e7 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/machdep.c
@@ -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_offset_t endkernel,
#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_offset_t endkernel,
#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
}
}
diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/machdep.c
index fc98ed6e1ef7..d3de34c81434 100644
--- a/sys/powerpc/booke/machdep.c
+++ b/sys/powerpc/booke/machdep.c
@@ -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 {
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index 587c90899a7b..0ee6de3a5131 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -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;
diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c
index c98c8bc912cd..c19d86accaa2 100644
--- a/sys/x86/xen/pv.c
+++ b/sys/x86/xen/pv.c
@@ -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 modulep)
xen_pv_set_env();
xen_pv_set_boothowto();
+#ifdef DDB
+ xen_pv_parse_symtab();
+#endif
+
return (NULL);
}