From a3ea6b3189514d463f655d400215cc6d752778e0 Mon Sep 17 00:00:00 2001
From: Justus Winter <4winter@informatik.uni-hamburg.de>
Date: Sun, 14 Sep 2014 13:35:50 +0200
Subject: [PATCH] dde: add support for ELF symbol tables XXX
---
Makefrag.am | 2 +
ddb/db_elf.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++
ddb/db_elf.h | 52 +++++++++++
ddb/db_sym.c | 12 ++-
ddb/db_sym.h | 7 ++
i386/i386at/model_dep.c | 25 ++++++
6 files changed, 327 insertions(+), 1 deletion(-)
create mode 100644 ddb/db_elf.c
create mode 100644 ddb/db_elf.h
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..43160f0
--- /dev/null
+++ b/ddb/db_elf.c
@@ -0,0 +1,230 @@
+/*
+ * 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 .
+ */
+/*
+ * 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
+#include
+#include
+#include /* data types */
+#include
+#include
+#include
+#include
+
+#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)
+{
+ 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,
+ "ELF",
+ (char *) phystokv (strtab->sh_addr),
+ 0)) {
+ db_printf ("Loaded ELF symbol table (%d symbols)\n",
+ 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
+#include
+
+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..3c1a7a0 100644
--- a/ddb/db_sym.c
+++ b/ddb/db_sym.c
@@ -38,6 +38,7 @@
#include
#include
#include
+#include
#include /* vm_map_t */
@@ -507,6 +508,8 @@ 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 +524,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..a0bbf80 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,12 @@ 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);
+
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..40d6b79 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -82,7 +82,16 @@
#if MACH_KDB
#include
#include
+
+/* 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,11 @@ 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);
+ }
#endif /* MACH_KDB */
machine_slot[0].is_cpu = TRUE;
--
2.1.0