mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
59d41830a3
With the previous commits, the only thing entangling elf and coff file reading with dbx file reading is the functions {elf|coff}stab_build_psymtabs, defined in dbxread.c. These functions depend on dbx_symfile_read. To solve this, I renamed read_stabs_symtab to read_stabs_symtab_1, and created a function with the original name that does what dbx_symfile_read used to do. This way, dbx_symfile_read can just call read_stabs_symtab, and the elf and coff psymtab builders can also call it directly, fully disentangling the readers, which would allow us to selectively not compile dbxread in the future. Approved-By: Tom Tromey <tom@tromey.com>
358 lines
12 KiB
C
358 lines
12 KiB
C
/* Read dbx symbol tables and convert to internal format, for GDB.
|
||
Copyright (C) 1986-2024 Free Software Foundation, Inc.
|
||
|
||
This file is part of GDB.
|
||
|
||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||
|
||
/* This module provides three functions: dbx_symfile_init,
|
||
which initializes to read a symbol file; dbx_new_init, which
|
||
discards existing cached information when all symbols are being
|
||
discarded; and dbx_symfile_read, which reads a symbol table
|
||
from a file.
|
||
|
||
dbx_symfile_read only does the minimum work necessary for letting the
|
||
user "name" things symbolically; it does not read the entire symtab.
|
||
Instead, it reads the external and static symbols and puts them in partial
|
||
symbol tables. When more extensive information is requested of a
|
||
file, the corresponding partial symbol table is mutated into a full
|
||
fledged symbol table by going back and reading the symbols
|
||
for real. dbx_psymtab_to_symtab() is the function that does this */
|
||
|
||
|
||
#include "event-top.h"
|
||
#include "gdbsupport/gdb_obstack.h"
|
||
#include <sys/stat.h>
|
||
#include "symtab.h"
|
||
#include "breakpoint.h"
|
||
#include "target.h"
|
||
#include "gdbcore.h"
|
||
#include "libaout.h"
|
||
#include "filenames.h"
|
||
#include "objfiles.h"
|
||
#include "buildsym-legacy.h"
|
||
#include "stabsread.h"
|
||
#include "gdb-stabs.h"
|
||
#include "demangle.h"
|
||
#include "complaints.h"
|
||
#include "cp-abi.h"
|
||
#include "cp-support.h"
|
||
#include "c-lang.h"
|
||
#include "psymtab.h"
|
||
#include "block.h"
|
||
#include "aout/aout64.h"
|
||
#include "aout/stab_gnu.h"
|
||
|
||
/* Required for the following registry. */
|
||
#include "gdb-stabs.h"
|
||
|
||
|
||
|
||
|
||
|
||
/* Local function prototypes. */
|
||
|
||
static void dbx_symfile_init (struct objfile *);
|
||
|
||
static void dbx_new_init (struct objfile *);
|
||
|
||
static void dbx_symfile_read (struct objfile *, symfile_add_flags);
|
||
|
||
static void dbx_symfile_finish (struct objfile *);
|
||
|
||
|
||
#if 0
|
||
static struct type **
|
||
explicit_lookup_type (int real_filenum, int index)
|
||
{
|
||
struct header_file *f = &HEADER_FILES (dbxread_objfile)[real_filenum];
|
||
|
||
if (index >= f->length)
|
||
{
|
||
f->length *= 2;
|
||
f->vector = (struct type **)
|
||
xrealloc (f->vector, f->length * sizeof (struct type *));
|
||
memset (&f->vector[f->length / 2],
|
||
'\0', f->length * sizeof (struct type *) / 2);
|
||
}
|
||
return &f->vector[index];
|
||
}
|
||
#endif
|
||
|
||
/* Scan and build partial symbols for a symbol file.
|
||
We have been initialized by a call to dbx_symfile_init, which
|
||
put all the relevant info into a "struct dbx_symfile_info",
|
||
hung off the objfile structure. */
|
||
|
||
static void
|
||
dbx_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
|
||
{
|
||
read_stabs_symtab (objfile, symfile_flags);
|
||
}
|
||
|
||
/* Initialize anything that needs initializing when a completely new
|
||
symbol file is specified (not just adding some symbols from another
|
||
file, e.g. a shared library). */
|
||
|
||
static void
|
||
dbx_new_init (struct objfile *ignore)
|
||
{
|
||
stabsread_new_init ();
|
||
init_header_files ();
|
||
}
|
||
|
||
|
||
/* dbx_symfile_init ()
|
||
is the dbx-specific initialization routine for reading symbols.
|
||
It is passed a struct objfile which contains, among other things,
|
||
the BFD for the file whose symbols are being read, and a slot for a pointer
|
||
to "private data" which we fill with goodies.
|
||
|
||
We read the string table into malloc'd space and stash a pointer to it.
|
||
|
||
Since BFD doesn't know how to read debug symbols in a format-independent
|
||
way (and may never do so...), we have to do it ourselves. We will never
|
||
be called unless this is an a.out (or very similar) file.
|
||
FIXME, there should be a cleaner peephole into the BFD environment here. */
|
||
|
||
#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */
|
||
|
||
static void
|
||
dbx_symfile_init (struct objfile *objfile)
|
||
{
|
||
int val;
|
||
bfd *sym_bfd = objfile->obfd.get ();
|
||
const char *name = bfd_get_filename (sym_bfd);
|
||
asection *text_sect;
|
||
unsigned char size_temp[DBX_STRINGTAB_SIZE_SIZE];
|
||
|
||
/* Allocate struct to keep track of the symfile. */
|
||
dbx_objfile_data_key.emplace (objfile);
|
||
|
||
DBX_TEXT_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
|
||
DBX_DATA_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".data");
|
||
DBX_BSS_SECTION (objfile) = bfd_get_section_by_name (sym_bfd, ".bss");
|
||
|
||
/* FIXME POKING INSIDE BFD DATA STRUCTURES. */
|
||
#define STRING_TABLE_OFFSET (sym_bfd->origin + obj_str_filepos (sym_bfd))
|
||
#define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_sym_filepos (sym_bfd))
|
||
|
||
/* FIXME POKING INSIDE BFD DATA STRUCTURES. */
|
||
|
||
text_sect = bfd_get_section_by_name (sym_bfd, ".text");
|
||
if (!text_sect)
|
||
error (_("Can't find .text section in symbol file"));
|
||
DBX_TEXT_ADDR (objfile) = bfd_section_vma (text_sect);
|
||
DBX_TEXT_SIZE (objfile) = bfd_section_size (text_sect);
|
||
|
||
DBX_SYMBOL_SIZE (objfile) = obj_symbol_entry_size (sym_bfd);
|
||
DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd);
|
||
DBX_SYMTAB_OFFSET (objfile) = SYMBOL_TABLE_OFFSET;
|
||
|
||
/* Read the string table and stash it away in the objfile_obstack.
|
||
When we blow away the objfile the string table goes away as well.
|
||
Note that gdb used to use the results of attempting to malloc the
|
||
string table, based on the size it read, as a form of sanity check
|
||
for botched byte swapping, on the theory that a byte swapped string
|
||
table size would be so totally bogus that the malloc would fail. Now
|
||
that we put in on the objfile_obstack, we can't do this since gdb gets
|
||
a fatal error (out of virtual memory) if the size is bogus. We can
|
||
however at least check to see if the size is less than the size of
|
||
the size field itself, or larger than the size of the entire file.
|
||
Note that all valid string tables have a size greater than zero, since
|
||
the bytes used to hold the size are included in the count. */
|
||
|
||
if (STRING_TABLE_OFFSET == 0)
|
||
{
|
||
/* It appears that with the existing bfd code, STRING_TABLE_OFFSET
|
||
will never be zero, even when there is no string table. This
|
||
would appear to be a bug in bfd. */
|
||
DBX_STRINGTAB_SIZE (objfile) = 0;
|
||
DBX_STRINGTAB (objfile) = NULL;
|
||
}
|
||
else
|
||
{
|
||
val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET);
|
||
if (val < 0)
|
||
perror_with_name (name);
|
||
|
||
memset (size_temp, 0, sizeof (size_temp));
|
||
val = bfd_read (size_temp, sizeof (size_temp), sym_bfd);
|
||
if (val < 0)
|
||
{
|
||
perror_with_name (name);
|
||
}
|
||
else if (val == 0)
|
||
{
|
||
/* With the existing bfd code, STRING_TABLE_OFFSET will be set to
|
||
EOF if there is no string table, and attempting to read the size
|
||
from EOF will read zero bytes. */
|
||
DBX_STRINGTAB_SIZE (objfile) = 0;
|
||
DBX_STRINGTAB (objfile) = NULL;
|
||
}
|
||
else
|
||
{
|
||
/* Read some data that would appear to be the string table size.
|
||
If there really is a string table, then it is probably the right
|
||
size. Byteswap if necessary and validate the size. Note that
|
||
the minimum is DBX_STRINGTAB_SIZE_SIZE. If we just read some
|
||
random data that happened to be at STRING_TABLE_OFFSET, because
|
||
bfd can't tell us there is no string table, the sanity checks may
|
||
or may not catch this. */
|
||
DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp);
|
||
|
||
if (DBX_STRINGTAB_SIZE (objfile) < sizeof (size_temp)
|
||
|| DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd))
|
||
error (_("ridiculous string table size (%d bytes)."),
|
||
DBX_STRINGTAB_SIZE (objfile));
|
||
|
||
DBX_STRINGTAB (objfile) =
|
||
(char *) obstack_alloc (&objfile->objfile_obstack,
|
||
DBX_STRINGTAB_SIZE (objfile));
|
||
OBJSTAT (objfile, sz_strtab += DBX_STRINGTAB_SIZE (objfile));
|
||
|
||
/* Now read in the string table in one big gulp. */
|
||
|
||
val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET);
|
||
if (val < 0)
|
||
perror_with_name (name);
|
||
val = bfd_read (DBX_STRINGTAB (objfile),
|
||
DBX_STRINGTAB_SIZE (objfile),
|
||
sym_bfd);
|
||
if (val != DBX_STRINGTAB_SIZE (objfile))
|
||
perror_with_name (name);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Perform any local cleanups required when we are done with a particular
|
||
objfile. I.E, we are in the process of discarding all symbol information
|
||
for an objfile, freeing up all memory held for it, and unlinking the
|
||
objfile struct from the global list of known objfiles. */
|
||
|
||
static void
|
||
dbx_symfile_finish (struct objfile *objfile)
|
||
{
|
||
free_header_files ();
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/* Scan and build partial symbols for a file with special sections for stabs
|
||
and stabstrings. The file has already been processed to get its minimal
|
||
symbols, and any other symbols that might be necessary to resolve GSYMs.
|
||
|
||
This routine is the equivalent of dbx_symfile_init and dbx_symfile_read
|
||
rolled into one.
|
||
|
||
OBJFILE is the object file we are reading symbols from.
|
||
ADDR is the address relative to which the symbols are (e.g. the base address
|
||
of the text segment).
|
||
STAB_NAME is the name of the section that contains the stabs.
|
||
STABSTR_NAME is the name of the section that contains the stab strings.
|
||
|
||
This routine is mostly copied from dbx_symfile_init and
|
||
dbx_symfile_read. */
|
||
|
||
void
|
||
stabsect_build_psymtabs (struct objfile *objfile, char *stab_name,
|
||
char *stabstr_name, char *text_name)
|
||
{
|
||
int val;
|
||
bfd *sym_bfd = objfile->obfd.get ();
|
||
const char *name = bfd_get_filename (sym_bfd);
|
||
asection *stabsect;
|
||
asection *stabstrsect;
|
||
asection *text_sect;
|
||
|
||
stabsect = bfd_get_section_by_name (sym_bfd, stab_name);
|
||
stabstrsect = bfd_get_section_by_name (sym_bfd, stabstr_name);
|
||
|
||
if (!stabsect)
|
||
return;
|
||
|
||
if (!stabstrsect)
|
||
error (_("stabsect_build_psymtabs: Found stabs (%s), "
|
||
"but not string section (%s)"),
|
||
stab_name, stabstr_name);
|
||
|
||
dbx_objfile_data_key.emplace (objfile);
|
||
|
||
text_sect = bfd_get_section_by_name (sym_bfd, text_name);
|
||
if (!text_sect)
|
||
error (_("Can't find %s section in symbol file"), text_name);
|
||
DBX_TEXT_ADDR (objfile) = bfd_section_vma (text_sect);
|
||
DBX_TEXT_SIZE (objfile) = bfd_section_size (text_sect);
|
||
|
||
DBX_SYMBOL_SIZE (objfile) = sizeof (struct external_nlist);
|
||
DBX_SYMCOUNT (objfile) = bfd_section_size (stabsect)
|
||
/ DBX_SYMBOL_SIZE (objfile);
|
||
DBX_STRINGTAB_SIZE (objfile) = bfd_section_size (stabstrsect);
|
||
DBX_SYMTAB_OFFSET (objfile) = stabsect->filepos; /* XXX - FIXME: POKING
|
||
INSIDE BFD DATA
|
||
STRUCTURES */
|
||
|
||
if (DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd))
|
||
error (_("ridiculous string table size: %d bytes"),
|
||
DBX_STRINGTAB_SIZE (objfile));
|
||
DBX_STRINGTAB (objfile) = (char *)
|
||
obstack_alloc (&objfile->objfile_obstack,
|
||
DBX_STRINGTAB_SIZE (objfile) + 1);
|
||
OBJSTAT (objfile, sz_strtab += DBX_STRINGTAB_SIZE (objfile) + 1);
|
||
|
||
/* Now read in the string table in one big gulp. */
|
||
|
||
val = bfd_get_section_contents (sym_bfd, /* bfd */
|
||
stabstrsect, /* bfd section */
|
||
DBX_STRINGTAB (objfile), /* input buffer */
|
||
0, /* offset into section */
|
||
DBX_STRINGTAB_SIZE (objfile)); /* amount to
|
||
read */
|
||
|
||
if (!val)
|
||
perror_with_name (name);
|
||
|
||
stabsread_new_init ();
|
||
free_header_files ();
|
||
init_header_files ();
|
||
|
||
/* Now, do an incremental load. */
|
||
|
||
dbx_objfile_data_key.get (objfile)->ctx.processing_acc_compilation = 1;
|
||
dbx_symfile_read (objfile, 0);
|
||
}
|
||
|
||
static const struct sym_fns aout_sym_fns =
|
||
{
|
||
dbx_new_init, /* init anything gbl to entire symtab */
|
||
dbx_symfile_init, /* read initial info, setup for sym_read() */
|
||
dbx_symfile_read, /* read a symbol file into symtab */
|
||
dbx_symfile_finish, /* finished with file, cleanup */
|
||
default_symfile_offsets, /* parse user's offsets to internal form */
|
||
default_symfile_segments, /* Get segment information from a file. */
|
||
NULL,
|
||
default_symfile_relocate, /* Relocate a debug section. */
|
||
NULL, /* sym_probe_fns */
|
||
};
|
||
|
||
void _initialize_dbxread ();
|
||
void
|
||
_initialize_dbxread ()
|
||
{
|
||
add_symtab_fns (bfd_target_aout_flavour, &aout_sym_fns);
|
||
}
|