#include "defs.h"
#include "bfd.h"
#include "gdb_obstack.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbtypes.h"
#include "complaints.h"
#include "gdb_string.h"
#include "expression.h"
#include "language.h"
#include "bcache.h"
#include "filenames.h"
#include "macrotab.h"
#include "demangle.h"
#define EXTERN
#include "buildsym.h"
#undef EXTERN
#include "stabsread.h"
static struct pending *free_pendings;
static int have_line_numbers;
static int compare_line_numbers (const void *ln1p, const void *ln2p);
#define INITIAL_CONTEXT_STACK_SIZE 10
#define INITIAL_LINE_VECTOR_LENGTH 1000
struct complaint block_end_complaint =
{"block end address less than block start address in %s (patched it)", 0, 0};
struct complaint anon_block_end_complaint =
{"block end address 0x%lx less than block start address 0x%lx (patched it)", 0, 0};
struct complaint innerblock_complaint =
{"inner block (0x%lx-0x%lx) not inside outer block (0x%lx-0x%lx) in %s", 0, 0};
struct complaint innerblock_anon_complaint =
{"inner block (0x%lx-0x%lx) not inside outer block (0x%lx-0x%lx)", 0, 0};
struct complaint blockvector_complaint =
{"block at %s out of order", 0, 0};
void
add_free_pendings (struct pending *list)
{
register 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)
{
register 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;
}
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 = 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 (PTR 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 objfile *objfile)
{
register struct pending *next, *next1;
register struct block *block;
register struct pending_block *pblock;
struct pending_block *opblock;
register int i;
register int j;
for (next = *listhead, i = 0;
next;
i += next->nsyms, next = next->next)
{
;
}
if (symbol)
{
block = (struct block *)
obstack_alloc (&objfile->symbol_obstack,
(sizeof (struct block) +
((i - 1) * sizeof (struct symbol *))));
BLOCK_NSYMS (block) = i;
for (next = *listhead; next; next = next->next)
for (j = next->nsyms - 1; j >= 0; j--)
{
BLOCK_SYM (block, --i) = next->symbol[j];
}
}
else
{
int htab_size = BLOCK_HASHTABLE_SIZE (i);
block = (struct block *)
obstack_alloc (&objfile->symbol_obstack,
(sizeof (struct block) +
((htab_size - 1) * sizeof (struct symbol *))));
for (j = 0; j < htab_size; j++)
{
BLOCK_BUCKET (block, j) = 0;
}
BLOCK_BUCKETS (block) = htab_size;
for (next = *listhead; next; next = next->next)
{
for (j = next->nsyms - 1; j >= 0; j--)
{
struct symbol *sym;
unsigned int hash_index;
const char *name = SYMBOL_DEMANGLED_NAME (next->symbol[j]);
if (name == NULL)
name = SYMBOL_NAME (next->symbol[j]);
hash_index = msymbol_hash_iw (name);
hash_index = hash_index % BLOCK_BUCKETS (block);
sym = BLOCK_BUCKET (block, hash_index);
BLOCK_BUCKET (block, hash_index) = next->symbol[j];
next->symbol[j]->hash_next = sym;
}
}
}
BLOCK_START (block) = start;
BLOCK_END (block) = end;
BLOCK_SUPERBLOCK (block) = NULL;
BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
if (symbol)
{
struct type *ftype = SYMBOL_TYPE (symbol);
SYMBOL_BLOCK_VALUE (symbol) = block;
BLOCK_FUNCTION (block) = symbol;
BLOCK_HASHTABLE (block) = 0;
if (TYPE_NFIELDS (ftype) <= 0)
{
int nparams = 0, iparams;
struct symbol *sym;
ALL_BLOCK_SYMBOLS (block, i, 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:
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:
default:
break;
}
}
if (nparams > 0)
{
TYPE_NFIELDS (ftype) = nparams;
TYPE_FIELDS (ftype) = (struct field *)
TYPE_ALLOC (ftype, nparams * sizeof (struct field));
for (i = iparams = 0; iparams < nparams; i++)
{
sym = BLOCK_SYM (block, i);
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:
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:
default:
break;
}
}
}
}
}
else
{
BLOCK_FUNCTION (block) = NULL;
BLOCK_HASHTABLE (block) = 1;
}
for (next = *listhead; next; next = next1)
{
next1 = next->next;
next->next = free_pendings;
free_pendings = next;
}
*listhead = NULL;
#if 1
if (BLOCK_END (block) < BLOCK_START (block))
{
if (symbol)
{
complain (&block_end_complaint, SYMBOL_SOURCE_NAME (symbol));
}
else
{
complain (&anon_block_end_complaint,
(unsigned long) BLOCK_END (block),
(unsigned long) BLOCK_START (block));
}
BLOCK_END (block) = BLOCK_START (block);
}
#endif
opblock = NULL;
for (pblock = pending_blocks;
pblock && pblock != old_blocks;
pblock = pblock->next)
{
if (BLOCK_SUPERBLOCK (pblock->block) == NULL)
{
#if 1
if (BLOCK_START (pblock->block) < BLOCK_START (block) ||
BLOCK_END (pblock->block) > BLOCK_END (block))
{
if (symbol)
{
complain (&innerblock_complaint,
(unsigned long) BLOCK_START (pblock->block),
(unsigned long) BLOCK_END (pblock->block),
(unsigned long) BLOCK_START (block),
(unsigned long) BLOCK_END (block),
SYMBOL_SOURCE_NAME (symbol));
}
else
{
complain (&innerblock_anon_complaint,
(unsigned long) BLOCK_START (pblock->block),
(unsigned long) BLOCK_END (pblock->block),
(unsigned long) BLOCK_START (block),
(unsigned long) BLOCK_END (block));
}
if (BLOCK_START (pblock->block) < BLOCK_START (block))
BLOCK_START (pblock->block) = BLOCK_START (block);
if (BLOCK_END (pblock->block) > BLOCK_END (block))
BLOCK_END (pblock->block) = BLOCK_END (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)
{
register struct pending_block *pblock;
pblock = (struct pending_block *)
obstack_alloc (&objfile->symbol_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
return 0;
}
static struct blockvector *
make_blockvector (struct objfile *objfile)
{
register struct pending_block *next;
register struct blockvector *blockvector;
register int i;
for (next = pending_blocks, i = 0; next; next = next->next, i++)
{;
}
blockvector = (struct blockvector *)
obstack_alloc (&objfile->symbol_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 1
if (objfile->flags & OBJF_REORDERED)
{
#if 0
for (i = 2; i < BLOCKVECTOR_NBLOCKS (blockvector) - 2; i++)
{
struct block *b = BLOCKVECTOR_BLOCK (blockvector, i);
struct minimal_symbol *min_sym = (struct minimal_symbol *)
lookup_minimal_symbol_by_pc_section_from_objfile
(BLOCK_START (b), find_pc_mapped_section (BLOCK_START (b)), objfile);
if (min_sym &&
((SYMBOL_VALUE_ADDRESS (min_sym) > BLOCK_END (b)) ||
(SYMBOL_VALUE_ADDRESS (min_sym + 1) &&
(SYMBOL_VALUE_ADDRESS (min_sym + 1) < BLOCK_END (b)))))
BLOCK_END (b) = SYMBOL_VALUE_ADDRESS (min_sym + 1);
}
#endif
if (BLOCKVECTOR_NBLOCKS (blockvector) > 2)
qsort (&blockvector->block[2],
BLOCKVECTOR_NBLOCKS (blockvector) - 2,
sizeof (struct block *),
compare_blocks);
}
#endif
#if 1
if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
{
for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++)
{
if (BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i - 1))
> BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i)))
{
CORE_ADDR start
= BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i));
complain (&blockvector_complaint,
local_hex_string ((LONGEST) start));
}
}
}
#endif
return (blockvector);
}
void
start_subfile (char *name, char *dirname)
{
register struct subfile *subfile;
for (subfile = subfiles; subfile; subfile = subfile->next)
{
if (FILENAME_CMP (subfile->name, name) == 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;
if (subfile->name)
{
struct subfile *s;
enum language sublang = deduce_language_from_filename (subfile->name);
if (sublang == language_cplus || 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_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)
{
register 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)
{
register char *name;
register 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 (register struct subfile *subfile, int line, CORE_ADDR pc)
{
struct linetable_entry *e;
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);
}
static 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;
subfiles = NULL;
current_subfile = NULL;
start_subfile (name, dirname);
}
struct symtab *
end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
{
register struct symtab *symtab = NULL;
register struct blockvector *blockvector;
register struct subfile *subfile;
register 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, objfile);
if (context_stack_depth > 0)
{
static struct complaint msg =
{"Context stack not empty in end_symtab", 0, 0};
complain (&msg);
context_stack_depth = 0;
}
}
#if 0
if ((objfile->flags & OBJF_REORDERED) && pending_blocks)
{
int swapped;
do
{
struct pending_block *pb, *pbnext;
pb = pending_blocks;
pbnext = pb->next;
swapped = 0;
while (pbnext)
{
if (BLOCK_START (pb->block) < BLOCK_START (pbnext->block))
{
struct block *tmp = pb->block;
pb->block = pbnext->block;
pbnext->block = tmp;
swapped = 1;
}
pb = pbnext;
pbnext = pbnext->next;
}
}
while (swapped);
}
#endif
cleanup_undefined_types ();
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,
objfile);
finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
objfile);
blockvector = make_blockvector (objfile);
}
#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->symbol_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->symbol_obstack,
strlen (subfile->dirname) + 1);
strcpy (symtab->dirname, subfile->dirname);
}
else
{
symtab->dirname = NULL;
}
symtab->free_code = free_linetable;
symtab->free_ptr = NULL;
symtab->language = subfile->language;
if (subfile->debugformat != NULL)
{
symtab->debugformat = obsavestring (subfile->debugformat,
strlen (subfile->debugformat),
&objfile->symbol_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);
}
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)
{
register 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;
}
int
hashname (char *name)
{
return (hash(name,strlen(name)) % HASHSIZE);
}
void
record_debugformat (char *format)
{
current_subfile->debugformat = savestring (format, strlen (format));
}
void
merge_symbol_lists (struct pending **srclist, struct pending **targetlist)
{
register 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 ();
}