#include "defs.h"
#include "bfd.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdb-stabs.h"
#include "target.h"
#include <sys/types.h>
#include "gdb_stat.h"
#include <fcntl.h>
#include "obstack.h"
#include "gdb_string.h"
#include "breakpoint.h"
#include <assert.h>
#ifndef TEXT_SECTION_NAME
#define TEXT_SECTION_NAME ".text"
#endif
#ifndef DATA_SECTION_NAME
#define DATA_SECTION_NAME ".data"
#endif
#define MAPPED_SYMFILES (USE_MMALLOC && HAVE_MMAP)
static void add_to_objfile_sections (bfd *, sec_ptr, PTR);
struct objfile *object_files;
struct objfile *current_objfile;
struct objfile *symfile_objfile;
struct objfile *rt_common_objfile;
int mapped_symbol_files;
#ifndef TARGET_KEEP_SECTION
#define TARGET_KEEP_SECTION(ASECT) 0
#endif
static void
add_to_objfile_sections (bfd *abfd, sec_ptr asect, PTR objfile_p_char)
{
struct objfile *objfile = (struct objfile *) objfile_p_char;
struct obj_section section;
flagword aflag;
aflag = bfd_get_section_flags (abfd, asect);
if (!(aflag & SEC_ALLOC) && !(TARGET_KEEP_SECTION (asect)))
return;
if (0 == bfd_section_size (abfd, asect))
return;
section.offset = 0;
section.objfile = objfile;
section.the_bfd_section = asect;
section.ovly_mapped = 0;
section.addr = bfd_section_vma (abfd, asect);
section.endaddr = section.addr + bfd_section_size (abfd, asect);
obstack_grow (&objfile->psymbol_obstack, (char *) §ion, sizeof (section));
objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1);
}
int
build_objfile_section_table (struct objfile *objfile)
{
objfile->sections_end = 0;
bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *) objfile);
objfile->sections = (struct obj_section *)
obstack_finish (&objfile->psymbol_obstack);
objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end;
return (0);
}
#if MAPPED_SYMFILES
static int
open_existing_mapped_file (char *symsfilename, long mtime, int mapped)
{
int fd = -1;
struct stat sbuf;
if (stat (symsfilename, &sbuf) == 0)
{
if (sbuf.st_mtime < mtime)
{
if (!mapped)
{
warning ("mapped symbol file `%s' is out of date, ignored it",
symsfilename);
}
}
else if ((fd = open (symsfilename, O_RDWR)) < 0)
{
if (error_pre_print)
{
printf_unfiltered (error_pre_print);
}
print_sys_errmsg (symsfilename, errno);
}
}
return (fd);
}
struct objfile *
open_mapped_objfile (bfd *abfd, int mapped, CORE_ADDR mapaddr)
{
char *filename = NULL;
time_t mtime = 0;
char *symsfilename = NULL;
int fd = -1;
PTR md = NULL;
struct objfile *objfile;
void *mapto;
filename = bfd_get_filename (abfd);
mtime = bfd_get_mtime (abfd);
symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL);
fd = open_existing_mapped_file (symsfilename, mtime, mapped);
free (symsfilename);
if (fd < 0)
{
symsfilename = concat (filename, ".syms", (char *) NULL);
fd = open_existing_mapped_file (symsfilename, mtime, mapped);
free (symsfilename);
}
if (fd < 0)
return NULL;
md = mmalloc_attach (fd, (PTR) 0);
if (md == NULL)
{
warning ("unable to attach to mapped file; ignoring");
return NULL;
}
mapto = (void *) mmalloc_getkey (md, 1);
if (mapto != (void *) md)
{
warning ("file is mapped at invalid address 0x%lx (should be 0x%lx)",
(unsigned long) md, (unsigned long) mapto);
return NULL;
}
#if 0
md = mmalloc_detach (md);
if (md != NULL)
{
warning ("unable to detach from mapped file; ignoring");
return NULL;
}
md = mmalloc_attach (fd, (PTR) mapto);
if (md == NULL)
{
warning ("unable to attach to mapped file; ignoring");
return NULL;
}
#endif
objfile = (struct objfile *) mmalloc_getkey (md, 0);
if (objfile == NULL)
{
warning ("unable to read objfile from mapped symbol file; ignoring");
return NULL;
}
init_malloc (md);
objfile->md = md;
objfile->mmfd = fd;
obstack_chunkfun (&objfile->psymbol_cache.cache, xmmalloc);
obstack_freefun (&objfile->psymbol_cache.cache, mfree);
obstack_chunkfun (&objfile->psymbol_obstack, xmmalloc);
obstack_freefun (&objfile->psymbol_obstack, mfree);
obstack_chunkfun (&objfile->symbol_obstack, xmmalloc);
obstack_freefun (&objfile->symbol_obstack, mfree);
obstack_chunkfun (&objfile->type_obstack, xmmalloc);
obstack_freefun (&objfile->type_obstack, mfree);
unlink_objfile (objfile);
objfile->sf = NULL;
return objfile;
}
struct objfile *
create_mapped_objfile (abfd, mapped, mapaddr)
bfd *abfd;
int mapped;
CORE_ADDR mapaddr;
{
char *filename = NULL;
time_t mtime = 0;
char *symsfilename = NULL;
int fd = -1;
PTR md = NULL;
struct objfile *objfile;
void *mapto;
filename = bfd_get_filename (abfd);
mtime = bfd_get_mtime (abfd);
symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL);
fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
{
if (error_pre_print)
{
printf_unfiltered (error_pre_print);
}
print_sys_errmsg (symsfilename, errno);
return NULL;
}
if (mapaddr == NULL)
{
mapaddr = (void *) mmalloc_findbase (64 * 1024 * 1024);
if (mapaddr == 0)
return NULL;
}
ftruncate (fd, 0);
md = mmalloc_attach (fd, (PTR) mapaddr);
if (md == NULL)
{
warning ("unable to map symbol file at 0x%lx", (unsigned long) mapaddr);
return NULL;
}
mmalloc_setkey (md, 1, (PTR) mapaddr);
init_malloc (md);
objfile = (struct objfile *) xmmalloc (md, sizeof (struct objfile));
memset (objfile, 0, sizeof (struct objfile));
objfile->md = md;
objfile->mmfd = fd;
objfile->flags |= OBJF_MAPPED;
mmalloc_setkey (objfile->md, 0, objfile);
obstack_specify_allocation_with_arg (&objfile->psymbol_cache.cache,
0, 0, xmmalloc, mfree,
objfile->md);
obstack_specify_allocation_with_arg (&objfile->psymbol_obstack,
0, 0, xmmalloc, mfree,
objfile->md);
obstack_specify_allocation_with_arg (&objfile->symbol_obstack,
0, 0, xmmalloc, mfree,
objfile->md);
obstack_specify_allocation_with_arg (&objfile->type_obstack,
0, 0, xmmalloc, mfree,
objfile->md);
return objfile;
}
#endif
struct objfile *
allocate_objfile (bfd *abfd, int flags, CORE_ADDR mapaddr)
{
struct objfile *objfile = NULL;
struct objfile *last_one = NULL;
if (mapped_symbol_files)
flags |= OBJF_MAPPED;
#if MAPPED_SYMFILES
objfile = open_mapped_objfile (abfd, (flags & OBJF_MAPPED), mapaddr);
if ((objfile == NULL) && (flags & OBJF_MAPPED))
{
objfile = create_mapped_objfile (abfd, (flags & OBJF_MAPPED), mapaddr);
}
#else
if (flags & OBJF_MAPPED)
{
warning ("mapped symbol tables are not supported on this machine; missing or broken mmap().");
mapped_symbol_files = 0;
flags &= ~OBJF_MAPPED;
}
#endif
if (objfile == NULL)
{
objfile = (struct objfile *) xmalloc (sizeof (struct objfile));
memset (objfile, 0, sizeof (struct objfile));
objfile->md = NULL;
obstack_specify_allocation (&objfile->psymbol_cache.cache, 0, 0,
xmalloc, free);
obstack_specify_allocation (&objfile->psymbol_obstack, 0, 0, xmalloc,
free);
obstack_specify_allocation (&objfile->symbol_obstack, 0, 0, xmalloc,
free);
obstack_specify_allocation (&objfile->type_obstack, 0, 0, xmalloc,
free);
flags &= ~OBJF_MAPPED;
}
objfile->obfd = abfd;
if (objfile->name != NULL)
{
mfree (objfile->md, objfile->name);
}
if (abfd != NULL)
{
objfile->name = mstrsave (objfile->md, bfd_get_filename (abfd));
objfile->mtime = bfd_get_mtime (abfd);
if (build_objfile_section_table (objfile))
{
error ("Can't find the file sections in `%s': %s",
objfile->name, bfd_errmsg (bfd_get_error ()));
}
}
objfile->sect_index_text = -1;
objfile->sect_index_data = -1;
objfile->sect_index_bss = -1;
objfile->sect_index_rodata = -1;
objfile->next = NULL;
if (object_files == NULL)
object_files = objfile;
else
{
for (last_one = object_files;
last_one->next;
last_one = last_one->next);
last_one->next = objfile;
}
objfile->flags |= flags;
return (objfile);
}
void
objfile_to_front (struct objfile *objfile)
{
struct objfile **objp;
for (objp = &object_files; *objp != NULL; objp = &((*objp)->next))
{
if (*objp == objfile)
{
*objp = objfile->next;
objfile->next = object_files;
object_files = objfile;
break;
}
}
}
void
unlink_objfile (struct objfile *objfile)
{
struct objfile **objpp;
for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp)->next))
{
if (*objpp == objfile)
{
*objpp = (*objpp)->next;
objfile->next = NULL;
break;
}
}
}
void
free_objfile (struct objfile *objfile)
{
if (objfile->sf != NULL)
{
(*objfile->sf->sym_finish) (objfile);
}
if (objfile->obfd != NULL)
{
char *name = bfd_get_filename (objfile->obfd);
if (!bfd_close (objfile->obfd))
warning ("cannot close \"%s\": %s",
name, bfd_errmsg (bfd_get_error ()));
free (name);
}
unlink_objfile (objfile);
if (objfile == rt_common_objfile)
rt_common_objfile = NULL;
#if defined (CLEAR_SOLIB)
CLEAR_SOLIB ();
{
struct target_ops *t = find_core_target ();
if (t != NULL)
(t->to_detach) (NULL, 0);
}
#endif
clear_pc_function_cache ();
#if MAPPED_SYMFILES
if (objfile->flags & OBJF_MAPPED)
{
int mmfd;
mmfd = objfile->mmfd;
mmalloc_detach (objfile->md);
objfile = NULL;
close (mmfd);
}
#endif
if (objfile != NULL)
{
if (objfile->name != NULL)
{
mfree (objfile->md, objfile->name);
}
if (objfile->global_psymbols.list)
mfree (objfile->md, objfile->global_psymbols.list);
if (objfile->static_psymbols.list)
mfree (objfile->md, objfile->static_psymbols.list);
free_bcache (&objfile->psymbol_cache);
obstack_free (&objfile->psymbol_obstack, 0);
obstack_free (&objfile->symbol_obstack, 0);
obstack_free (&objfile->type_obstack, 0);
mfree (objfile->md, objfile);
objfile = NULL;
}
{
extern struct target_ops exec_ops;
update_section_tables (¤t_target);
update_section_tables (&exec_ops);
}
}
void
update_section_tables (struct target_ops *target)
{
struct objfile *objfile;
struct obj_section *osection;
unsigned int nsections = 0;
struct section_table *sections, *tsection;
if (target->to_sections != NULL) {
assert (target->to_sections_end >= target->to_sections);
target->to_sections = NULL;
target->to_sections_end = NULL;
}
nsections = 0;
ALL_OBJSECTIONS (objfile, osection) {
nsections++;
}
sections = (struct section_table *) xmalloc (nsections * sizeof (struct section_table));
tsection = sections;
ALL_OBJSECTIONS (objfile, osection) {
assert (objfile != NULL);
assert (osection != NULL);
assert (osection->objfile != NULL);
tsection->addr = osection->addr;
tsection->endaddr = osection->endaddr;
tsection->the_bfd_section =osection->the_bfd_section;
tsection->bfd = osection->objfile->obfd;
tsection++;
}
target->to_sections = sections;
target->to_sections_end = sections + nsections;
}
static void
do_free_objfile_cleanup (void *obj)
{
free_objfile (obj);
}
struct cleanup *
make_cleanup_free_objfile (struct objfile *obj)
{
return make_cleanup (do_free_objfile_cleanup, obj);
}
void
free_all_objfiles (void)
{
struct objfile *objfile, *temp;
ALL_OBJFILES_SAFE (objfile, temp)
{
free_objfile (objfile);
}
clear_symtab_users ();
}
void
objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
{
struct section_offsets *delta =
(struct section_offsets *) alloca (SIZEOF_SECTION_OFFSETS);
{
int i;
int something_changed = 0;
for (i = 0; i < objfile->num_sections; ++i)
{
delta->offsets[i] =
ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i);
if (ANOFFSET (delta, i) != 0)
something_changed = 1;
}
if (!something_changed)
return;
}
{
struct symtab *s;
ALL_OBJFILE_SYMTABS (objfile, s)
{
struct linetable *l;
struct blockvector *bv;
int i;
l = LINETABLE (s);
if (l)
{
for (i = 0; i < l->nitems; ++i)
l->item[i].pc += ANOFFSET (delta, s->block_line_section);
}
if (!s->primary)
continue;
bv = BLOCKVECTOR (s);
for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
{
struct block *b;
int j;
b = BLOCKVECTOR_BLOCK (bv, i);
BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
for (j = 0; j < BLOCK_NSYMS (b); ++j)
{
struct symbol *sym = BLOCK_SYM (b, j);
fixup_symbol_section (sym, objfile);
if ((SYMBOL_CLASS (sym) == LOC_LABEL
|| SYMBOL_CLASS (sym) == LOC_STATIC
|| SYMBOL_CLASS (sym) == LOC_INDIRECT)
&& SYMBOL_SECTION (sym) >= 0)
{
SYMBOL_VALUE_ADDRESS (sym) +=
ANOFFSET (delta, SYMBOL_SECTION (sym));
}
#ifdef MIPS_EFI_SYMBOL_NAME
else if (SYMBOL_CLASS (sym) == LOC_CONST
&& SYMBOL_NAMESPACE (sym) == LABEL_NAMESPACE
&& STRCMP (SYMBOL_NAME (sym), MIPS_EFI_SYMBOL_NAME) == 0)
ecoff_relocate_efi (sym, ANOFFSET (delta,
s->block_line_section));
#endif
}
}
}
}
{
struct partial_symtab *p;
ALL_OBJFILE_PSYMTABS (objfile, p)
{
p->textlow += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
}
}
{
struct partial_symbol **psym;
for (psym = objfile->global_psymbols.list;
psym < objfile->global_psymbols.next;
psym++)
{
fixup_psymbol_section (*psym, objfile);
if (SYMBOL_SECTION (*psym) >= 0)
SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta,
SYMBOL_SECTION (*psym));
}
for (psym = objfile->static_psymbols.list;
psym < objfile->static_psymbols.next;
psym++)
{
fixup_psymbol_section (*psym, objfile);
if (SYMBOL_SECTION (*psym) >= 0)
SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta,
SYMBOL_SECTION (*psym));
}
}
{
struct minimal_symbol *msym;
ALL_OBJFILE_MSYMBOLS (objfile, msym)
if (SYMBOL_SECTION (msym) >= 0)
SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym));
}
msymbols_sort (objfile);
{
int i;
for (i = 0; i < objfile->num_sections; ++i)
(objfile->section_offsets)->offsets[i] = ANOFFSET (new_offsets, i);
}
if (objfile->ei.entry_point != ~(CORE_ADDR) 0)
{
struct obj_section *s;
s = find_pc_section (objfile->ei.entry_point);
if (s)
objfile->ei.entry_point += ANOFFSET (delta, s->the_bfd_section->index);
else
objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
}
{
struct obj_section *s;
bfd *abfd;
abfd = objfile->obfd;
ALL_OBJFILE_OSECTIONS (objfile, s)
{
int idx = s->the_bfd_section->index;
s->addr += ANOFFSET (delta, idx);
s->endaddr += ANOFFSET (delta, idx);
}
}
if (objfile->ei.entry_func_lowpc != INVALID_ENTRY_LOWPC)
{
objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
}
if (objfile->ei.entry_file_lowpc != INVALID_ENTRY_LOWPC)
{
objfile->ei.entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
objfile->ei.entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
}
if (objfile->ei.main_func_lowpc != INVALID_ENTRY_LOWPC)
{
objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
}
breakpoint_re_set ();
}
int
have_partial_symbols (void)
{
struct objfile *ofp;
ALL_OBJFILES (ofp)
{
if (ofp->psymtabs != NULL)
{
return 1;
}
}
return 0;
}
int
have_full_symbols (void)
{
struct objfile *ofp;
ALL_OBJFILES (ofp)
{
if (ofp->symtabs != NULL)
{
return 1;
}
}
return 0;
}
void
objfile_purge_solibs (void)
{
struct objfile *objf;
struct objfile *temp;
ALL_OBJFILES_SAFE (objf, temp)
{
#if 0
if (!(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED))
free_objfile (objf);
#endif
}
}
int
have_minimal_symbols (void)
{
struct objfile *ofp;
ALL_OBJFILES (ofp)
{
if (ofp->msymbols != NULL)
{
return 1;
}
}
return 0;
}
struct obj_section *
find_pc_sect_section (CORE_ADDR pc, struct sec *section)
{
struct obj_section *s;
struct objfile *objfile;
ALL_OBJSECTIONS (objfile, s)
if ((section == 0 || section == s->the_bfd_section) &&
s->addr <= pc && pc < s->endaddr)
return (s);
return (NULL);
}
struct obj_section *
find_pc_section (CORE_ADDR pc)
{
return find_pc_sect_section (pc, find_pc_mapped_section (pc));
}
int
in_plt_section (CORE_ADDR pc, char *name)
{
struct obj_section *s;
int retval = 0;
s = find_pc_section (pc);
retval = (s != NULL
&& s->the_bfd_section->name != NULL
&& STREQ (s->the_bfd_section->name, ".plt"));
return (retval);
}
int
is_in_import_list (char *name, struct objfile *objfile)
{
register int i;
if (!objfile || !name || !*name)
return 0;
for (i = 0; i < objfile->import_list_size; i++)
if (objfile->import_list[i] && STREQ (name, objfile->import_list[i]))
return 1;
return 0;
}