#include "defs.h"
#include "bfd.h"
#include "gdb_obstack.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbtypes.h"
#include "gdb_assert.h"
#include "complaints.h"
#include "gdb_string.h"
#include "expression.h"
#include "bcache.h"
#include "filenames.h"
#include "macrotab.h"
#include "demangle.h"
#include "block.h"
#include "cp-support.h"
#include "dictionary.h"
#include "inlining.h"
#define EXTERN
#include "buildsym.h"
#undef EXTERN
#include "stabsread.h"
static struct pending *free_pendings;
static int have_line_numbers;
#define INITIAL_CONTEXT_STACK_SIZE 10
#define INITIAL_LINE_VECTOR_LENGTH 1000
void
add_free_pendings (struct pending *list)
{
struct pending *link = list;
if (list)
{
while (link->next) link = link->next;
link->next = free_pendings;
free_pendings = list;
}
}
void
add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
{
struct pending *link;
if (symbol->ginfo.name && symbol->ginfo.name[0] == '#')
return;
if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE)
{
if (free_pendings)
{
link = free_pendings;
free_pendings = link->next;
}
else
{
link = (struct pending *) xmalloc (sizeof (struct pending));
}
link->next = *listhead;
*listhead = link;
link->nsyms = 0;
}
(*listhead)->symbol[(*listhead)->nsyms++] = symbol;
if (SYMBOL_LANGUAGE (symbol) == language_cplus
|| SYMBOL_LANGUAGE (symbol) == language_objcplus)
cp_scan_for_anonymous_namespaces (symbol);
SYMBOL_OBSOLETED (symbol) = 0;
}
struct symbol *
find_symbol_in_list (struct pending *list, char *name, int length)
{
int j;
char *pp;
while (list != NULL)
{
for (j = list->nsyms; --j >= 0;)
{
pp = DEPRECATED_SYMBOL_NAME (list->symbol[j]);
if (*pp == *name && strncmp (pp, name, length) == 0 &&
pp[length] == '\0')
{
return (list->symbol[j]);
}
}
list = list->next;
}
return (NULL);
}
void
really_free_pendings (void *dummy)
{
struct pending *next, *next1;
for (next = free_pendings; next; next = next1)
{
next1 = next->next;
xfree ((void *) next);
}
free_pendings = NULL;
free_pending_blocks ();
for (next = file_symbols; next != NULL; next = next1)
{
next1 = next->next;
xfree ((void *) next);
}
file_symbols = NULL;
for (next = global_symbols; next != NULL; next = next1)
{
next1 = next->next;
xfree ((void *) next);
}
global_symbols = NULL;
if (pending_macros)
free_macro_table (pending_macros);
}
void
free_pending_blocks (void)
{
#if 0
struct pending_block *bnext, *bnext1;
for (bnext = pending_blocks; bnext; bnext = bnext1)
{
bnext1 = bnext->next;
xfree ((void *) bnext);
}
#endif
pending_blocks = NULL;
}
void
finish_block (struct symbol *symbol, struct pending **listhead,
struct pending_block *old_blocks,
CORE_ADDR start, CORE_ADDR end,
struct address_range_list *ranges, struct objfile *objfile)
{
struct pending *next, *next1;
struct block *block;
struct pending_block *pblock;
struct pending_block *opblock;
int i;
block = allocate_block (&objfile->objfile_obstack);
if (symbol)
{
BLOCK_DICT (block) = dict_create_linear (&objfile->objfile_obstack,
*listhead);
}
else
{
BLOCK_DICT (block) = dict_create_hashed (&objfile->objfile_obstack,
*listhead);
}
if (ranges)
{
for (i=0; i<ranges->nelts; i++)
{
if (ranges->ranges[i].startaddr < start)
start = ranges->ranges[i].startaddr;
if (ranges->ranges[i].endaddr > end)
end = ranges->ranges[i].endaddr;
}
}
BLOCK_START (block) = start;
BLOCK_END (block) = end;
BLOCK_RANGES (block) = ranges;
BLOCK_SUPERBLOCK (block) = NULL;
BLOCK_NAMESPACE (block) = NULL;
BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
if (symbol)
{
struct type *ftype = SYMBOL_TYPE (symbol);
struct dict_iterator iter;
SYMBOL_BLOCK_VALUE (symbol) = block;
BLOCK_FUNCTION (block) = symbol;
if (TYPE_NFIELDS (ftype) <= 0)
{
int nparams = 0, iparams;
struct symbol *sym;
ALL_BLOCK_SYMBOLS (block, iter, sym)
{
switch (SYMBOL_CLASS (sym))
{
case LOC_ARG:
case LOC_REF_ARG:
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_LOCAL_ARG:
case LOC_COMPUTED_ARG:
nparams++;
break;
case LOC_UNDEF:
case LOC_CONST:
case LOC_STATIC:
case LOC_INDIRECT:
case LOC_REGISTER:
case LOC_LOCAL:
case LOC_TYPEDEF:
case LOC_LABEL:
case LOC_BLOCK:
case LOC_CONST_BYTES:
case LOC_BASEREG:
case LOC_UNRESOLVED:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
default:
break;
}
}
if (nparams > 0)
{
TYPE_NFIELDS (ftype) = nparams;
TYPE_FIELDS (ftype) = (struct field *)
TYPE_ALLOC (ftype, nparams * sizeof (struct field));
memset (TYPE_FIELDS (ftype), 0, sizeof (struct field) * nparams);
iparams = 0;
ALL_BLOCK_SYMBOLS (block, iter, sym)
{
if (iparams == nparams)
break;
switch (SYMBOL_CLASS (sym))
{
case LOC_ARG:
case LOC_REF_ARG:
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_LOCAL_ARG:
case LOC_COMPUTED_ARG:
TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym);
TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
iparams++;
break;
case LOC_UNDEF:
case LOC_CONST:
case LOC_STATIC:
case LOC_INDIRECT:
case LOC_REGISTER:
case LOC_LOCAL:
case LOC_TYPEDEF:
case LOC_LABEL:
case LOC_BLOCK:
case LOC_CONST_BYTES:
case LOC_BASEREG:
case LOC_UNRESOLVED:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
default:
break;
}
}
}
}
if (SYMBOL_LANGUAGE (symbol) == language_cplus
|| SYMBOL_LANGUAGE (symbol) == language_objcplus)
{
cp_set_block_scope (symbol, block, &objfile->objfile_obstack);
}
}
else
{
BLOCK_FUNCTION (block) = NULL;
}
for (next = *listhead; next; next = next1)
{
next1 = next->next;
next->next = free_pendings;
free_pendings = next;
}
*listhead = NULL;
#if 1
if (!BLOCK_RANGES (block)
&& BLOCK_END (block) < BLOCK_START (block))
{
if (symbol)
{
complaint (&symfile_complaints,
_("block end address less than block start address in %s (patched it)"),
SYMBOL_PRINT_NAME (symbol));
}
else
{
complaint (&symfile_complaints,
_("block end address 0x%s less than block start address 0x%s (patched it)"),
paddr_nz (BLOCK_END (block)), paddr_nz (BLOCK_START (block)));
}
BLOCK_END (block) = BLOCK_START (block);
}
else if (BLOCK_RANGES (block))
{
int i;
for (i = 0; i < BLOCK_RANGES (block)->nelts; i++)
if (BLOCK_RANGE_END (block, i) < BLOCK_RANGE_START (block, i))
{
if (symbol)
{
complaint (&symfile_complaints,
_("block end address less than block start address in %s (patched it)"),
SYMBOL_PRINT_NAME (symbol));
}
else
{
complaint (&symfile_complaints,
_("block end address 0x%s less than block start address 0x%s (patched it)"),
paddr_nz (BLOCK_RANGE_END (block, i)),
paddr_nz (BLOCK_RANGE_START (block, i)));
}
BLOCK_RANGE_END (block, i) = BLOCK_RANGE_START (block, i);
}
}
#endif
opblock = NULL;
for (pblock = pending_blocks;
pblock && pblock != old_blocks;
pblock = pblock->next)
{
if (BLOCK_SUPERBLOCK (pblock->block) == NULL)
{
#if 1
if (!contained_in (pblock->block, block))
{
if (symbol)
{
complaint (&symfile_complaints,
_("inner block not inside outer block in %s"),
SYMBOL_PRINT_NAME (symbol));
}
else
{
if (pblock->block->function
&& pblock->block->function->ginfo.name)
complaint (&symfile_complaints,
_("inner block (0x%s-0x%s '%s') not inside outer block (0x%s-0x%s)"),
paddr_nz (BLOCK_START (pblock->block)),
paddr_nz (BLOCK_END (pblock->block)),
pblock->block->function->ginfo.name,
paddr_nz (BLOCK_START (block)),
paddr_nz (BLOCK_END (block)));
else
complaint (&symfile_complaints,
_("inner block (0x%s-0x%s) not inside outer block (0x%s-0x%s)"),
paddr_nz (BLOCK_START (pblock->block)),
paddr_nz (BLOCK_END (pblock->block)),
paddr_nz (BLOCK_START (block)),
paddr_nz (BLOCK_END (block)));
}
if (!BLOCK_RANGES (pblock->block) && !BLOCK_RANGES (block))
{
if (BLOCK_START (pblock->block) < BLOCK_START (block))
BLOCK_START (block) = BLOCK_START (pblock->block);
if (BLOCK_END (pblock->block) > BLOCK_END (block))
BLOCK_END (block) = BLOCK_END (pblock->block);
}
}
#endif
BLOCK_SUPERBLOCK (pblock->block) = block;
}
opblock = pblock;
}
record_pending_block (objfile, block, opblock);
}
void
record_pending_block (struct objfile *objfile, struct block *block,
struct pending_block *opblock)
{
struct pending_block *pblock;
pblock = (struct pending_block *)
obstack_alloc (&objfile->objfile_obstack, sizeof (struct pending_block));
pblock->block = block;
if (opblock)
{
pblock->next = opblock->next;
opblock->next = pblock;
}
else
{
pblock->next = pending_blocks;
pending_blocks = pblock;
}
}
static int
compare_blocks (const void *v1, const void *v2)
{
const struct block *const *b1 = v1;
const struct block *const *b2 = v2;
if ((*b1)->startaddr < (*b2)->startaddr)
return -1;
else if ((*b1)->startaddr > (*b2)->startaddr)
return 1;
else if ((*b1)->endaddr < (*b2)->endaddr)
return 1;
else if ((*b1)->endaddr > (*b2)->endaddr)
return -1;
else if (BLOCK_SUPERBLOCK(*b1) == (*b2))
return 1;
else if (BLOCK_SUPERBLOCK(*b2) == (*b1))
return -1;
else
return 0;
}
static struct blockvector *
make_blockvector (struct objfile *objfile)
{
struct pending_block *next;
struct blockvector *blockvector;
int i;
for (next = pending_blocks, i = 0; next; next = next->next, i++)
{;
}
blockvector = (struct blockvector *)
obstack_alloc (&objfile->objfile_obstack,
(sizeof (struct blockvector)
+ (i - 1) * sizeof (struct block *)));
BLOCKVECTOR_NBLOCKS (blockvector) = i;
for (next = pending_blocks; next; next = next->next)
{
BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
}
#if 0
for (next = pending_blocks; next; next = next1)
{
next1 = next->next;
xfree (next);
}
#endif
pending_blocks = NULL;
if (objfile->flags & OBJF_REORDERED)
{
if (BLOCKVECTOR_NBLOCKS (blockvector) > 2)
qsort (&blockvector->block[2],
BLOCKVECTOR_NBLOCKS (blockvector) - 2,
sizeof (struct block *),
compare_blocks);
}
#if 1
if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
{
for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++)
{
CORE_ADDR start1;
CORE_ADDR start2;
start1 = BLOCK_LOWEST_PC (BLOCKVECTOR_BLOCK (blockvector, i - 1));
start2 = BLOCK_LOWEST_PC (BLOCKVECTOR_BLOCK (blockvector, i));
if (start1 > start2)
complaint (&symfile_complaints, _("block at %s out of order"),
hex_string ((LONGEST) start2));
}
}
#endif
return (blockvector);
}
void
start_subfile (char *name, char *dirname)
{
struct subfile *subfile;
for (subfile = subfiles; subfile; subfile = subfile->next)
{
if (FILENAME_CMP (subfile->name, name) == 0
&& ((subfile->dirname != NULL)
&& (dirname != NULL)
&& (FILENAME_CMP (subfile->dirname, dirname) == 0)))
{
current_subfile = subfile;
return;
}
}
subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
memset ((char *) subfile, 0, sizeof (struct subfile));
subfile->next = subfiles;
subfiles = subfile;
current_subfile = subfile;
subfile->name = (name == NULL) ? NULL : savestring (name, strlen (name));
subfile->dirname =
(dirname == NULL) ? NULL : savestring (dirname, strlen (dirname));
subfile->line_vector = NULL;
subfile->language = deduce_language_from_filename (subfile->name);
if (subfile->language == language_unknown &&
subfile->next != NULL)
{
subfile->language = subfile->next->language;
}
subfile->debugformat = NULL;
subfile->producer = NULL;
if (subfile->name)
{
struct subfile *s;
enum language sublang = deduce_language_from_filename (subfile->name);
if (sublang == language_cplus || sublang == language_objcplus || sublang == language_fortran)
for (s = subfiles; s != NULL; s = s->next)
if (s->language == language_c)
s->language = sublang;
}
if (subfile->language == language_c
&& subfile->next != NULL
&& (subfile->next->language == language_cplus
|| subfile->next->language == language_objcplus
|| subfile->next->language == language_fortran))
{
subfile->language = subfile->next->language;
}
}
void
patch_subfile_names (struct subfile *subfile, char *name)
{
if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL
&& subfile->name[strlen (subfile->name) - 1] == '/')
{
subfile->dirname = subfile->name;
subfile->name = savestring (name, strlen (name));
last_source_file = name;
subfile->language = deduce_language_from_filename (subfile->name);
if (subfile->language == language_unknown &&
subfile->next != NULL)
{
subfile->language = subfile->next->language;
}
}
}
void
push_subfile (void)
{
struct subfile_stack *tem
= (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack));
tem->next = subfile_stack;
subfile_stack = tem;
if (current_subfile == NULL || current_subfile->name == NULL)
{
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
tem->name = current_subfile->name;
}
char *
pop_subfile (void)
{
char *name;
struct subfile_stack *link = subfile_stack;
if (link == NULL)
{
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
name = link->name;
subfile_stack = link->next;
xfree ((void *) link);
return (name);
}
void
record_line (struct subfile *subfile, int line, CORE_ADDR pc, CORE_ADDR end_pc,
enum line_table_entry_type entry_type)
{
struct linetable_entry *e;
if (dwarf2_debug_inlined_stepping)
{
if (entry_type != NORMAL_LT_ENTRY)
{
if (entry_type == INLINED_CALL_SITE_LT_ENTRY)
fprintf_unfiltered (gdb_stdout, " INLINED CALL SITE, ");
else
fprintf_unfiltered (gdb_stdout, " INLINED SUBROUTINE, ");
fprintf_unfiltered (gdb_stdout, "0x%x - 0x%x, ",
(unsigned int) pc, (unsigned int) end_pc);
fprintf_unfiltered (gdb_stdout, "%s:%d\n", subfile->name, line);
}
}
if (line == 0xffff)
{
return;
}
if (!subfile->line_vector)
{
subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH;
subfile->line_vector = (struct linetable *)
xmalloc (sizeof (struct linetable)
+ subfile->line_vector_length * sizeof (struct linetable_entry));
subfile->line_vector->nitems = 0;
subfile->line_vector->lines_are_chars = 0;
have_line_numbers = 1;
}
if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length)
{
subfile->line_vector_length *= 2;
subfile->line_vector = (struct linetable *)
xrealloc ((char *) subfile->line_vector,
(sizeof (struct linetable)
+ (subfile->line_vector_length
* sizeof (struct linetable_entry))));
}
e = subfile->line_vector->item + subfile->line_vector->nitems++;
e->line = line;
e->pc = ADDR_BITS_REMOVE(pc);
e->end_pc = ADDR_BITS_REMOVE(end_pc);
e->entry_type = entry_type;
}
int
compare_line_numbers (const void *ln1p, const void *ln2p)
{
struct linetable_entry *ln1 = (struct linetable_entry *) ln1p;
struct linetable_entry *ln2 = (struct linetable_entry *) ln2p;
if (ln1->pc < ln2->pc)
return -1;
if (ln1->pc > ln2->pc)
return 1;
return ln1->line - ln2->line;
}
void
start_symtab (char *name, char *dirname, CORE_ADDR start_addr)
{
last_source_file = name;
last_source_start_addr = start_addr;
file_symbols = NULL;
global_symbols = NULL;
within_function = 0;
have_line_numbers = 0;
if (context_stack == NULL)
{
context_stack_size = INITIAL_CONTEXT_STACK_SIZE;
context_stack = (struct context_stack *)
xmalloc (context_stack_size * sizeof (struct context_stack));
}
context_stack_depth = 0;
cp_initialize_namespace ();
subfiles = NULL;
current_subfile = NULL;
start_subfile (name, dirname);
}
struct symtab *
end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
{
struct symtab *symtab = NULL;
struct blockvector *blockvector;
struct subfile *subfile;
struct context_stack *cstk;
struct subfile *nextsub;
if (context_stack_depth > 0)
{
cstk = pop_context ();
finish_block (cstk->name, &local_symbols, cstk->old_blocks,
cstk->start_addr, end_addr, NULL, objfile);
if (context_stack_depth > 0)
{
complaint (&symfile_complaints,
_("Context stack not empty in end_symtab"));
context_stack_depth = 0;
}
}
cleanup_undefined_types ();
cleanup_undefined_fields ();
cleanup_undefined_arrays ();
finish_global_stabs (objfile);
if (pending_blocks == NULL
&& file_symbols == NULL
&& global_symbols == NULL
&& have_line_numbers == 0
&& pending_macros == NULL)
{
blockvector = NULL;
}
else
{
finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr,
NULL, objfile);
finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
NULL, objfile);
blockvector = make_blockvector (objfile);
cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
&objfile->objfile_obstack);
}
#ifndef PROCESS_LINENUMBER_HOOK
#define PROCESS_LINENUMBER_HOOK()
#endif
PROCESS_LINENUMBER_HOOK ();
for (subfile = subfiles; subfile; subfile = nextsub)
{
int linetablesize = 0;
symtab = NULL;
if (blockvector)
{
if (subfile->line_vector)
{
linetablesize = sizeof (struct linetable) +
subfile->line_vector->nitems * sizeof (struct linetable_entry);
#if 0
subfile->line_vector = (struct linetable *)
xrealloc ((char *) subfile->line_vector, linetablesize);
#endif
if (objfile->flags & OBJF_REORDERED)
qsort (subfile->line_vector->item,
subfile->line_vector->nitems,
sizeof (struct linetable_entry), compare_line_numbers);
}
symtab = allocate_symtab (subfile->name, objfile);
symtab->blockvector = blockvector;
symtab->macro_table = pending_macros;
if (subfile->line_vector)
{
symtab->linetable = (struct linetable *)
obstack_alloc (&objfile->objfile_obstack, linetablesize);
memcpy (symtab->linetable, subfile->line_vector, linetablesize);
}
else
{
symtab->linetable = NULL;
}
symtab->block_line_section = section;
if (subfile->dirname)
{
symtab->dirname = (char *)
obstack_alloc (&objfile->objfile_obstack,
strlen (subfile->dirname) + 1);
strcpy (symtab->dirname, subfile->dirname);
}
else
{
symtab->dirname = NULL;
}
symtab->free_code = free_linetable;
symtab->free_func = NULL;
symtab->language = subfile->language;
if (subfile->debugformat != NULL)
{
symtab->debugformat = obsavestring (subfile->debugformat,
strlen (subfile->debugformat),
&objfile->objfile_obstack);
}
if (subfile->producer != NULL)
symtab->producer = obsavestring (subfile->producer,
strlen (subfile->producer),
&objfile->objfile_obstack);
symtab->primary = 0;
}
if (subfile->name != NULL)
{
xfree ((void *) subfile->name);
}
if (subfile->dirname != NULL)
{
xfree ((void *) subfile->dirname);
}
if (subfile->line_vector != NULL)
{
xfree ((void *) subfile->line_vector);
}
if (subfile->debugformat != NULL)
{
xfree ((void *) subfile->debugformat);
}
if (subfile->producer != NULL)
xfree (subfile->producer);
nextsub = subfile->next;
xfree ((void *) subfile);
}
if (symtab)
{
symtab->primary = 1;
}
last_source_file = NULL;
current_subfile = NULL;
pending_macros = NULL;
return symtab;
}
struct context_stack *
push_context (int desc, CORE_ADDR valu)
{
struct context_stack *new;
if (context_stack_depth == context_stack_size)
{
context_stack_size *= 2;
context_stack = (struct context_stack *)
xrealloc ((char *) context_stack,
(context_stack_size * sizeof (struct context_stack)));
}
new = &context_stack[context_stack_depth++];
new->depth = desc;
new->locals = local_symbols;
new->params = param_symbols;
new->old_blocks = pending_blocks;
new->start_addr = valu;
new->name = NULL;
local_symbols = NULL;
param_symbols = NULL;
return new;
}
struct context_stack *
pop_context (void)
{
gdb_assert (context_stack_depth > 0);
return (&context_stack[--context_stack_depth]);
}
int
hashname (char *name)
{
return (hash(name,strlen(name)) % HASHSIZE);
}
void
record_debugformat (char *format)
{
current_subfile->debugformat = savestring (format, strlen (format));
}
void
record_producer (const char *producer)
{
if (producer == NULL)
return;
current_subfile->producer = savestring (producer, strlen (producer));
}
void
merge_symbol_lists (struct pending **srclist, struct pending **targetlist)
{
int i;
if (!srclist || !*srclist)
return;
for (i = 0; i < (*srclist)->nsyms; i++)
add_symbol_to_list ((*srclist)->symbol[i], targetlist);
merge_symbol_lists (&(*srclist)->next, targetlist);
(*srclist)->next = free_pendings;
free_pendings = (*srclist);
}
void
buildsym_init (void)
{
free_pendings = NULL;
file_symbols = NULL;
global_symbols = NULL;
pending_blocks = NULL;
pending_macros = NULL;
}
void
buildsym_new_init (void)
{
buildsym_init ();
}