/*
* 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,
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 */