/* DWARF 2 debugging format support for GDB.
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
#include "buildsym.h"
#include "demangle.h"
#include "expression.h"
+#include "filenames.h" /* for DOSish file names */
+#include "macrotab.h"
#include "language.h"
#include "complaints.h"
#include "bcache.h"
#include <fcntl.h>
#include "gdb_string.h"
+#include "gdb_assert.h"
#include <sys/types.h>
#ifndef DWARF2_REG_TO_REGNUM
static file_ptr dwarf_loc_offset;
static file_ptr dwarf_macinfo_offset;
static file_ptr dwarf_str_offset;
+file_ptr dwarf_frame_offset;
+file_ptr dwarf_eh_frame_offset;
static unsigned int dwarf_info_size;
static unsigned int dwarf_abbrev_size;
static unsigned int dwarf_loc_size;
static unsigned int dwarf_macinfo_size;
static unsigned int dwarf_str_size;
+unsigned int dwarf_frame_size;
+unsigned int dwarf_eh_frame_size;
/* names of the debugging sections */
#define LOC_SECTION ".debug_loc"
#define MACINFO_SECTION ".debug_macinfo"
#define STR_SECTION ".debug_str"
+#define FRAME_SECTION ".debug_frame"
+#define EH_FRAME_SECTION ".eh_frame"
/* local data types */
4 or 12 */
};
-/* The data in the .debug_line statement prologue looks like this. */
-struct line_head
+/* The line number information for a compilation unit (found in the
+ .debug_line section) begins with a "statement program header",
+ which contains the following information. */
+struct line_header
+{
+ unsigned int total_length;
+ unsigned short version;
+ unsigned int header_length;
+ unsigned char minimum_instruction_length;
+ unsigned char default_is_stmt;
+ int line_base;
+ unsigned char line_range;
+ unsigned char opcode_base;
+
+ /* standard_opcode_lengths[i] is the number of operands for the
+ standard opcode whose value is i. This means that
+ standard_opcode_lengths[0] is unused, and the last meaningful
+ element is standard_opcode_lengths[opcode_base - 1]. */
+ unsigned char *standard_opcode_lengths;
+
+ /* The include_directories table. NOTE! These strings are not
+ allocated with xmalloc; instead, they are pointers into
+ debug_line_buffer. If you try to free them, `free' will get
+ indigestion. */
+ unsigned int num_include_dirs, include_dirs_size;
+ char **include_dirs;
+
+ /* The file_names table. NOTE! These strings are not allocated
+ with xmalloc; instead, they are pointers into debug_line_buffer.
+ Don't try to free them directly. */
+ unsigned int num_file_names, file_names_size;
+ struct file_entry
{
- unsigned int total_length;
- unsigned short version;
- unsigned int prologue_length;
- unsigned char minimum_instruction_length;
- unsigned char default_is_stmt;
- int line_base;
- unsigned char line_range;
- unsigned char opcode_base;
- unsigned char *standard_opcode_lengths;
- };
+ char *name;
+ unsigned int dir_index;
+ unsigned int mod_time;
+ unsigned int length;
+ } *file_names;
+
+ /* The start and end of the statement program following this
+ header. These point into dwarf_line_buffer. */
+ char *statement_program_start, *statement_program_end;
+};
/* When we construct a partial symbol table entry we only
need this much information. */
unsigned int offset;
unsigned int abbrev;
char *name;
+ int has_pc_info;
CORE_ADDR lowpc;
CORE_ADDR highpc;
struct dwarf_block *locdesc;
u;
};
+struct function_range
+{
+ const char *name;
+ CORE_ADDR lowpc, highpc;
+ int seen_line;
+ struct function_range *next;
+};
+
+static struct function_range *cu_first_fn, *cu_last_fn, *cu_cached_fn;
+
/* Get at parts of an attribute structure */
#define DW_STRING(attr) ((attr)->u.str)
static char *dwarf_info_buffer;
static char *dwarf_abbrev_buffer;
static char *dwarf_line_buffer;
+static char *dwarf_str_buffer;
+static char *dwarf_macinfo_buffer;
/* A zeroed version of a partial die for initialization purposes. */
static struct partial_die_info zeroed_partial_die;
/* Pointer to start of dwarf line buffer for the objfile. */
char *dwarf_line_buffer;
+
+ /* Size of dwarf_line_buffer, in bytes. */
+
+ unsigned int dwarf_line_size;
+
+ /* Pointer to start of dwarf string buffer for the objfile. */
+
+ char *dwarf_str_buffer;
+
+ /* Size of dwarf string section for the objfile. */
+
+ unsigned int dwarf_str_size;
+
+ /* Pointer to start of dwarf macro buffer for the objfile. */
+
+ char *dwarf_macinfo_buffer;
+
+ /* Size of dwarf macinfo section for the objfile. */
+
+ unsigned int dwarf_macinfo_size;
+
};
#define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
#define DWARF_ABBREV_BUFFER(p) (PST_PRIVATE(p)->dwarf_abbrev_buffer)
#define DWARF_ABBREV_SIZE(p) (PST_PRIVATE(p)->dwarf_abbrev_size)
#define DWARF_LINE_BUFFER(p) (PST_PRIVATE(p)->dwarf_line_buffer)
+#define DWARF_LINE_SIZE(p) (PST_PRIVATE(p)->dwarf_line_size)
+#define DWARF_STR_BUFFER(p) (PST_PRIVATE(p)->dwarf_str_buffer)
+#define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size)
+#define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer)
+#define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size)
/* Maintain an array of referenced fundamental types for the current
compilation unit being read. For DWARF version 1, we have to construct
int nfnfields;
};
-/* FIXME: Kludge to mark a varargs function type for C++ member function
- argument processing. */
-#define TYPE_FLAG_VARARGS (1 << 10)
-
-/* Dwarf2 has no clean way to discern C++ static and non-static member
- functions. G++ helps GDB by marking the first parameter for non-static
- member functions (which is the this pointer) as artificial.
- We pass this information between dwarf2_add_member_fn and
- read_subroutine_type via TYPE_FIELD_ARTIFICIAL. */
-#define TYPE_FIELD_ARTIFICIAL TYPE_FIELD_BITPOS
-
/* Various complaints about symbol reading that don't abort the process */
static struct complaint dwarf2_const_ignored =
{
"missing .debug_line section", 0, 0
};
+static struct complaint dwarf2_statement_list_fits_in_line_number_section =
+{
+ "statement list doesn't fit in .debug_line section", 0, 0
+};
static struct complaint dwarf2_mangled_line_number_section =
{
"mangled .debug_line section", 0, 0
{
"unsupported const value attribute form: '%s'", 0, 0
};
-
-/* Externals references. */
-extern int info_verbose; /* From main.c; nonzero => verbose */
+static struct complaint dwarf2_misplaced_line_number =
+{
+ "misplaced first line number at 0x%lx for '%s'", 0, 0
+};
+static struct complaint dwarf2_line_header_too_long =
+{
+ "line number info header doesn't fit in `.debug_line' section", 0, 0
+};
+static struct complaint dwarf2_missing_macinfo_section =
+{
+ "missing .debug_macinfo section", 0, 0
+};
+static struct complaint dwarf2_macros_too_long =
+{
+ "macro info runs off end of `.debug_macinfo' section", 0, 0
+};
+static struct complaint dwarf2_macros_not_terminated =
+{
+ "no terminating 0-type entry for macros in `.debug_macinfo' section", 0, 0
+};
+static struct complaint dwarf2_macro_outside_file =
+{
+ "debug info gives macro %s outside of any file: %s", 0, 0
+};
+static struct complaint dwarf2_macro_unmatched_end_file =
+{
+ "macro debug info has an unmatched `close_file' directive", 0, 0
+};
+static struct complaint dwarf2_macro_malformed_definition =
+{
+ "macro debug info contains a malformed macro definition:\n`%s'", 0, 0
+};
+static struct complaint dwarf2_macro_spaces_in_definition =
+{
+ "macro definition contains spaces in formal argument list:\n`%s'", 0, 0
+};
/* local function prototypes */
static void psymtab_to_symtab_1 (struct partial_symtab *);
-static char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int);
+char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int);
static void dwarf2_read_abbrevs (bfd *, unsigned int);
static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int);
static char *read_partial_die (struct partial_die_info *,
- bfd *, char *, int *,
+ bfd *, char *,
const struct comp_unit_head *);
static char *read_full_die (struct die_info **, bfd *, char *,
static char *read_attribute (struct attribute *, struct attr_abbrev *,
bfd *, char *, const struct comp_unit_head *);
+static char *read_attribute_value (struct attribute *, unsigned,
+ bfd *, char *, const struct comp_unit_head *);
+
static unsigned int read_1_byte (bfd *, char *);
static int read_1_signed_byte (bfd *, char *);
static char *read_string (bfd *, char *, unsigned int *);
+static char *read_indirect_string (bfd *, char *, const struct comp_unit_head *,
+ unsigned int *);
+
static unsigned long read_unsigned_leb128 (bfd *, char *, unsigned int *);
static long read_signed_leb128 (bfd *, char *, unsigned int *);
static int die_is_declaration (struct die_info *);
-static void dwarf_decode_lines (unsigned int, char *, bfd *,
+static void free_line_header (struct line_header *lh);
+
+static struct line_header *(dwarf_decode_line_header
+ (unsigned int offset,
+ bfd *abfd,
+ const struct comp_unit_head *cu_header));
+
+static void dwarf_decode_lines (struct line_header *, char *, bfd *,
const struct comp_unit_head *);
static void dwarf2_start_subfile (char *, char *);
struct type *, struct objfile *);
static void dwarf2_add_member_fn (struct field_info *,
- struct die_info *, struct type *,
- struct objfile *objfile,
+ struct die_info *, struct objfile *objfile,
const struct comp_unit_head *);
static void dwarf2_attach_fn_fields_to_type (struct field_info *,
static void read_subroutine_type (struct die_info *, struct objfile *,
const struct comp_unit_head *);
-struct die_info *read_comp_unit (char *, bfd *, const struct comp_unit_head *);
+static struct die_info *read_comp_unit (char *, bfd *,
+ const struct comp_unit_head *);
static void free_die_list (struct die_info *);
struct die_info *copy_die (struct die_info *);
#endif
-struct die_info *sibling_die (struct die_info *);
+static struct die_info *sibling_die (struct die_info *);
-void dump_die (struct die_info *);
+static void dump_die (struct die_info *);
-void dump_die_list (struct die_info *);
+static void dump_die_list (struct die_info *);
-void store_in_ref_table (unsigned int, struct die_info *);
+static void store_in_ref_table (unsigned int, struct die_info *);
static void dwarf2_empty_hash_tables (void);
static unsigned int dwarf2_get_ref_die_offset (struct attribute *);
-struct die_info *follow_die_ref (unsigned int);
+static struct die_info *follow_die_ref (unsigned int);
static struct type *dwarf2_fundamental_type (struct objfile *, int);
static struct die_info *dwarf_alloc_die (void);
+static void initialize_cu_func_list (void);
+
+static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR);
+
+static void dwarf_decode_macros (struct line_header *, unsigned int,
+ char *, bfd *, const struct comp_unit_head *,
+ struct objfile *);
+
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
int
dwarf2_has_info (bfd *abfd)
{
- dwarf_info_offset = dwarf_abbrev_offset = dwarf_line_offset = 0;
+ dwarf_info_offset = 0;
+ dwarf_abbrev_offset = 0;
+ dwarf_line_offset = 0;
+ dwarf_str_offset = 0;
+ dwarf_macinfo_offset = 0;
+ dwarf_frame_offset = 0;
+ dwarf_eh_frame_offset = 0;
bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
if (dwarf_info_offset && dwarf_abbrev_offset)
{
dwarf_str_offset = sectp->filepos;
dwarf_str_size = bfd_get_section_size_before_reloc (sectp);
}
+ else if (STREQ (sectp->name, FRAME_SECTION))
+ {
+ dwarf_frame_offset = sectp->filepos;
+ dwarf_frame_size = bfd_get_section_size_before_reloc (sectp);
+ }
+ else if (STREQ (sectp->name, EH_FRAME_SECTION))
+ {
+ dwarf_eh_frame_offset = sectp->filepos;
+ dwarf_eh_frame_size = bfd_get_section_size_before_reloc (sectp);
+ }
}
/* Build a partial symbol table. */
dwarf_line_offset,
dwarf_line_size);
- if (mainline || objfile->global_psymbols.size == 0 ||
- objfile->static_psymbols.size == 0)
+ if (dwarf_str_offset)
+ dwarf_str_buffer = dwarf2_read_section (objfile,
+ dwarf_str_offset,
+ dwarf_str_size);
+ else
+ dwarf_str_buffer = NULL;
+
+ if (dwarf_macinfo_offset)
+ dwarf_macinfo_buffer = dwarf2_read_section (objfile,
+ dwarf_macinfo_offset,
+ dwarf_macinfo_size);
+ else
+ dwarf_macinfo_buffer = NULL;
+
+ if (mainline
+ || (objfile->global_psymbols.size == 0
+ && objfile->static_psymbols.size == 0))
{
init_psymbol_list (objfile, 1024);
}
struct partial_die_info comp_unit_die;
struct partial_symtab *pst;
struct cleanup *back_to;
- int comp_unit_has_pc_info;
CORE_ADDR lowpc, highpc;
info_ptr = dwarf_info_buffer;
abbrev_ptr = dwarf_abbrev_buffer;
+ /* We use dwarf2_tmp_obstack for objects that don't need to survive
+ the partial symbol scan, like attribute values.
+
+ We could reduce our peak memory consumption during partial symbol
+ table construction by freeing stuff from this obstack more often
+ --- say, after processing each compilation unit, or each die ---
+ but it turns out that this saves almost nothing. For an
+ executable with 11Mb of Dwarf 2 data, I found about 64k allocated
+ on dwarf2_tmp_obstack. Some investigation showed:
+
+ 1) 69% of the attributes used forms DW_FORM_addr, DW_FORM_data*,
+ DW_FORM_flag, DW_FORM_[su]data, and DW_FORM_ref*. These are
+ all fixed-length values not requiring dynamic allocation.
+
+ 2) 30% of the attributes used the form DW_FORM_string. For
+ DW_FORM_string, read_attribute simply hands back a pointer to
+ the null-terminated string in dwarf_info_buffer, so no dynamic
+ allocation is needed there either.
+
+ 3) The remaining 1% of the attributes all used DW_FORM_block1.
+ 75% of those were DW_AT_frame_base location lists for
+ functions; the rest were DW_AT_location attributes, probably
+ for the global variables.
+
+ Anyway, what this all means is that the memory the dwarf2
+ reader uses as temporary space reading partial symbols is about
+ 0.5% as much as we use for dwarf_*_buffer. That's noise. */
+
obstack_init (&dwarf2_tmp_obstack);
back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL);
- while ((unsigned int) (info_ptr - dwarf_info_buffer)
- + ((info_ptr - dwarf_info_buffer) % 4) < dwarf_info_size)
+ /* Since the objects we're extracting from dwarf_info_buffer vary in
+ length, only the individual functions to extract them (like
+ read_comp_unit_head and read_partial_die) can really know whether
+ the buffer is large enough to hold another complete object.
+
+ At the moment, they don't actually check that. If
+ dwarf_info_buffer holds just one extra byte after the last
+ compilation unit's dies, then read_comp_unit_head will happily
+ read off the end of the buffer. read_partial_die is similarly
+ casual. Those functions should be fixed.
+
+ For this loop condition, simply checking whether there's any data
+ left at all should be sufficient. */
+ while (info_ptr < dwarf_info_buffer + dwarf_info_size)
{
struct comp_unit_head cu_header;
beg_of_comp_unit = info_ptr;
/* Read the compilation unit die */
info_ptr = read_partial_die (&comp_unit_die, abfd, info_ptr,
- &comp_unit_has_pc_info, &cu_header);
+ &cu_header);
/* Set the language we're debugging */
set_cu_language (comp_unit_die.language);
DWARF_ABBREV_BUFFER (pst) = dwarf_abbrev_buffer;
DWARF_ABBREV_SIZE (pst) = dwarf_abbrev_size;
DWARF_LINE_BUFFER (pst) = dwarf_line_buffer;
+ DWARF_LINE_SIZE (pst) = dwarf_line_size;
+ DWARF_STR_BUFFER (pst) = dwarf_str_buffer;
+ DWARF_STR_SIZE (pst) = dwarf_str_size;
+ DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer;
+ DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
/* Store the function that reads in the rest of the symbol table */
/* If the compilation unit didn't have an explicit address range,
then use the information extracted from its child dies. */
- if (!comp_unit_has_pc_info)
+ if (! comp_unit_die.has_pc_info)
{
comp_unit_die.lowpc = lowpc;
comp_unit_die.highpc = highpc;
back to that level. */
int nesting_level = 1;
- int has_pc_info;
*lowpc = ((CORE_ADDR) -1);
*highpc = ((CORE_ADDR) 0);
while (nesting_level)
{
- info_ptr = read_partial_die (&pdi, abfd, info_ptr,
- &has_pc_info, cu_header);
+ info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header);
if (pdi.name)
{
switch (pdi.tag)
{
case DW_TAG_subprogram:
- if (has_pc_info)
+ if (pdi.has_pc_info)
{
if (pdi.lowpc < *lowpc)
{
dwarf_abbrev_buffer = DWARF_ABBREV_BUFFER (pst);
dwarf_abbrev_size = DWARF_ABBREV_SIZE (pst);
dwarf_line_buffer = DWARF_LINE_BUFFER (pst);
+ dwarf_line_size = DWARF_LINE_SIZE (pst);
+ dwarf_str_buffer = DWARF_STR_BUFFER (pst);
+ dwarf_str_size = DWARF_STR_SIZE (pst);
+ dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst);
+ dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
cu_header_offset = offset;
info_ptr = dwarf_info_buffer + offset;
}
}
+static void
+initialize_cu_func_list (void)
+{
+ cu_first_fn = cu_last_fn = cu_cached_fn = NULL;
+}
+
static void
read_file_scope (struct die_info *die, struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
- unsigned int line_offset = 0;
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
CORE_ADDR lowpc = ((CORE_ADDR) -1);
CORE_ADDR highpc = ((CORE_ADDR) 0);
struct attribute *attr;
char *comp_dir = NULL;
struct die_info *child_die;
bfd *abfd = objfile->obfd;
+ struct line_header *line_header = 0;
if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile))
{
start_symtab (name, comp_dir, lowpc);
record_debugformat ("DWARF 2");
- /* Decode line number information if present. */
- attr = dwarf_attr (die, DW_AT_stmt_list);
- if (attr)
- {
- line_offset = DW_UNSND (attr);
- dwarf_decode_lines (line_offset, comp_dir, abfd, cu_header);
- }
+ initialize_cu_func_list ();
/* Process all dies in compilation unit. */
if (die->has_children)
child_die = sibling_die (child_die);
}
}
+
+ /* Decode line number information if present. */
+ attr = dwarf_attr (die, DW_AT_stmt_list);
+ if (attr)
+ {
+ unsigned int line_offset = DW_UNSND (attr);
+ line_header = dwarf_decode_line_header (line_offset,
+ abfd, cu_header);
+ if (line_header)
+ {
+ make_cleanup ((make_cleanup_ftype *) free_line_header,
+ (void *) line_header);
+ dwarf_decode_lines (line_header, comp_dir, abfd, cu_header);
+ }
+ }
+
+ /* Decode macro information, if present. Dwarf 2 macro information
+ refers to information in the line number info statement program
+ header, so we can only read it if we've read the header
+ successfully. */
+ attr = dwarf_attr (die, DW_AT_macro_info);
+ if (attr)
+ {
+ unsigned int macro_offset = DW_UNSND (attr);
+ dwarf_decode_macros (line_header, macro_offset,
+ comp_dir, abfd, cu_header, objfile);
+ }
+ do_cleanups (back_to);
+}
+
+static void
+add_to_cu_func_list (const char *name, CORE_ADDR lowpc, CORE_ADDR highpc)
+{
+ struct function_range *thisfn;
+
+ thisfn = (struct function_range *)
+ obstack_alloc (&dwarf2_tmp_obstack, sizeof (struct function_range));
+ thisfn->name = name;
+ thisfn->lowpc = lowpc;
+ thisfn->highpc = highpc;
+ thisfn->seen_line = 0;
+ thisfn->next = NULL;
+
+ if (cu_last_fn == NULL)
+ cu_first_fn = thisfn;
+ else
+ cu_last_fn->next = thisfn;
+
+ cu_last_fn = thisfn;
}
static void
lowpc += baseaddr;
highpc += baseaddr;
+ /* Record the function range for dwarf_decode_lines. */
+ add_to_cu_func_list (name, lowpc, highpc);
+
if (objfile->ei.entry_point >= lowpc &&
objfile->ei.entry_point < highpc)
{
static void
dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
- struct type *type, struct objfile *objfile,
+ struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
struct attribute *attr;
if (die->type && TYPE_CODE (die->type) == TYPE_CODE_FUNC)
{
struct type *return_type = TYPE_TARGET_TYPE (die->type);
- struct type **arg_types;
int nparams = TYPE_NFIELDS (die->type);
- int iparams;
-
- /* Copy argument types from the subroutine type. */
- arg_types = (struct type **)
- TYPE_ALLOC (fnp->type, (nparams + 1) * sizeof (struct type *));
- for (iparams = 0; iparams < nparams; iparams++)
- arg_types[iparams] = TYPE_FIELD_TYPE (die->type, iparams);
-
- /* Set last entry in argument type vector. */
- if (TYPE_FLAGS (die->type) & TYPE_FLAG_VARARGS)
- arg_types[nparams] = NULL;
- else
- arg_types[nparams] = dwarf2_fundamental_type (objfile, FT_VOID);
- smash_to_method_type (fnp->type, type, return_type, arg_types);
+ smash_to_method_type (fnp->type, die->type,
+ TYPE_TARGET_TYPE (die->type),
+ TYPE_FIELDS (die->type),
+ TYPE_NFIELDS (die->type),
+ TYPE_VARARGS (die->type));
/* Handle static member functions.
Dwarf2 has no clean way to discern C++ static and non-static
}
}
+ /* Check for artificial methods. */
+ attr = dwarf_attr (die, DW_AT_artificial);
+ if (attr && DW_UNSND (attr) != 0)
+ fnp->is_artificial = 1;
+
/* Get index in virtual function table if it is a virtual member function. */
attr = dwarf_attr (die, DW_AT_vtable_elem_location);
if (attr)
{
/* C++ member function. */
process_die (child_die, objfile, cu_header);
- dwarf2_add_member_fn (&fi, child_die, type, objfile, cu_header);
+ dwarf2_add_member_fn (&fi, child_die, objfile, cu_header);
}
else if (child_die->tag == DW_TAG_inheritance)
{
/* No children, must be stub. */
TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
}
-
- die->type = type;
}
/* Given a pointer to a die which begins an enumeration, process all
else if (attr->form == DW_FORM_udata
|| attr->form == DW_FORM_data1
|| attr->form == DW_FORM_data2
- || attr->form == DW_FORM_data4)
+ || attr->form == DW_FORM_data4
+ || attr->form == DW_FORM_data8)
{
low = DW_UNSND (attr);
}
else if (attr->form == DW_FORM_udata
|| attr->form == DW_FORM_data1
|| attr->form == DW_FORM_data2
- || attr->form == DW_FORM_data4)
+ || attr->form == DW_FORM_data4
+ || attr->form == DW_FORM_data8)
{
high = DW_UNSND (attr);
}
while (ndim-- > 0)
type = create_array_type (NULL, type, range_types[ndim]);
+ /* Understand Dwarf2 support for vector types (like they occur on
+ the PowerPC w/ AltiVec). Gcc just adds another attribute to the
+ array type. This is not part of the Dwarf2/3 standard yet, but a
+ custom vendor extension. The main difference between a regular
+ array and the vector variant is that vectors are passed by value
+ to functions. */
+ attr = dwarf_attr (die, DW_AT_GNU_vector);
+ if (attr)
+ TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
+
do_cleanups (back_to);
/* Install the type in the die. */
}
else
{
- length = 1;
+ /* check for the DW_AT_byte_size attribute */
+ attr = dwarf_attr (die, DW_AT_byte_size);
+ if (attr)
+ {
+ length = DW_UNSND (attr);
+ }
+ else
+ {
+ length = 1;
+ }
}
index_type = dwarf2_fundamental_type (objfile, FT_INTEGER);
range_type = create_range_type (NULL, index_type, 1, length);
- char_type = dwarf2_fundamental_type (objfile, FT_CHAR);
- type = create_string_type (char_type, range_type);
+ if (cu_language == language_fortran)
+ {
+ /* Need to create a unique string type for bounds
+ information */
+ type = create_string_type (0, range_type);
+ }
+ else
+ {
+ char_type = dwarf2_fundamental_type (objfile, FT_CHAR);
+ type = create_string_type (char_type, range_type);
+ }
die->type = type;
}
read_typedef (struct die_info *die, struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
- struct type *type;
+ struct attribute *attr;
+ char *name = NULL;
if (!die->type)
{
- struct attribute *attr;
- struct type *xtype;
-
- xtype = die_type (die, objfile, cu_header);
-
- type = alloc_type (objfile);
- TYPE_CODE (type) = TYPE_CODE_TYPEDEF;
- TYPE_FLAGS (type) |= TYPE_FLAG_TARGET_STUB;
- TYPE_TARGET_TYPE (type) = xtype;
attr = dwarf_attr (die, DW_AT_name);
if (attr && DW_STRING (attr))
- TYPE_NAME (type) = obsavestring (DW_STRING (attr),
- strlen (DW_STRING (attr)),
- &objfile->type_obstack);
-
- die->type = type;
+ {
+ name = DW_STRING (attr);
+ }
+ die->type = init_type (TYPE_CODE_TYPEDEF, 0, TYPE_FLAG_TARGET_STUB, name, objfile);
+ TYPE_TARGET_TYPE (die->type) = die_type (die, objfile, cu_header);
}
}
if (attr && DW_STRING (attr))
{
enum type_code code = TYPE_CODE_INT;
- int is_unsigned = 0;
+ int type_flags = 0;
switch (encoding)
{
case DW_ATE_address:
/* Turn DW_ATE_address into a void * pointer. */
code = TYPE_CODE_PTR;
- is_unsigned = 1;
+ type_flags |= TYPE_FLAG_UNSIGNED;
break;
case DW_ATE_boolean:
code = TYPE_CODE_BOOL;
- is_unsigned = 1;
+ type_flags |= TYPE_FLAG_UNSIGNED;
break;
case DW_ATE_complex_float:
code = TYPE_CODE_COMPLEX;
break;
case DW_ATE_unsigned:
case DW_ATE_unsigned_char:
- is_unsigned = 1;
+ type_flags |= TYPE_FLAG_UNSIGNED;
break;
default:
complain (&dwarf2_unsupported_at_encoding,
dwarf_type_encoding_name (encoding));
break;
}
- type = init_type (code, size, is_unsigned, DW_STRING (attr), objfile);
+ type = init_type (code, size, type_flags, DW_STRING (attr), objfile);
if (encoding == DW_ATE_address)
TYPE_TARGET_TYPE (type) = dwarf2_fundamental_type (objfile, FT_VOID);
+ else if (encoding == DW_ATE_complex_float)
+ {
+ if (size == 32)
+ TYPE_TARGET_TYPE (type)
+ = dwarf2_fundamental_type (objfile, FT_EXT_PREC_FLOAT);
+ else if (size == 16)
+ TYPE_TARGET_TYPE (type)
+ = dwarf2_fundamental_type (objfile, FT_DBL_PREC_FLOAT);
+ else if (size == 8)
+ TYPE_TARGET_TYPE (type)
+ = dwarf2_fundamental_type (objfile, FT_FLOAT);
+ }
}
else
{
/* Read a whole compilation unit into a linked list of dies. */
-struct die_info *
+static struct die_info *
read_comp_unit (char *info_ptr, bfd *abfd,
const struct comp_unit_head *cu_header)
{
/* Read the contents of the section at OFFSET and of size SIZE from the
object file specified by OBJFILE into the psymbol_obstack and return it. */
-static char *
+char *
dwarf2_read_section (struct objfile *objfile, file_ptr offset,
unsigned int size)
{
buf = (char *) obstack_alloc (&objfile->psymbol_obstack, size);
if ((bfd_seek (abfd, offset, SEEK_SET) != 0) ||
- (bfd_read (buf, size, 1, abfd) != size))
+ (bfd_bread (buf, size, abfd) != size))
{
buf = NULL;
error ("Dwarf Error: Can't read DWARF data from '%s'",
static char *
read_partial_die (struct partial_die_info *part_die, bfd *abfd,
- char *info_ptr, int *has_pc_info,
- const struct comp_unit_head *cu_header)
+ char *info_ptr, const struct comp_unit_head *cu_header)
{
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
int has_high_pc_attr = 0;
*part_die = zeroed_partial_die;
- *has_pc_info = 0;
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
if (!abbrev_number)
int dummy;
spec_ptr = dwarf_info_buffer + dwarf2_get_ref_die_offset (&spec_attr);
- read_partial_die (&spec_die, abfd, spec_ptr, &dummy, cu_header);
+ read_partial_die (&spec_die, abfd, spec_ptr, cu_header);
if (spec_die.name)
{
part_die->name = spec_die.name;
&& part_die->lowpc < part_die->highpc
&& (part_die->lowpc != 0
|| (bfd_get_file_flags (abfd) & HAS_RELOC)))
- *has_pc_info = 1;
+ part_die->has_pc_info = 1;
return info_ptr;
}
return info_ptr;
}
-/* Read an attribute described by an abbreviated attribute. */
+/* Read an attribute value described by an attribute form. */
static char *
-read_attribute (struct attribute *attr, struct attr_abbrev *abbrev,
+read_attribute_value (struct attribute *attr, unsigned form,
bfd *abfd, char *info_ptr,
const struct comp_unit_head *cu_header)
{
unsigned int bytes_read;
struct dwarf_block *blk;
- attr->name = abbrev->name;
- attr->form = abbrev->form;
- switch (abbrev->form)
+ attr->form = form;
+ switch (form)
{
case DW_FORM_addr:
case DW_FORM_ref_addr:
DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
+ case DW_FORM_strp:
+ DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header,
+ &bytes_read);
+ info_ptr += bytes_read;
+ break;
case DW_FORM_block:
blk = dwarf_alloc_block ();
blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
- case DW_FORM_strp:
case DW_FORM_indirect:
+ form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ info_ptr = read_attribute_value (attr, form, abfd, info_ptr, cu_header);
+ break;
default:
error ("Dwarf Error: Cannot handle %s in DWARF reader.",
- dwarf_form_name (abbrev->form));
+ dwarf_form_name (form));
}
return info_ptr;
}
+/* Read an attribute described by an abbreviated attribute. */
+
+static char *
+read_attribute (struct attribute *attr, struct attr_abbrev *abbrev,
+ bfd *abfd, char *info_ptr,
+ const struct comp_unit_head *cu_header)
+{
+ attr->name = abbrev->name;
+ return read_attribute_value (attr, abbrev->form, abfd, info_ptr, cu_header);
+}
+
/* read dwarf information from a buffer */
static unsigned int
/* If the size of a host char is 8 bits, we can return a pointer
to the buffer, otherwise we have to copy the data to a buffer
allocated on the temporary obstack. */
-#if HOST_CHAR_BIT == 8
+ gdb_assert (HOST_CHAR_BIT == 8);
return buf;
-#else
- char *ret;
- unsigned int i;
-
- ret = obstack_alloc (&dwarf2_tmp_obstack, size);
- for (i = 0; i < size; ++i)
- {
- ret[i] = bfd_get_8 (abfd, (bfd_byte *) buf);
- buf++;
- }
- return ret;
-#endif
}
static char *
/* If the size of a host char is 8 bits, we can return a pointer
to the string, otherwise we have to copy the string to a buffer
allocated on the temporary obstack. */
-#if HOST_CHAR_BIT == 8
+ gdb_assert (HOST_CHAR_BIT == 8);
if (*buf == '\0')
{
*bytes_read_ptr = 1;
}
*bytes_read_ptr = strlen (buf) + 1;
return buf;
-#else
- int byte;
- unsigned int i = 0;
+}
+
+static char *
+read_indirect_string (bfd *abfd, char *buf,
+ const struct comp_unit_head *cu_header,
+ unsigned int *bytes_read_ptr)
+{
+ LONGEST str_offset = read_offset (abfd, buf, cu_header,
+ (int *) bytes_read_ptr);
- while ((byte = bfd_get_8 (abfd, (bfd_byte *) buf)) != 0)
+ if (dwarf_str_buffer == NULL)
{
- obstack_1grow (&dwarf2_tmp_obstack, byte);
- i++;
- buf++;
+ error ("DW_FORM_strp used without .debug_str section");
+ return NULL;
}
- if (i == 0)
+ if (str_offset >= dwarf_str_size)
{
- *bytes_read_ptr = 1;
+ error ("DW_FORM_strp pointing outside of .debug_str section");
return NULL;
}
- obstack_1grow (&dwarf2_tmp_obstack, '\0');
- *bytes_read_ptr = i + 1;
- return obstack_finish (&dwarf2_tmp_obstack);
-#endif
+ gdb_assert (HOST_CHAR_BIT == 8);
+ if (dwarf_str_buffer[str_offset] == '\0')
+ return NULL;
+ return dwarf_str_buffer + str_offset;
}
static unsigned long
break;
case DW_LANG_Fortran77:
case DW_LANG_Fortran90:
+ case DW_LANG_Fortran95:
cu_language = language_fortran;
break;
case DW_LANG_Mips_Assembler:
cu_language = language_asm;
break;
+ case DW_LANG_Java:
+ cu_language = language_java;
+ break;
case DW_LANG_Ada83:
case DW_LANG_Cobol74:
case DW_LANG_Cobol85:
&& ! dwarf_attr (die, DW_AT_specification));
}
-/* Decode the line number information for the compilation unit whose
- line number info is at OFFSET in the .debug_line section.
- The compilation directory of the file is passed in COMP_DIR. */
-struct filenames
+/* Free the line_header structure *LH, and any arrays and strings it
+ refers to. */
+static void
+free_line_header (struct line_header *lh)
{
- unsigned int num_files;
- struct fileinfo
+ if (lh->standard_opcode_lengths)
+ xfree (lh->standard_opcode_lengths);
+
+ /* Remember that all the lh->file_names[i].name pointers are
+ pointers into debug_line_buffer, and don't need to be freed. */
+ if (lh->file_names)
+ xfree (lh->file_names);
+
+ /* Similarly for the include directory names. */
+ if (lh->include_dirs)
+ xfree (lh->include_dirs);
+
+ xfree (lh);
+}
+
+
+/* Add an entry to LH's include directory table. */
+static void
+add_include_dir (struct line_header *lh, char *include_dir)
+{
+ /* Grow the array if necessary. */
+ if (lh->include_dirs_size == 0)
{
- char *name;
- unsigned int dir;
- unsigned int time;
- unsigned int size;
+ lh->include_dirs_size = 1; /* for testing */
+ lh->include_dirs = xmalloc (lh->include_dirs_size
+ * sizeof (*lh->include_dirs));
+ }
+ else if (lh->num_include_dirs >= lh->include_dirs_size)
+ {
+ lh->include_dirs_size *= 2;
+ lh->include_dirs = xrealloc (lh->include_dirs,
+ (lh->include_dirs_size
+ * sizeof (*lh->include_dirs)));
}
- *files;
-};
-struct directories
- {
- unsigned int num_dirs;
- char **dirs;
- };
+ lh->include_dirs[lh->num_include_dirs++] = include_dir;
+}
+
+/* Add an entry to LH's file name table. */
static void
-dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
- const struct comp_unit_head *cu_header)
+add_file_name (struct line_header *lh,
+ char *name,
+ unsigned int dir_index,
+ unsigned int mod_time,
+ unsigned int length)
{
- char *line_ptr;
- char *line_end;
- struct line_head lh;
- struct cleanup *back_to;
- unsigned int i, bytes_read;
- char *cur_file, *cur_dir;
- unsigned char op_code, extended_op, adj_opcode;
+ struct file_entry *fe;
-#define FILE_ALLOC_CHUNK 5
-#define DIR_ALLOC_CHUNK 5
+ /* Grow the array if necessary. */
+ if (lh->file_names_size == 0)
+ {
+ lh->file_names_size = 1; /* for testing */
+ lh->file_names = xmalloc (lh->file_names_size
+ * sizeof (*lh->file_names));
+ }
+ else if (lh->num_file_names >= lh->file_names_size)
+ {
+ lh->file_names_size *= 2;
+ lh->file_names = xrealloc (lh->file_names,
+ (lh->file_names_size
+ * sizeof (*lh->file_names)));
+ }
- struct filenames files;
- struct directories dirs;
+ fe = &lh->file_names[lh->num_file_names++];
+ fe->name = name;
+ fe->dir_index = dir_index;
+ fe->mod_time = mod_time;
+ fe->length = length;
+}
+
+
+/* Read the statement program header starting at OFFSET in
+ dwarf_line_buffer, according to the endianness of ABFD. Return a
+ pointer to a struct line_header, allocated using xmalloc.
+
+ NOTE: the strings in the include directory and file name tables of
+ the returned object point into debug_line_buffer, and must not be
+ freed. */
+static struct line_header *
+dwarf_decode_line_header (unsigned int offset, bfd *abfd,
+ const struct comp_unit_head *cu_header)
+{
+ struct cleanup *back_to;
+ struct line_header *lh;
+ char *line_ptr;
+ int bytes_read;
+ int i;
+ char *cur_dir, *cur_file;
if (dwarf_line_buffer == NULL)
{
complain (&dwarf2_missing_line_number_section);
- return;
+ return 0;
}
- files.num_files = 0;
- files.files = NULL;
+ /* Make sure that at least there's room for the total_length field. That
+ could be 12 bytes long, but we're just going to fudge that. */
+ if (offset + 4 >= dwarf_line_size)
+ {
+ complain (&dwarf2_statement_list_fits_in_line_number_section);
+ return 0;
+ }
- dirs.num_dirs = 0;
- dirs.dirs = NULL;
+ lh = xmalloc (sizeof (*lh));
+ memset (lh, 0, sizeof (*lh));
+ back_to = make_cleanup ((make_cleanup_ftype *) free_line_header,
+ (void *) lh);
line_ptr = dwarf_line_buffer + offset;
- /* read in the prologue */
- lh.total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
+ /* read in the header */
+ lh->total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
line_ptr += bytes_read;
- line_end = line_ptr + lh.total_length;
- lh.version = read_2_bytes (abfd, line_ptr);
+ if (line_ptr + lh->total_length > dwarf_line_buffer + dwarf_line_size)
+ {
+ complain (&dwarf2_statement_list_fits_in_line_number_section);
+ return 0;
+ }
+ lh->statement_program_end = line_ptr + lh->total_length;
+ lh->version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
- lh.prologue_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
+ lh->header_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
line_ptr += bytes_read;
- lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
+ lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- lh.default_is_stmt = read_1_byte (abfd, line_ptr);
+ lh->default_is_stmt = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- lh.line_base = read_1_signed_byte (abfd, line_ptr);
+ lh->line_base = read_1_signed_byte (abfd, line_ptr);
line_ptr += 1;
- lh.line_range = read_1_byte (abfd, line_ptr);
+ lh->line_range = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- lh.opcode_base = read_1_byte (abfd, line_ptr);
+ lh->opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- lh.standard_opcode_lengths = (unsigned char *)
- xmalloc (lh.opcode_base * sizeof (unsigned char));
- back_to = make_cleanup (free_current_contents, &lh.standard_opcode_lengths);
+ lh->standard_opcode_lengths
+ = (unsigned char *) xmalloc (lh->opcode_base * sizeof (unsigned char));
- lh.standard_opcode_lengths[0] = 1;
- for (i = 1; i < lh.opcode_base; ++i)
+ lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
+ for (i = 1; i < lh->opcode_base; ++i)
{
- lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
+ lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
- if ((dirs.num_dirs % DIR_ALLOC_CHUNK) == 0)
- {
- dirs.dirs = (char **)
- xrealloc (dirs.dirs,
- (dirs.num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *));
- if (dirs.num_dirs == 0)
- make_cleanup (free_current_contents, &dirs.dirs);
- }
- dirs.dirs[dirs.num_dirs++] = cur_dir;
+ add_include_dir (lh, cur_dir);
}
line_ptr += bytes_read;
/* Read file name table */
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
+ unsigned int dir_index, mod_time, length;
+
line_ptr += bytes_read;
- if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
- {
- files.files = (struct fileinfo *)
- xrealloc (files.files,
- (files.num_files + FILE_ALLOC_CHUNK)
- * sizeof (struct fileinfo));
- if (files.num_files == 0)
- make_cleanup (free_current_contents, &files.files);
- }
- files.files[files.num_files].name = cur_file;
- files.files[files.num_files].dir =
- read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- files.files[files.num_files].time =
- read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- files.files[files.num_files].size =
- read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- files.num_files++;
+
+ add_file_name (lh, cur_file, dir_index, mod_time, length);
}
line_ptr += bytes_read;
+ lh->statement_program_start = line_ptr;
+
+ if (line_ptr > dwarf_line_buffer + dwarf_line_size)
+ complain (&dwarf2_line_header_too_long);
+
+ discard_cleanups (back_to);
+ return lh;
+}
+
+/* This function exists to work around a bug in certain compilers
+ (particularly GCC 2.95), in which the first line number marker of a
+ function does not show up until after the prologue, right before
+ the second line number marker. This function shifts ADDRESS down
+ to the beginning of the function if necessary, and is called on
+ addresses passed to record_line. */
+
+static CORE_ADDR
+check_cu_functions (CORE_ADDR address)
+{
+ struct function_range *fn;
+
+ /* Find the function_range containing address. */
+ if (!cu_first_fn)
+ return address;
+
+ if (!cu_cached_fn)
+ cu_cached_fn = cu_first_fn;
+
+ fn = cu_cached_fn;
+ while (fn)
+ if (fn->lowpc <= address && fn->highpc > address)
+ goto found;
+ else
+ fn = fn->next;
+
+ fn = cu_first_fn;
+ while (fn && fn != cu_cached_fn)
+ if (fn->lowpc <= address && fn->highpc > address)
+ goto found;
+ else
+ fn = fn->next;
+
+ return address;
+
+ found:
+ if (fn->seen_line)
+ return address;
+ if (address != fn->lowpc)
+ complain (&dwarf2_misplaced_line_number,
+ (unsigned long) address, fn->name);
+ fn->seen_line = 1;
+ return fn->lowpc;
+}
+
+/* Decode the line number information for the compilation unit whose
+ line number info is at OFFSET in the .debug_line section.
+ The compilation directory of the file is passed in COMP_DIR. */
+
+static void
+dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
+ const struct comp_unit_head *cu_header)
+{
+ char *line_ptr;
+ char *line_end;
+ unsigned int i, bytes_read;
+ char *cur_dir;
+ unsigned char op_code, extended_op, adj_opcode;
+
+ line_ptr = lh->statement_program_start;
+ line_end = lh->statement_program_end;
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
unsigned int file = 1;
unsigned int line = 1;
unsigned int column = 0;
- int is_stmt = lh.default_is_stmt;
+ int is_stmt = lh->default_is_stmt;
int basic_block = 0;
int end_sequence = 0;
/* Start a subfile for the current file of the state machine. */
- if (files.num_files >= file)
+ if (lh->num_file_names >= file)
{
- /* The file and directory tables are 0 based, the references
- are 1 based. */
- dwarf2_start_subfile (files.files[file - 1].name,
- (files.files[file - 1].dir
- ? dirs.dirs[files.files[file - 1].dir - 1]
- : comp_dir));
+ /* lh->include_dirs and lh->file_names are 0-based, but the
+ directory and file name numbers in the statement program
+ are 1-based. */
+ struct file_entry *fe = &lh->file_names[file - 1];
+ char *dir;
+ if (fe->dir_index)
+ dir = lh->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+ dwarf2_start_subfile (fe->name, dir);
}
/* Decode the table. */
{
op_code = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- switch (op_code)
+
+ if (op_code >= lh->opcode_base)
+ { /* Special operand. */
+ adj_opcode = op_code - lh->opcode_base;
+ address += (adj_opcode / lh->line_range)
+ * lh->minimum_instruction_length;
+ line += lh->line_base + (adj_opcode % lh->line_range);
+ /* append row to matrix using current values */
+ address = check_cu_functions (address);
+ record_line (current_subfile, line, address);
+ basic_block = 1;
+ }
+ else switch (op_code)
{
case DW_LNS_extended_op:
line_ptr += 1; /* ignore length */
{
case DW_LNE_end_sequence:
end_sequence = 1;
- /* Don't call record_line here. The end_sequence
- instruction provides the address of the first byte
- *after* the last line in the sequence; it's not the
- address of any real source line. However, the GDB
- linetable structure only records the starts of lines,
- not the ends. This is a weakness of GDB. */
+ record_line (current_subfile, 0, address);
break;
case DW_LNE_set_address:
address = read_address (abfd, line_ptr, cu_header, &bytes_read);
address += baseaddr;
break;
case DW_LNE_define_file:
- cur_file = read_string (abfd, line_ptr, &bytes_read);
- line_ptr += bytes_read;
- if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
- {
- files.files = (struct fileinfo *)
- xrealloc (files.files,
- (files.num_files + FILE_ALLOC_CHUNK)
- * sizeof (struct fileinfo));
- if (files.num_files == 0)
- make_cleanup (free_current_contents, &files.files);
- }
- files.files[files.num_files].name = cur_file;
- files.files[files.num_files].dir =
- read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
- line_ptr += bytes_read;
- files.files[files.num_files].time =
- read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
- line_ptr += bytes_read;
- files.files[files.num_files].size =
- read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
- line_ptr += bytes_read;
- files.num_files++;
+ {
+ char *cur_file;
+ unsigned int dir_index, mod_time, length;
+
+ cur_file = read_string (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ dir_index =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ mod_time =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ length =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ add_file_name (lh, cur_file, dir_index, mod_time, length);
+ }
break;
default:
complain (&dwarf2_mangled_line_number_section);
- goto done;
+ return;
}
break;
case DW_LNS_copy:
+ address = check_cu_functions (address);
record_line (current_subfile, line, address);
basic_block = 0;
break;
case DW_LNS_advance_pc:
- address += lh.minimum_instruction_length
+ address += lh->minimum_instruction_length
* read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
line_ptr += bytes_read;
break;
case DW_LNS_set_file:
- /* The file and directory tables are 0 based, the references
- are 1 based. */
- file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
- line_ptr += bytes_read;
- dwarf2_start_subfile
- (files.files[file - 1].name,
- (files.files[file - 1].dir
- ? dirs.dirs[files.files[file - 1].dir - 1]
- : comp_dir));
+ {
+ /* lh->include_dirs and lh->file_names are 0-based,
+ but the directory and file name numbers in the
+ statement program are 1-based. */
+ struct file_entry *fe;
+ char *dir;
+ file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ fe = &lh->file_names[file - 1];
+ if (fe->dir_index)
+ dir = lh->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+ dwarf2_start_subfile (fe->name, dir);
+ }
break;
case DW_LNS_set_column:
column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
length since special opcode 255 would have scaled the
the increment. */
case DW_LNS_const_add_pc:
- address += (lh.minimum_instruction_length
- * ((255 - lh.opcode_base) / lh.line_range));
+ address += (lh->minimum_instruction_length
+ * ((255 - lh->opcode_base) / lh->line_range));
break;
case DW_LNS_fixed_advance_pc:
address += read_2_bytes (abfd, line_ptr);
line_ptr += 2;
break;
- default: /* special operand */
- adj_opcode = op_code - lh.opcode_base;
- address += (adj_opcode / lh.line_range)
- * lh.minimum_instruction_length;
- line += lh.line_base + (adj_opcode % lh.line_range);
- /* append row to matrix using current values */
- record_line (current_subfile, line, address);
- basic_block = 1;
+ default:
+ { /* Unknown standard opcode, ignore it. */
+ int i;
+ for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
+ {
+ (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ }
+ }
}
}
}
-done:
- do_cleanups (back_to);
}
/* Start a subfile for DWARF. FILENAME is the name of the file and
/* If the filename isn't absolute, try to match an existing subfile
with the full pathname. */
- if (*filename != '/' && dirname != NULL)
+ if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL)
{
struct subfile *subfile;
char *fullname = concat (dirname, "/", filename, NULL);
for (subfile = subfiles; subfile; subfile = subfile->next)
{
- if (STREQ (subfile->name, fullname))
+ if (FILENAME_CMP (subfile->name, fullname) == 0)
{
current_subfile = subfile;
xfree (fullname);
/* Return sibling of die, NULL if no sibling. */
-struct die_info *
+static struct die_info *
sibling_die (struct die_info *die)
{
int nesting_level = 0;
return "DW_AT_body_begin";
case DW_AT_body_end:
return "DW_AT_body_end";
+ case DW_AT_GNU_vector:
+ return "DW_AT_GNU_vector";
default:
return "DW_AT_<unknown>";
}
return "DW_CFA_def_cfa_register";
case DW_CFA_def_cfa_offset:
return "DW_CFA_def_cfa_offset";
+
+ /* DWARF 3 */
+ case DW_CFA_def_cfa_expression:
+ return "DW_CFA_def_cfa_expression";
+ case DW_CFA_expression:
+ return "DW_CFA_expression";
+ case DW_CFA_offset_extended_sf:
+ return "DW_CFA_offset_extended_sf";
+ case DW_CFA_def_cfa_sf:
+ return "DW_CFA_def_cfa_sf";
+ case DW_CFA_def_cfa_offset_sf:
+ return "DW_CFA_def_cfa_offset_sf";
+
/* SGI/MIPS specific */
case DW_CFA_MIPS_advance_loc8:
return "DW_CFA_MIPS_advance_loc8";
+
+ /* GNU extensions */
+ case DW_CFA_GNU_window_save:
+ return "DW_CFA_GNU_window_save";
+ case DW_CFA_GNU_args_size:
+ return "DW_CFA_GNU_args_size";
+ case DW_CFA_GNU_negative_offset_extended:
+ return "DW_CFA_GNU_negative_offset_extended";
+
default:
return "DW_CFA_<unknown>";
}
}
#endif
-void
+static void
dump_die (struct die_info *die)
{
unsigned int i;
- fprintf (stderr, "Die: %s (abbrev = %d, offset = %d)\n",
+ fprintf_unfiltered (gdb_stderr, "Die: %s (abbrev = %d, offset = %d)\n",
dwarf_tag_name (die->tag), die->abbrev, die->offset);
- fprintf (stderr, "\thas children: %s\n",
+ fprintf_unfiltered (gdb_stderr, "\thas children: %s\n",
dwarf_bool_name (die->has_children));
- fprintf (stderr, "\tattributes:\n");
+ fprintf_unfiltered (gdb_stderr, "\tattributes:\n");
for (i = 0; i < die->num_attrs; ++i)
{
- fprintf (stderr, "\t\t%s (%s) ",
+ fprintf_unfiltered (gdb_stderr, "\t\t%s (%s) ",
dwarf_attr_name (die->attrs[i].name),
dwarf_form_name (die->attrs[i].form));
switch (die->attrs[i].form)
{
case DW_FORM_ref_addr:
case DW_FORM_addr:
- fprintf (stderr, "address: ");
+ fprintf_unfiltered (gdb_stderr, "address: ");
print_address_numeric (DW_ADDR (&die->attrs[i]), 1, gdb_stderr);
break;
case DW_FORM_block2:
case DW_FORM_block4:
case DW_FORM_block:
case DW_FORM_block1:
- fprintf (stderr, "block: size %d", DW_BLOCK (&die->attrs[i])->size);
+ fprintf_unfiltered (gdb_stderr, "block: size %d", DW_BLOCK (&die->attrs[i])->size);
break;
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_ref4:
case DW_FORM_udata:
case DW_FORM_sdata:
- fprintf (stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
+ fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
break;
case DW_FORM_string:
- fprintf (stderr, "string: \"%s\"",
+ case DW_FORM_strp:
+ fprintf_unfiltered (gdb_stderr, "string: \"%s\"",
DW_STRING (&die->attrs[i])
? DW_STRING (&die->attrs[i]) : "");
break;
case DW_FORM_flag:
if (DW_UNSND (&die->attrs[i]))
- fprintf (stderr, "flag: TRUE");
+ fprintf_unfiltered (gdb_stderr, "flag: TRUE");
else
- fprintf (stderr, "flag: FALSE");
+ fprintf_unfiltered (gdb_stderr, "flag: FALSE");
+ break;
+ case DW_FORM_indirect:
+ /* the reader will have reduced the indirect form to
+ the "base form" so this form should not occur */
+ fprintf_unfiltered (gdb_stderr, "unexpected attribute form: DW_FORM_indirect");
break;
- case DW_FORM_strp: /* we do not support separate string
- section yet */
- case DW_FORM_indirect: /* we do not handle indirect yet */
default:
- fprintf (stderr, "unsupported attribute form: %d.",
+ fprintf_unfiltered (gdb_stderr, "unsupported attribute form: %d.",
die->attrs[i].form);
}
- fprintf (stderr, "\n");
+ fprintf_unfiltered (gdb_stderr, "\n");
}
}
-void
+static void
dump_die_list (struct die_info *die)
{
while (die)
}
}
-void
+static void
store_in_ref_table (unsigned int offset, struct die_info *die)
{
int h;
return result;
}
-struct die_info *
+static struct die_info *
follow_die_ref (unsigned int offset)
{
struct die_info *die;
op = data[i++];
switch (op)
{
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ stack[++stacki] = op - DW_OP_lit0;
+ break;
+
case DW_OP_reg0:
case DW_OP_reg1:
case DW_OP_reg2:
i += bytes_read;
break;
+ case DW_OP_dup:
+ stack[stacki + 1] = stack[stacki];
+ stacki++;
+ break;
+
case DW_OP_plus:
stack[stacki - 1] += stack[stacki];
stacki--;
break;
case DW_OP_minus:
- stack[stacki - 1] = stack[stacki] - stack[stacki - 1];
+ stack[stacki - 1] -= stack[stacki];
stacki--;
break;
memset (die, 0, sizeof (struct die_info));
return (die);
}
+
+\f
+/* Macro support. */
+
+
+/* Return the full name of file number I in *LH's file name table.
+ Use COMP_DIR as the name of the current directory of the
+ compilation. The result is allocated using xmalloc; the caller is
+ responsible for freeing it. */
+static char *
+file_full_name (int file, struct line_header *lh, const char *comp_dir)
+{
+ struct file_entry *fe = &lh->file_names[file - 1];
+
+ if (IS_ABSOLUTE_PATH (fe->name))
+ return xstrdup (fe->name);
+ else
+ {
+ const char *dir;
+ int dir_len;
+ char *full_name;
+
+ if (fe->dir_index)
+ dir = lh->include_dirs[fe->dir_index - 1];
+ else
+ dir = comp_dir;
+
+ if (dir)
+ {
+ dir_len = strlen (dir);
+ full_name = xmalloc (dir_len + 1 + strlen (fe->name) + 1);
+ strcpy (full_name, dir);
+ full_name[dir_len] = '/';
+ strcpy (full_name + dir_len + 1, fe->name);
+ return full_name;
+ }
+ else
+ return xstrdup (fe->name);
+ }
+}
+
+
+static struct macro_source_file *
+macro_start_file (int file, int line,
+ struct macro_source_file *current_file,
+ const char *comp_dir,
+ struct line_header *lh, struct objfile *objfile)
+{
+ /* The full name of this source file. */
+ char *full_name = file_full_name (file, lh, comp_dir);
+
+ /* We don't create a macro table for this compilation unit
+ at all until we actually get a filename. */
+ if (! pending_macros)
+ pending_macros = new_macro_table (&objfile->symbol_obstack,
+ &objfile->macro_cache);
+
+ if (! current_file)
+ /* If we have no current file, then this must be the start_file
+ directive for the compilation unit's main source file. */
+ current_file = macro_set_main (pending_macros, full_name);
+ else
+ current_file = macro_include (current_file, line, full_name);
+
+ xfree (full_name);
+
+ return current_file;
+}
+
+
+/* Copy the LEN characters at BUF to a xmalloc'ed block of memory,
+ followed by a null byte. */
+static char *
+copy_string (const char *buf, int len)
+{
+ char *s = xmalloc (len + 1);
+ memcpy (s, buf, len);
+ s[len] = '\0';
+
+ return s;
+}
+
+
+static const char *
+consume_improper_spaces (const char *p, const char *body)
+{
+ if (*p == ' ')
+ {
+ complain (&dwarf2_macro_spaces_in_definition, body);
+
+ while (*p == ' ')
+ p++;
+ }
+
+ return p;
+}
+
+
+static void
+parse_macro_definition (struct macro_source_file *file, int line,
+ const char *body)
+{
+ const char *p;
+
+ /* The body string takes one of two forms. For object-like macro
+ definitions, it should be:
+
+ <macro name> " " <definition>
+
+ For function-like macro definitions, it should be:
+
+ <macro name> "() " <definition>
+ or
+ <macro name> "(" <arg name> ( "," <arg name> ) * ") " <definition>
+
+ Spaces may appear only where explicitly indicated, and in the
+ <definition>.
+
+ The Dwarf 2 spec says that an object-like macro's name is always
+ followed by a space, but versions of GCC around March 2002 omit
+ the space when the macro's definition is the empty string.
+
+ The Dwarf 2 spec says that there should be no spaces between the
+ formal arguments in a function-like macro's formal argument list,
+ but versions of GCC around March 2002 include spaces after the
+ commas. */
+
+
+ /* Find the extent of the macro name. The macro name is terminated
+ by either a space or null character (for an object-like macro) or
+ an opening paren (for a function-like macro). */
+ for (p = body; *p; p++)
+ if (*p == ' ' || *p == '(')
+ break;
+
+ if (*p == ' ' || *p == '\0')
+ {
+ /* It's an object-like macro. */
+ int name_len = p - body;
+ char *name = copy_string (body, name_len);
+ const char *replacement;
+
+ if (*p == ' ')
+ replacement = body + name_len + 1;
+ else
+ {
+ complain (&dwarf2_macro_malformed_definition, body);
+ replacement = body + name_len;
+ }
+
+ macro_define_object (file, line, name, replacement);
+
+ xfree (name);
+ }
+ else if (*p == '(')
+ {
+ /* It's a function-like macro. */
+ char *name = copy_string (body, p - body);
+ int argc = 0;
+ int argv_size = 1;
+ char **argv = xmalloc (argv_size * sizeof (*argv));
+
+ p++;
+
+ p = consume_improper_spaces (p, body);
+
+ /* Parse the formal argument list. */
+ while (*p && *p != ')')
+ {
+ /* Find the extent of the current argument name. */
+ const char *arg_start = p;
+
+ while (*p && *p != ',' && *p != ')' && *p != ' ')
+ p++;
+
+ if (! *p || p == arg_start)
+ complain (&dwarf2_macro_malformed_definition,
+ body);
+ else
+ {
+ /* Make sure argv has room for the new argument. */
+ if (argc >= argv_size)
+ {
+ argv_size *= 2;
+ argv = xrealloc (argv, argv_size * sizeof (*argv));
+ }
+
+ argv[argc++] = copy_string (arg_start, p - arg_start);
+ }
+
+ p = consume_improper_spaces (p, body);
+
+ /* Consume the comma, if present. */
+ if (*p == ',')
+ {
+ p++;
+
+ p = consume_improper_spaces (p, body);
+ }
+ }
+
+ if (*p == ')')
+ {
+ p++;
+
+ if (*p == ' ')
+ /* Perfectly formed definition, no complaints. */
+ macro_define_function (file, line, name,
+ argc, (const char **) argv,
+ p + 1);
+ else if (*p == '\0')
+ {
+ /* Complain, but do define it. */
+ complain (&dwarf2_macro_malformed_definition, body);
+ macro_define_function (file, line, name,
+ argc, (const char **) argv,
+ p);
+ }
+ else
+ /* Just complain. */
+ complain (&dwarf2_macro_malformed_definition, body);
+ }
+ else
+ /* Just complain. */
+ complain (&dwarf2_macro_malformed_definition, body);
+
+ xfree (name);
+ {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ xfree (argv[i]);
+ }
+ xfree (argv);
+ }
+ else
+ complain (&dwarf2_macro_malformed_definition, body);
+}
+
+
+static void
+dwarf_decode_macros (struct line_header *lh, unsigned int offset,
+ char *comp_dir, bfd *abfd,
+ const struct comp_unit_head *cu_header,
+ struct objfile *objfile)
+{
+ char *mac_ptr, *mac_end;
+ struct macro_source_file *current_file = 0;
+
+ if (dwarf_macinfo_buffer == NULL)
+ {
+ complain (&dwarf2_missing_macinfo_section);
+ return;
+ }
+
+ mac_ptr = dwarf_macinfo_buffer + offset;
+ mac_end = dwarf_macinfo_buffer + dwarf_macinfo_size;
+
+ for (;;)
+ {
+ enum dwarf_macinfo_record_type macinfo_type;
+
+ /* Do we at least have room for a macinfo type byte? */
+ if (mac_ptr >= mac_end)
+ {
+ complain (&dwarf2_macros_too_long);
+ return;
+ }
+
+ macinfo_type = read_1_byte (abfd, mac_ptr);
+ mac_ptr++;
+
+ switch (macinfo_type)
+ {
+ /* A zero macinfo type indicates the end of the macro
+ information. */
+ case 0:
+ return;
+
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ {
+ int bytes_read;
+ int line;
+ char *body;
+
+ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ body = read_string (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ if (! current_file)
+ complain (&dwarf2_macro_outside_file,
+ macinfo_type == DW_MACINFO_define ? "definition" :
+ macinfo_type == DW_MACINFO_undef ? "undefinition" :
+ "something-or-other",
+ body);
+ else
+ {
+ if (macinfo_type == DW_MACINFO_define)
+ parse_macro_definition (current_file, line, body);
+ else if (macinfo_type == DW_MACINFO_undef)
+ macro_undef (current_file, line, body);
+ }
+ }
+ break;
+
+ case DW_MACINFO_start_file:
+ {
+ int bytes_read;
+ int line, file;
+
+ line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ current_file = macro_start_file (file, line,
+ current_file, comp_dir,
+ lh, objfile);
+ }
+ break;
+
+ case DW_MACINFO_end_file:
+ if (! current_file)
+ complain (&dwarf2_macro_unmatched_end_file);
+ else
+ {
+ current_file = current_file->included_by;
+ if (! current_file)
+ {
+ enum dwarf_macinfo_record_type next_type;
+
+ /* GCC circa March 2002 doesn't produce the zero
+ type byte marking the end of the compilation
+ unit. Complain if it's not there, but exit no
+ matter what. */
+
+ /* Do we at least have room for a macinfo type byte? */
+ if (mac_ptr >= mac_end)
+ {
+ complain (&dwarf2_macros_too_long);
+ return;
+ }
+
+ /* We don't increment mac_ptr here, so this is just
+ a look-ahead. */
+ next_type = read_1_byte (abfd, mac_ptr);
+ if (next_type != 0)
+ complain (&dwarf2_macros_not_terminated);
+
+ return;
+ }
+ }
+ break;
+
+ case DW_MACINFO_vendor_ext:
+ {
+ int bytes_read;
+ int constant;
+ char *string;
+
+ constant = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+ string = read_string (abfd, mac_ptr, &bytes_read);
+ mac_ptr += bytes_read;
+
+ /* We don't recognize any vendor extensions. */
+ }
+ break;
+ }
+ }
+}