diff options
-rw-r--r-- | Makefrag.am | 2 | ||||
-rw-r--r-- | ddb/db_elf.c | 232 | ||||
-rw-r--r-- | ddb/db_elf.h | 52 | ||||
-rw-r--r-- | ddb/db_sym.c | 14 | ||||
-rw-r--r-- | ddb/db_sym.h | 9 | ||||
-rw-r--r-- | i386/i386at/model_dep.c | 27 |
6 files changed, 335 insertions, 1 deletions
diff --git a/Makefrag.am b/Makefrag.am index d6dd77f..5e98b21 100644 --- a/Makefrag.am +++ b/Makefrag.am @@ -25,6 +25,8 @@ libkernel_a_SOURCES += \ ddb/db_access.h \ ddb/db_aout.c \ ddb/db_aout.h \ + ddb/db_elf.c \ + ddb/db_elf.h \ ddb/db_break.c \ ddb/db_break.h \ ddb/db_command.c \ diff --git a/ddb/db_elf.c b/ddb/db_elf.c new file mode 100644 index 0000000..10e7162 --- /dev/null +++ b/ddb/db_elf.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2014 Free Software Foundation, Inc. + * + * 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 2, 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/>. + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#if MACH_KDB + +/* + * Symbol table routines for ELF format files. + */ + +#include <string.h> +#include <mach/std_types.h> +#include <mach/exec/elf.h> +#include <machine/db_machdep.h> /* data types */ +#include <machine/vm_param.h> +#include <ddb/db_output.h> +#include <ddb/db_sym.h> +#include <ddb/db_elf.h> + +#ifndef DB_NO_ELF + +struct db_symtab_elf { + int type; + Elf32_Sym *start; + Elf32_Sym *end; + char *strings; + char *map_pointer; /* symbols are for this map only, + if not null */ + char name[SYMTAB_NAME_LEN]; + /* symtab name */ +}; + +boolean_t +elf_db_sym_init (unsigned shdr_num, + vm_size_t shdr_size, + vm_offset_t shdr_addr, + unsigned shdr_shndx, + char *name, + char *task_addr) +{ + Elf32_Shdr *shdr, *symtab, *strtab; + const char *shstrtab; + int i; + + if (shdr_num == 0) + return FALSE; + + if (shdr_size != sizeof *shdr) + return FALSE; + + shdr = (Elf32_Shdr *) shdr_addr; + + if (shdr[shdr_shndx].sh_type != SHT_STRTAB) + return FALSE; + + shstrtab = (const char *) phystokv (shdr[shdr_shndx].sh_addr); + + symtab = strtab = NULL; + for (i = 0; i < shdr_num; i++) + switch (shdr[i].sh_type) { + case SHT_SYMTAB: + if (symtab) + db_printf ("Ignoring additional ELF symbol table at %d\n", i); + else + symtab = &shdr[i]; + break; + + case SHT_STRTAB: + if (strcmp (&shstrtab[shdr[i].sh_name], ".strtab") == 0) { + if (strtab) + db_printf ("Ignoring additional ELF string table at %d\n", i); + else + strtab = &shdr[i]; + } + break; + } + + if (symtab == NULL || strtab == NULL) + return FALSE; + + if (db_add_symbol_table (SYMTAB_ELF, + (char *) phystokv (symtab->sh_addr), + (char *) phystokv (symtab->sh_addr)+symtab->sh_size, + name, + (char *) phystokv (strtab->sh_addr), + task_addr)) { + db_printf ("Loaded ELF symbol table for %s (%d symbols)\n", + name, symtab->sh_size / sizeof (Elf32_Sym)); + return TRUE; + } + + return FALSE; +} + +/* + * lookup symbol by name + */ +db_sym_t +elf_db_lookup (db_symtab_t *stab, + char *symstr) +{ + struct db_symtab_elf *self = (struct db_symtab_elf *) stab; + Elf32_Sym *s; + + for (s = self->start; s < self->end; s++) + if (strcmp (symstr, &self->strings[s->st_name]) == 0) + return (db_sym_t) s; + + return NULL; +} + +db_sym_t +elf_db_search_symbol (db_symtab_t *stab, + db_addr_t off, + db_strategy_t strategy, + db_expr_t *diffp) /* in/out */ +{ + struct db_symtab_elf *self = (struct db_symtab_elf *) stab; + unsigned long diff = *diffp; + Elf32_Sym *s, *symp = NULL; + + for (s = self->start; s < self->end; s++) { + if (s->st_name == 0) + continue; + + if (strategy == DB_STGY_XTRN && (s->st_info & STB_GLOBAL) == 0) + continue; + + if (off >= s->st_value) { + if (s->st_info == STT_FUNC) + continue; + + if (off - s->st_value < diff) { + diff = off - s->st_value; + symp = s; + if (diff == 0 && (s->st_info & STB_GLOBAL)) + break; + } else if (off - s->st_value == diff) { + if (symp == NULL) + symp = s; + else if ((symp->st_info & STB_GLOBAL) == 0 + && (s->st_info & STB_GLOBAL) != 0) + symp = s; /* pick the external symbol */ + } + } + } + + if (symp == NULL) + *diffp = off; + else + *diffp = diff; + + return (db_sym_t) symp; +} + +/* + * Return the name and value for a symbol. + */ +void +elf_db_symbol_values (db_symtab_t *stab, + db_sym_t sym, + char **namep, + db_expr_t *valuep) +{ + struct db_symtab_elf *self = (struct db_symtab_elf *) stab; + Elf32_Sym *s = (Elf32_Sym *) sym; + + if (namep) + *namep = &self->strings[s->st_name]; + if (valuep) + *valuep = s->st_value; +} + +/* + * Find filename and lineno within, given the current pc. + */ +boolean_t +elf_db_line_at_pc (db_symtab_t *stab, + db_sym_t sym, + char **file, + int *line, + db_addr_t pc) +{ + /* XXX Parse DWARF information. */ + return FALSE; +} + +#endif /* DB_NO_ELF */ + +#endif /* MACH_KDB */ diff --git a/ddb/db_elf.h b/ddb/db_elf.h new file mode 100644 index 0000000..12b8286 --- /dev/null +++ b/ddb/db_elf.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 Free Software Foundation. + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _DDB_DB_ELF_H_ +#define _DDB_DB_ELF_H_ + +#include <ddb/db_sym.h> +#include <machine/db_machdep.h> + +extern boolean_t +elf_db_line_at_pc( + db_symtab_t *stab, + db_sym_t sym, + char **file, + int *line, + db_addr_t pc); + +extern db_sym_t +elf_db_lookup( + db_symtab_t *stab, + char * symstr); + +extern db_sym_t +elf_db_search_symbol( + db_symtab_t * symtab, + db_addr_t off, + db_strategy_t strategy, + db_expr_t *diffp); + +extern void +elf_db_symbol_values( + db_symtab_t *stab, + db_sym_t sym, + char **namep, + db_expr_t *valuep); + +#endif /* _DDB_DB_ELF_H_ */ diff --git a/ddb/db_sym.c b/ddb/db_sym.c index 7d97d15..0179137 100644 --- a/ddb/db_sym.c +++ b/ddb/db_sym.c @@ -38,6 +38,7 @@ #include <ddb/db_sym.h> #include <ddb/db_task_thread.h> #include <ddb/db_aout.h> +#include <ddb/db_elf.h> #include <vm/vm_map.h> /* vm_map_t */ @@ -507,6 +508,10 @@ void db_free_symbol(db_sym_t s) */ void dummy_db_free_symbol(db_sym_t symbol) { } +boolean_t dummy_db_sym_init(char *a, char *b, char *c, char *d) { + return FALSE; +} + struct db_sym_switch x_db[] = { @@ -521,7 +526,14 @@ struct db_sym_switch x_db[] = { { 0,}, /* Machdep, not inited here */ - { 0,} + { 0,}, + +#ifdef DB_NO_ELF + { 0,}, +#else /* DB_NO_ELF */ + { dummy_db_sym_init, elf_db_lookup, elf_db_search_symbol, + elf_db_line_at_pc, elf_db_symbol_values, dummy_db_free_symbol }, +#endif /* DB_NO_ELF */ }; diff --git a/ddb/db_sym.h b/ddb/db_sym.h index 2c3e10a..d8f3387 100644 --- a/ddb/db_sym.h +++ b/ddb/db_sym.h @@ -46,6 +46,7 @@ typedef struct { #define SYMTAB_AOUT 0 #define SYMTAB_COFF 1 #define SYMTAB_MACHDEP 2 +#define SYMTAB_ELF 3 char *start; /* symtab location */ char *end; char *private; /* optional machdep pointer */ @@ -243,6 +244,14 @@ extern boolean_t aout_db_sym_init( char *name, char *task_addr); +extern boolean_t elf_db_sym_init ( + unsigned shdr_num, + vm_size_t shdr_size, + vm_offset_t shdr_addr, + unsigned shdr_shndx, + char *name, + char *task_addr); + db_sym_t db_lookup(char *); db_sym_t diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c index 209cfb1..bc34c9b 100644 --- a/i386/i386at/model_dep.c +++ b/i386/i386at/model_dep.c @@ -82,7 +82,16 @@ #if MACH_KDB #include <ddb/db_sym.h> #include <i386/db_interface.h> + +/* a.out symbol table */ static vm_offset_t kern_sym_start, kern_sym_end; + +/* ELF section header */ +static unsigned elf_shdr_num; +static vm_size_t elf_shdr_size; +static vm_offset_t elf_shdr_addr; +static unsigned elf_shdr_shndx; + #else /* MACH_KDB */ #define kern_sym_start 0 #define kern_sym_end 0 @@ -570,6 +579,17 @@ void c_boot_entry(vm_offset_t bi) kern_sym_start, kern_sym_end, symtab_size, strtab_size); } + + if ((boot_info.flags & MULTIBOOT_ELF_SHDR) + && boot_info.syms.e.num) + { + elf_shdr_num = boot_info.syms.e.num; + elf_shdr_size = boot_info.syms.e.size; + elf_shdr_addr = (vm_offset_t)phystokv(boot_info.syms.e.addr); + elf_shdr_shndx = boot_info.syms.e.shndx; + + printf("ELF section header table at %08lx\n", elf_shdr_addr); + } #endif /* MACH_KDB */ #endif /* MACH_XEN */ @@ -588,6 +608,13 @@ void c_boot_entry(vm_offset_t bi) { aout_db_sym_init((char *)kern_sym_start, (char *)kern_sym_end, "mach", (char *)0); } + + if (elf_shdr_num) + { + elf_db_sym_init(elf_shdr_num,elf_shdr_size, + elf_shdr_addr, elf_shdr_shndx, + "mach", NULL); + } #endif /* MACH_KDB */ machine_slot[0].is_cpu = TRUE; |