#include "defs.h"
#include "gdb_string.h"
#include "bfd.h"
#include "symtab.h"
#include "objfiles.h"
#include "buildsym.h"
#include "stabsread.h"
#include "coff/sym.h"
#include "coff/internal.h"
#include "coff/ecoff.h"
#include "libcoff.h"
#include "libecoff.h"
#include "elf/common.h"
#include "elf/mips.h"
static void
read_alphacoff_dynamic_symtab (struct section_offsets *,
struct objfile *objfile);
static void
mipscoff_new_init (struct objfile *ignore)
{
stabsread_new_init ();
buildsym_new_init ();
}
static void
mipscoff_symfile_init (struct objfile *objfile)
{
}
static void
mipscoff_symfile_read (struct objfile *objfile, int mainline)
{
bfd *abfd = objfile->obfd;
struct cleanup *back_to;
init_minimal_symbol_collection ();
back_to = make_cleanup_discard_minimal_symbols ();
if (!((*ecoff_backend (abfd)->debug_swap.read_debug_info)
(abfd, (asection *) NULL, &ecoff_data (abfd)->debug_info)))
error (_("Error reading symbol table: %s"), bfd_errmsg (bfd_get_error ()));
mdebug_build_psymtabs (objfile, &ecoff_backend (abfd)->debug_swap,
&ecoff_data (abfd)->debug_info);
read_alphacoff_dynamic_symtab (objfile->section_offsets, objfile);
install_minimal_symbols (objfile);
do_cleanups (back_to);
}
static void
mipscoff_symfile_finish (struct objfile *objfile)
{
}
typedef struct
{
unsigned char st_name[4];
unsigned char st_pad[4];
unsigned char st_value[8];
unsigned char st_size[4];
unsigned char st_info[1];
unsigned char st_other[1];
unsigned char st_shndx[2];
} Elfalpha_External_Sym;
typedef struct
{
unsigned char d_tag[4];
unsigned char d_pad[4];
union
{
unsigned char d_ptr[8];
unsigned char d_val[4];
}
d_un;
} Elfalpha_External_Dyn;
struct alphacoff_dynsecinfo
{
asection *sym_sect;
asection *str_sect;
asection *dyninfo_sect;
asection *got_sect;
};
static void
alphacoff_locate_sections (bfd *ignore_abfd, asection *sectp, void *sip)
{
struct alphacoff_dynsecinfo *si;
si = (struct alphacoff_dynsecinfo *) sip;
if (strcmp (sectp->name, ".dynsym") == 0)
si->sym_sect = sectp;
else if (strcmp (sectp->name, ".dynstr") == 0)
si->str_sect = sectp;
else if (strcmp (sectp->name, ".dynamic") == 0)
si->dyninfo_sect = sectp;
else if (strcmp (sectp->name, ".got") == 0)
si->got_sect = sectp;
}
static void
read_alphacoff_dynamic_symtab (struct section_offsets *section_offsets,
struct objfile *objfile)
{
bfd *abfd = objfile->obfd;
struct alphacoff_dynsecinfo si;
char *sym_secptr;
char *str_secptr;
char *dyninfo_secptr;
char *got_secptr;
bfd_size_type sym_secsize;
bfd_size_type str_secsize;
bfd_size_type dyninfo_secsize;
bfd_size_type got_secsize;
int sym_count;
int i;
int stripped;
Elfalpha_External_Sym *x_symp;
char *dyninfo_p;
char *dyninfo_end;
int got_entry_size = 8;
int dt_mips_local_gotno = -1;
int dt_mips_gotsym = -1;
struct cleanup *cleanups;
if (bfd_get_arch (abfd) != bfd_arch_alpha)
return;
memset ((char *) &si, 0, sizeof (si));
bfd_map_over_sections (abfd, alphacoff_locate_sections, (void *) & si);
if (si.sym_sect == NULL || si.str_sect == NULL
|| si.dyninfo_sect == NULL || si.got_sect == NULL)
return;
sym_secsize = bfd_get_section_size (si.sym_sect);
str_secsize = bfd_get_section_size (si.str_sect);
dyninfo_secsize = bfd_get_section_size (si.dyninfo_sect);
got_secsize = bfd_get_section_size (si.got_sect);
sym_secptr = xmalloc (sym_secsize);
cleanups = make_cleanup (free, sym_secptr);
str_secptr = xmalloc (str_secsize);
make_cleanup (free, str_secptr);
dyninfo_secptr = xmalloc (dyninfo_secsize);
make_cleanup (free, dyninfo_secptr);
got_secptr = xmalloc (got_secsize);
make_cleanup (free, got_secptr);
if (!bfd_get_section_contents (abfd, si.sym_sect, sym_secptr,
(file_ptr) 0, sym_secsize))
return;
if (!bfd_get_section_contents (abfd, si.str_sect, str_secptr,
(file_ptr) 0, str_secsize))
return;
if (!bfd_get_section_contents (abfd, si.dyninfo_sect, dyninfo_secptr,
(file_ptr) 0, dyninfo_secsize))
return;
if (!bfd_get_section_contents (abfd, si.got_sect, got_secptr,
(file_ptr) 0, got_secsize))
return;
for (dyninfo_p = dyninfo_secptr, dyninfo_end = dyninfo_p + dyninfo_secsize;
dyninfo_p < dyninfo_end;
dyninfo_p += sizeof (Elfalpha_External_Dyn))
{
Elfalpha_External_Dyn *x_dynp = (Elfalpha_External_Dyn *) dyninfo_p;
long dyn_tag;
dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_tag);
if (dyn_tag == DT_NULL)
break;
else if (dyn_tag == DT_MIPS_LOCAL_GOTNO)
{
if (dt_mips_local_gotno < 0)
dt_mips_local_gotno
= bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val);
}
else if (dyn_tag == DT_MIPS_GOTSYM)
{
if (dt_mips_gotsym < 0)
dt_mips_gotsym
= bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val);
}
}
if (dt_mips_local_gotno < 0 || dt_mips_gotsym < 0)
return;
sym_count = sym_secsize / sizeof (Elfalpha_External_Sym);
stripped = (bfd_get_symcount (abfd) == 0);
for (i = 1, x_symp = (Elfalpha_External_Sym *) sym_secptr + 1;
i < sym_count;
i++, x_symp++)
{
unsigned long strx;
char *name;
bfd_vma sym_value;
unsigned char sym_info;
unsigned int sym_shndx;
int isglobal;
enum minimal_symbol_type ms_type;
strx = bfd_h_get_32 (abfd, (bfd_byte *) x_symp->st_name);
if (strx >= str_secsize)
continue;
name = str_secptr + strx;
if (*name == '\0' || *name == '.')
continue;
sym_value = bfd_h_get_64 (abfd, (bfd_byte *) x_symp->st_value);
sym_info = bfd_h_get_8 (abfd, (bfd_byte *) x_symp->st_info);
sym_shndx = bfd_h_get_16 (abfd, (bfd_byte *) x_symp->st_shndx);
isglobal = (ELF_ST_BIND (sym_info) == STB_GLOBAL);
if (sym_shndx == SHN_UNDEF)
{
if (ELF_ST_TYPE (sym_info) != STT_FUNC
|| ELF_ST_BIND (sym_info) != STB_GLOBAL)
continue;
ms_type = mst_solib_trampoline;
if (sym_value == 0)
{
int got_entry_offset =
(i - dt_mips_gotsym + dt_mips_local_gotno) * got_entry_size;
if (got_entry_offset < 0 || got_entry_offset >= got_secsize)
continue;
sym_value =
bfd_h_get_64 (abfd,
(bfd_byte *) (got_secptr + got_entry_offset));
if (sym_value == 0)
continue;
}
}
else
{
if (!stripped)
continue;
if (sym_shndx == SHN_MIPS_TEXT)
{
if (isglobal)
ms_type = mst_text;
else
ms_type = mst_file_text;
sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile));
}
else if (sym_shndx == SHN_MIPS_DATA)
{
if (isglobal)
ms_type = mst_data;
else
ms_type = mst_file_data;
sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA (objfile));
}
else if (sym_shndx == SHN_MIPS_ACOMMON)
{
if (isglobal)
ms_type = mst_bss;
else
ms_type = mst_file_bss;
sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS (objfile));
}
else if (sym_shndx == SHN_ABS)
{
ms_type = mst_abs;
}
else
{
continue;
}
}
prim_record_minimal_symbol (name, sym_value, ms_type, objfile);
}
do_cleanups (cleanups);
}
static struct sym_fns ecoff_sym_fns =
{
bfd_target_ecoff_flavour,
mipscoff_new_init,
mipscoff_symfile_init,
mipscoff_symfile_read,
mipscoff_symfile_finish,
default_symfile_offsets,
NULL
};
void _initialize_mipsread (void);
void
_initialize_mipsread (void)
{
add_symtab_fns (&ecoff_sym_fns);
}