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 #endif +#ifdef DDB +#include +#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 @@ -76,6 +76,13 @@ SYSCTL_DECL(_debug_ddb); 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 @@ -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 -#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 #ifdef DDB -extern vm_offset_t ksym_start, ksym_end; +#include #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 __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" + #include #include #include #include #include #include +#include #include #include #include @@ -66,6 +69,10 @@ __FBSDID("$FreeBSD$"); #include +#ifdef DDB +#include +#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); }