-/* Output Dwarf2 format symbol table information from the GNU C compiler.
- Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
- Free Software Foundation, Inc.
+/* Output Dwarf2 format symbol table information from GCC.
+ Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003 Free Software Foundation, Inc.
Contributed by Gary Funck (gary@intrepid.com).
Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
Extensively modified by Jason Merrill (jason@cygnus.com).
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "flags.h"
#include "real.h"
#include "debug.h"
#include "target.h"
#include "langhooks.h"
-#include "hashtable.h"
+#include "hashtab.h"
+#include "cgraph.h"
#ifdef DWARF2_DEBUGGING_INFO
-static void dwarf2out_source_line PARAMS ((unsigned int, const char *));
+static void dwarf2out_source_line (unsigned int, const char *);
#endif
/* DWARF2 Abbreviation Glossary:
translation unit. */
int
-dwarf2out_do_frame ()
+dwarf2out_do_frame (void)
{
return (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
#endif
-/* Default version of targetm.eh_frame_section. Note this must appear
- outside the DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO macro
- guards. */
+/* Various versions of targetm.eh_frame_section. Note these must appear
+ outside the DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO macro guards. */
+/* Version of targetm.eh_frame_section for systems with named sections. */
void
-default_eh_frame_section ()
+named_section_eh_frame_section (void)
{
#ifdef EH_FRAME_SECTION_NAME
- named_section_flags (EH_FRAME_SECTION_NAME, SECTION_WRITE);
+#ifdef HAVE_LD_RO_RW_SECTION_MIXING
+ int fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
+ int per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
+ int lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
+ int flags;
+
+ flags = (! flag_pic
+ || ((fde_encoding & 0x70) != DW_EH_PE_absptr
+ && (fde_encoding & 0x70) != DW_EH_PE_aligned
+ && (per_encoding & 0x70) != DW_EH_PE_absptr
+ && (per_encoding & 0x70) != DW_EH_PE_aligned
+ && (lsda_encoding & 0x70) != DW_EH_PE_absptr
+ && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
+ ? 0 : SECTION_WRITE;
+ named_section_flags (EH_FRAME_SECTION_NAME, flags);
#else
+ named_section_flags (EH_FRAME_SECTION_NAME, SECTION_WRITE);
+#endif
+#endif
+}
+
+/* Version of targetm.eh_frame_section for systems using collect2. */
+void
+collect2_eh_frame_section (void)
+{
tree label = get_file_function_name ('F');
data_section ();
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
- ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+ (*targetm.asm_out.globalize_label) (asm_out_file, IDENTIFIER_POINTER (label));
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+}
+
+/* Default version of targetm.eh_frame_section. */
+void
+default_eh_frame_section (void)
+{
+#ifdef EH_FRAME_SECTION_NAME
+ named_section_eh_frame_section ();
+#else
+ collect2_eh_frame_section ();
#endif
}
define type declaration DIE's. */
static GTY(()) varray_type decl_scope_table;
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
and address fields are provided as possible operands;
their use is selected by the opcode field. */
-typedef union dw_cfi_oprnd_struct
+enum dw_cfi_oprnd_type {
+ dw_cfi_oprnd_unused,
+ dw_cfi_oprnd_reg_num,
+ dw_cfi_oprnd_offset,
+ dw_cfi_oprnd_addr,
+ dw_cfi_oprnd_loc
+};
+
+typedef union dw_cfi_oprnd_struct GTY(())
{
- unsigned long dw_cfi_reg_num;
- long int dw_cfi_offset;
- const char *dw_cfi_addr;
- struct dw_loc_descr_struct *dw_cfi_loc;
+ unsigned long GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num;
+ HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset;
+ const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr;
+ struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc;
}
dw_cfi_oprnd;
-typedef struct dw_cfi_struct
+typedef struct dw_cfi_struct GTY(())
{
dw_cfi_ref dw_cfi_next;
enum dwarf_call_frame_info dw_cfi_opc;
- dw_cfi_oprnd dw_cfi_oprnd1;
- dw_cfi_oprnd dw_cfi_oprnd2;
+ dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)")))
+ dw_cfi_oprnd1;
+ dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)")))
+ dw_cfi_oprnd2;
}
dw_cfi_node;
It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
Instead of passing around REG and OFFSET, we pass a copy
of this structure. */
-typedef struct cfa_loc
+typedef struct cfa_loc GTY(())
{
unsigned long reg;
- long offset;
- long base_offset;
+ HOST_WIDE_INT offset;
+ HOST_WIDE_INT base_offset;
int indirect; /* 1 if CFA is accessed via a dereference. */
} dw_cfa_location;
CIE obviates the need to keep track of multiple CIE's
in the DWARF generation routines below. */
-typedef struct dw_fde_struct
+typedef struct dw_fde_struct GTY(())
{
const char *dw_fde_begin;
const char *dw_fde_current_label;
const char *dw_fde_end;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
+ unsigned all_throwers_are_sibcalls : 1;
unsigned nothrow : 1;
unsigned uses_eh_lsda : 1;
}
#define DWARF_OFFSET_SIZE 4
#endif
+/* According to the (draft) DWARF 3 specification, the initial length
+ should either be 4 or 12 bytes. When it's 12 bytes, the first 4
+ bytes are 0xffffffff, followed by the length stored in the next 8
+ bytes.
+
+ However, the SGI/MIPS ABI uses an initial length which is equal to
+ DWARF_OFFSET_SIZE. It is defined (elsewhere) accordingly. */
+
+#ifndef DWARF_INITIAL_LENGTH_SIZE
+#define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12)
+#endif
+
#define DWARF_VERSION 2
/* Round SIZE up to the nearest BOUNDARY. */
/* A pointer to the base of a table that contains frame description
information for each routine. */
-static dw_fde_ref fde_table;
+static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
/* Number of elements currently allocated for fde_table. */
-static unsigned fde_table_allocated;
+static GTY(()) unsigned fde_table_allocated;
/* Number of elements in fde_table currently in use. */
-static unsigned fde_table_in_use;
+static GTY(()) unsigned fde_table_in_use;
/* Size (in elements) of increments by which we may expand the
fde_table. */
#define FDE_TABLE_INCREMENT 256
/* A list of call frame insns for the CIE. */
-static dw_cfi_ref cie_cfi_head;
+static GTY(()) dw_cfi_ref cie_cfi_head;
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
attribute that accelerates the lookup of the FDE associated
with the subprogram. This variable holds the table index of the FDE
associated with the current function (body) definition. */
static unsigned current_funcdef_fde;
+#endif
-struct ht *debug_str_hash;
-
-struct indirect_string_node
+struct indirect_string_node GTY(())
{
- struct ht_identifier id;
+ const char *str;
unsigned int refcount;
unsigned int form;
char *label;
};
+static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
+
+static GTY(()) int dw2_string_counter;
+static GTY(()) unsigned long dwarf2out_cfi_label_num;
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
/* Forward declarations for functions defined in this file. */
-static char *stripattributes PARAMS ((const char *));
-static const char *dwarf_cfi_name PARAMS ((unsigned));
-static dw_cfi_ref new_cfi PARAMS ((void));
-static void add_cfi PARAMS ((dw_cfi_ref *, dw_cfi_ref));
-static void add_fde_cfi PARAMS ((const char *, dw_cfi_ref));
-static void lookup_cfa_1 PARAMS ((dw_cfi_ref,
- dw_cfa_location *));
-static void lookup_cfa PARAMS ((dw_cfa_location *));
-static void reg_save PARAMS ((const char *, unsigned,
- unsigned, long));
-static void initial_return_save PARAMS ((rtx));
-static long stack_adjust_offset PARAMS ((rtx));
-static void output_cfi PARAMS ((dw_cfi_ref, dw_fde_ref, int));
-static void output_call_frame_info PARAMS ((int));
-static void dwarf2out_stack_adjust PARAMS ((rtx));
-static void queue_reg_save PARAMS ((const char *, rtx, long));
-static void flush_queued_reg_saves PARAMS ((void));
-static bool clobbers_queued_reg_save PARAMS ((rtx));
-static void dwarf2out_frame_debug_expr PARAMS ((rtx, const char *));
+static char *stripattributes (const char *);
+static const char *dwarf_cfi_name (unsigned);
+static dw_cfi_ref new_cfi (void);
+static void add_cfi (dw_cfi_ref *, dw_cfi_ref);
+static void add_fde_cfi (const char *, dw_cfi_ref);
+static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *);
+static void lookup_cfa (dw_cfa_location *);
+static void reg_save (const char *, unsigned, unsigned, HOST_WIDE_INT);
+static void initial_return_save (rtx);
+static HOST_WIDE_INT stack_adjust_offset (rtx);
+static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
+static void output_call_frame_info (int);
+static void dwarf2out_stack_adjust (rtx);
+static void queue_reg_save (const char *, rtx, HOST_WIDE_INT);
+static void flush_queued_reg_saves (void);
+static bool clobbers_queued_reg_save (rtx);
+static void dwarf2out_frame_debug_expr (rtx, const char *);
/* Support for complex CFA locations. */
-static void output_cfa_loc PARAMS ((dw_cfi_ref));
-static void get_cfa_from_loc_descr PARAMS ((dw_cfa_location *,
- struct dw_loc_descr_struct *));
+static void output_cfa_loc (dw_cfi_ref);
+static void get_cfa_from_loc_descr (dw_cfa_location *,
+ struct dw_loc_descr_struct *);
static struct dw_loc_descr_struct *build_cfa_loc
- PARAMS ((dw_cfa_location *));
-static void def_cfa_1 PARAMS ((const char *,
- dw_cfa_location *));
+ (dw_cfa_location *);
+static void def_cfa_1 (const char *, dw_cfa_location *);
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
registers. */
#ifndef DWARF_FRAME_RETURN_COLUMN
#ifdef PC_REGNUM
-#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM)
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM)
#else
-#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGISTERS
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGISTERS
#endif
#endif
/* Hook used by __throw. */
rtx
-expand_builtin_dwarf_fp_regnum ()
+expand_builtin_dwarf_sp_column (void)
{
- return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
+ return GEN_INT (DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
}
/* Return a pointer to a copy of the section string name S with all
attributes stripped off, and an asterisk prepended (for assemble_name). */
static inline char *
-stripattributes (s)
- const char *s;
+stripattributes (const char *s)
{
char *stripped = xmalloc (strlen (s) + 2);
char *p = stripped;
/* Generate code to initialize the register size table. */
void
-expand_builtin_init_dwarf_reg_sizes (address)
- tree address;
+expand_builtin_init_dwarf_reg_sizes (tree address)
{
int i;
enum machine_mode mode = TYPE_MODE (char_type_node);
rtx addr = expand_expr (address, NULL_RTX, VOIDmode, 0);
rtx mem = gen_rtx_MEM (BLKmode, addr);
+ bool wrote_return_column = false;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (DWARF_FRAME_REGNUM (i) < DWARF_FRAME_REGISTERS)
{
HOST_WIDE_INT offset = DWARF_FRAME_REGNUM (i) * GET_MODE_SIZE (mode);
- HOST_WIDE_INT size = GET_MODE_SIZE (reg_raw_mode[i]);
+ enum machine_mode save_mode = reg_raw_mode[i];
+ HOST_WIDE_INT size;
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
+ save_mode = choose_hard_reg_mode (i, 1, true);
+ if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
+ {
+ if (save_mode == VOIDmode)
+ continue;
+ wrote_return_column = true;
+ }
+ size = GET_MODE_SIZE (save_mode);
if (offset < 0)
continue;
emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
}
+
+#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
+ if (! wrote_return_column)
+ abort ();
+ i = DWARF_ALT_FRAME_RETURN_COLUMN;
+ wrote_return_column = false;
+#else
+ i = DWARF_FRAME_RETURN_COLUMN;
+#endif
+
+ if (! wrote_return_column)
+ {
+ enum machine_mode save_mode = Pmode;
+ HOST_WIDE_INT offset = i * GET_MODE_SIZE (mode);
+ HOST_WIDE_INT size = GET_MODE_SIZE (save_mode);
+ emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
+ }
}
/* Convert a DWARF call frame info. operation to its string name */
static const char *
-dwarf_cfi_name (cfi_opc)
- unsigned cfi_opc;
+dwarf_cfi_name (unsigned int cfi_opc)
{
switch (cfi_opc)
{
/* Return a pointer to a newly allocated Call Frame Instruction. */
static inline dw_cfi_ref
-new_cfi ()
+new_cfi (void)
{
- dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node));
+ dw_cfi_ref cfi = ggc_alloc (sizeof (dw_cfi_node));
cfi->dw_cfi_next = NULL;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
/* Add a Call Frame Instruction to list of instructions. */
static inline void
-add_cfi (list_head, cfi)
- dw_cfi_ref *list_head;
- dw_cfi_ref cfi;
+add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi)
{
dw_cfi_ref *p;
/* Generate a new label for the CFI info to refer to. */
char *
-dwarf2out_cfi_label ()
+dwarf2out_cfi_label (void)
{
static char label[20];
- static unsigned long label_num = 0;
- ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++);
+ ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
ASM_OUTPUT_LABEL (asm_out_file, label);
return label;
}
or to the CIE if LABEL is NULL. */
static void
-add_fde_cfi (label, cfi)
- const char *label;
- dw_cfi_ref cfi;
+add_fde_cfi (const char *label, dw_cfi_ref cfi)
{
if (label)
{
/* Subroutine of lookup_cfa. */
static inline void
-lookup_cfa_1 (cfi, loc)
- dw_cfi_ref cfi;
- dw_cfa_location *loc;
+lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc)
{
switch (cfi->dw_cfi_opc)
{
/* Find the previous value for the CFA. */
static void
-lookup_cfa (loc)
- dw_cfa_location *loc;
+lookup_cfa (dw_cfa_location *loc)
{
dw_cfi_ref cfi;
static dw_cfa_location cfa_store;
/* The running total of the size of arguments pushed onto the stack. */
-static long args_size;
+static HOST_WIDE_INT args_size;
/* The last args_size we actually output. */
-static long old_args_size;
+static HOST_WIDE_INT old_args_size;
/* Entry point to update the canonical frame address (CFA).
LABEL is passed to add_fde_cfi. The value of CFA is now to be
calculated from REG+OFFSET. */
void
-dwarf2out_def_cfa (label, reg, offset)
- const char *label;
- unsigned reg;
- long offset;
+dwarf2out_def_cfa (const char *label, unsigned int reg, HOST_WIDE_INT offset)
{
dw_cfa_location loc;
loc.indirect = 0;
the dw_cfa_location structure. */
static void
-def_cfa_1 (label, loc_p)
- const char *label;
- dw_cfa_location *loc_p;
+def_cfa_1 (const char *label, dw_cfa_location *loc_p)
{
dw_cfi_ref cfi;
dw_cfa_location old_cfa, loc;
otherwise it is saved in SREG. */
static void
-reg_save (label, reg, sreg, offset)
- const char *label;
- unsigned reg;
- unsigned sreg;
- long offset;
+reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
{
dw_cfi_ref cfi = new_cfi ();
DWARF_CIE_DATA_ALIGNMENT, there is either a bug in the
definition of DWARF_CIE_DATA_ALIGNMENT, or a bug in the machine
description. */
- long check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
+ HOST_WIDE_INT check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
if (check_offset * DWARF_CIE_DATA_ALIGNMENT != offset)
abort ();
assuming 0(cfa)) and what registers are in the window. */
void
-dwarf2out_window_save (label)
- const char *label;
+dwarf2out_window_save (const char *label)
{
dw_cfi_ref cfi = new_cfi ();
pushed onto the stack. */
void
-dwarf2out_args_size (label, size)
- const char *label;
- long size;
+dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
{
dw_cfi_ref cfi;
number. LABEL and OFFSET are passed to reg_save. */
void
-dwarf2out_reg_save (label, reg, offset)
- const char *label;
- unsigned reg;
- long offset;
+dwarf2out_reg_save (const char *label, unsigned int reg, HOST_WIDE_INT offset)
{
reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
}
LABEL and OFFSET are passed to reg_save. */
void
-dwarf2out_return_save (label, offset)
- const char *label;
- long offset;
+dwarf2out_return_save (const char *label, HOST_WIDE_INT offset)
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset);
}
LABEL and SREG are passed to reg_save. */
void
-dwarf2out_return_reg (label, sreg)
- const char *label;
- unsigned sreg;
+dwarf2out_return_reg (const char *label, unsigned int sreg)
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0);
}
INCOMING_RETURN_ADDR_RTX. */
static void
-initial_return_save (rtl)
- rtx rtl;
+initial_return_save (rtx rtl)
{
unsigned int reg = (unsigned int) -1;
HOST_WIDE_INT offset = 0;
/* Given a SET, calculate the amount of stack adjustment it
contains. */
-static long
-stack_adjust_offset (pattern)
- rtx pattern;
+static HOST_WIDE_INT
+stack_adjust_offset (rtx pattern)
{
rtx src = SET_SRC (pattern);
rtx dest = SET_DEST (pattern);
much extra space it needs to pop off the stack. */
static void
-dwarf2out_stack_adjust (insn)
- rtx insn;
+dwarf2out_stack_adjust (rtx insn)
{
HOST_WIDE_INT offset;
const char *label;
dwarf2out_args_size (label, args_size);
}
+#endif
+
/* We delay emitting a register save until either (a) we reach the end
of the prologue or (b) the register is clobbered. This clusters
register saves so that there are fewer pc advances. */
-struct queued_reg_save
+struct queued_reg_save GTY(())
{
struct queued_reg_save *next;
rtx reg;
- long cfa_offset;
+ HOST_WIDE_INT cfa_offset;
};
-static struct queued_reg_save *queued_reg_saves;
+static GTY(()) struct queued_reg_save *queued_reg_saves;
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
static const char *last_reg_save_label;
static void
-queue_reg_save (label, reg, offset)
- const char *label;
- rtx reg;
- long offset;
+queue_reg_save (const char *label, rtx reg, HOST_WIDE_INT offset)
{
- struct queued_reg_save *q = (struct queued_reg_save *) xmalloc (sizeof (*q));
+ struct queued_reg_save *q = ggc_alloc (sizeof (*q));
q->next = queued_reg_saves;
q->reg = reg;
}
static void
-flush_queued_reg_saves ()
+flush_queued_reg_saves (void)
{
struct queued_reg_save *q, *next;
{
dwarf2out_reg_save (last_reg_save_label, REGNO (q->reg), q->cfa_offset);
next = q->next;
- free (q);
}
queued_reg_saves = NULL;
}
static bool
-clobbers_queued_reg_save (insn)
- rtx insn;
+clobbers_queued_reg_save (rtx insn)
{
struct queued_reg_save *q;
had better be the one we think we're using for this purpose.
Except: If the register being saved is the CFA register, and the
- offset is non-zero, we are saving the CFA, so we assume we have to
+ offset is nonzero, we are saving the CFA, so we assume we have to
use DW_CFA_def_cfa_expression. If the offset is 0, we assume that
the intent is to save the value of SP from the previous frame.
to track stores to the stack via fp or a temp reg.
Rules 1- 4: Setting a register's value to cfa.reg or an expression
- with cfa.reg as the first operand changes the cfa.reg and its
+ with cfa.reg as the first operand changes the cfa.reg and its
cfa.offset. Rule 1 and 4 also set cfa_temp.reg and
cfa_temp.offset.
Rule 1:
(set <reg1> <reg2>:cfa.reg)
effects: cfa.reg = <reg1>
- cfa.offset unchanged
+ cfa.offset unchanged
cfa_temp.reg = <reg1>
cfa_temp.offset = cfa.offset
(set sp ({minus,plus,losum} {sp,fp}:cfa.reg
{<const_int>,<reg>:cfa_temp.reg}))
effects: cfa.reg = sp if fp used
- cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
+ cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
if cfa_store.reg==sp
Rule 3:
(set fp ({minus,plus,losum} <reg>:cfa.reg <const_int>))
effects: cfa.reg = fp
- cfa_offset += +/- <const_int>
+ cfa_offset += +/- <const_int>
Rule 4:
(set <reg1> ({plus,losum} <reg2>:cfa.reg <const_int>))
constraints: <reg1> != fp
- <reg1> != sp
+ <reg1> != sp
effects: cfa.reg = <reg1>
cfa_temp.reg = <reg1>
cfa_temp.offset = cfa.offset
Rule 5:
(set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
constraints: <reg1> != fp
- <reg1> != sp
+ <reg1> != sp
effects: cfa_store.reg = <reg1>
- cfa_store.offset = cfa.offset - cfa_temp.offset
+ cfa_store.offset = cfa.offset - cfa_temp.offset
Rule 6:
(set <reg> <const_int>)
effects: cfa_temp.reg = <reg>
- cfa_temp.offset = <const_int>
+ cfa_temp.offset = <const_int>
Rule 7:
(set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
Rule 9:
(set <reg> (lo_sum <exp> <const_int>))
effects: cfa_temp.reg = <reg>
- cfa_temp.offset = <const_int>
+ cfa_temp.offset = <const_int>
Rule 10:
(set (mem (pre_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
cfa_temp.offset -= mode_size(mem) */
static void
-dwarf2out_frame_debug_expr (expr, label)
- rtx expr;
- const char *label;
+dwarf2out_frame_debug_expr (rtx expr, const char *label)
{
rtx src, dest;
HOST_WIDE_INT offset;
case REG:
/* Rule 1 */
/* Update the CFA rule wrt SP or FP. Make sure src is
- relative to the current CFA register. */
+ relative to the current CFA register. */
switch (GET_CODE (src))
{
/* Setting FP from SP. */
else
{
/* Otherwise, we'll need to look in the stack to
- calculate the CFA. */
+ calculate the CFA. */
rtx x = XEXP (dest, 0);
if (GET_CODE (x) != REG)
register to the stack. If INSN is NULL_RTX, initialize our state. */
void
-dwarf2out_frame_debug (insn)
- rtx insn;
+dwarf2out_frame_debug (rtx insn)
{
const char *label;
rtx src;
dwarf2out_frame_debug_expr (insn, label);
}
+#endif
+
+/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */
+static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc
+ (enum dwarf_call_frame_info cfi);
+
+static enum dw_cfi_oprnd_type
+dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
+{
+ switch (cfi)
+ {
+ case DW_CFA_nop:
+ case DW_CFA_GNU_window_save:
+ return dw_cfi_oprnd_unused;
+
+ case DW_CFA_set_loc:
+ case DW_CFA_advance_loc1:
+ case DW_CFA_advance_loc2:
+ case DW_CFA_advance_loc4:
+ case DW_CFA_MIPS_advance_loc8:
+ return dw_cfi_oprnd_addr;
+
+ case DW_CFA_offset:
+ case DW_CFA_offset_extended:
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_register:
+ return dw_cfi_oprnd_reg_num;
+
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_GNU_args_size:
+ case DW_CFA_def_cfa_offset_sf:
+ return dw_cfi_oprnd_offset;
+
+ case DW_CFA_def_cfa_expression:
+ case DW_CFA_expression:
+ return dw_cfi_oprnd_loc;
+
+ default:
+ abort ();
+ }
+}
+
+/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */
+static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc
+ (enum dwarf_call_frame_info cfi);
+
+static enum dw_cfi_oprnd_type
+dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
+{
+ switch (cfi)
+ {
+ case DW_CFA_def_cfa:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_offset:
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_offset_extended:
+ return dw_cfi_oprnd_offset;
+
+ case DW_CFA_register:
+ return dw_cfi_oprnd_reg_num;
+
+ default:
+ return dw_cfi_oprnd_unused;
+ }
+}
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
/* Output a Call Frame Information opcode and its operand(s). */
static void
-output_cfi (cfi, fde, for_eh)
- dw_cfi_ref cfi;
- dw_fde_ref fde;
- int for_eh;
+output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
{
if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
dw2_asm_output_data (1, (cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
- "DW_CFA_advance_loc 0x%lx",
+ "DW_CFA_advance_loc " HOST_WIDE_INT_PRINT_HEX,
cfi->dw_cfi_oprnd1.dw_cfi_offset);
else if (cfi->dw_cfi_opc == DW_CFA_offset)
{
location of saved registers. */
static void
-output_call_frame_info (for_eh)
- int for_eh;
+output_call_frame_info (int for_eh)
{
unsigned int i;
dw_fde_ref fde;
dw_cfi_ref cfi;
char l1[20], l2[20], section_start_label[20];
- int any_lsda_needed = 0;
+ bool any_lsda_needed = false;
char augmentation[6];
int augmentation_size;
int fde_encoding = DW_EH_PE_absptr;
if (fde_table_in_use == 0)
return;
- /* If we don't have any functions we'll want to unwind out of, don't emit any
- EH unwind information. */
+ /* If we don't have any functions we'll want to unwind out of, don't
+ emit any EH unwind information. Note that if exceptions aren't
+ enabled, we won't have collected nothrow information, and if we
+ asked for asynchronous tables, we always want this info. */
if (for_eh)
{
- int any_eh_needed = flag_asynchronous_unwind_tables;
+ bool any_eh_needed = !flag_exceptions || flag_asynchronous_unwind_tables;
for (i = 0; i < fde_table_in_use; i++)
if (fde_table[i].uses_eh_lsda)
- any_eh_needed = any_lsda_needed = 1;
- else if (! fde_table[i].nothrow)
- any_eh_needed = 1;
+ any_eh_needed = any_lsda_needed = true;
+ else if (! fde_table[i].nothrow
+ && ! fde_table[i].all_throwers_are_sibcalls)
+ any_eh_needed = true;
if (! any_eh_needed)
return;
/* Augmentation:
z Indicates that a uleb128 is present to size the
- augmentation section.
+ augmentation section.
L Indicates the encoding (and thus presence) of
an LSDA pointer in the FDE augmentation.
R Indicates a non-default pointer encoding for
fde = &fde_table[i];
/* Don't emit EH unwind info for leaf functions that don't need it. */
- if (!flag_asynchronous_unwind_tables && for_eh && fde->nothrow
- && ! fde->uses_eh_lsda)
+ if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
+ && (fde->nothrow || fde->all_throwers_are_sibcalls)
+ && !fde->uses_eh_lsda)
continue;
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, FDE_LABEL, for_eh + i * 2);
+ (*targetm.asm_out.internal_label) (asm_out_file, FDE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
dw2_asm_output_data_uleb128 (size, "Augmentation size");
if (fde->uses_eh_lsda)
- {
- ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
+ {
+ ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
fde->funcdef_number);
- dw2_asm_output_encoded_addr_rtx (
+ dw2_asm_output_encoded_addr_rtx (
lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
- "Language Specific Data Area");
- }
+ "Language Specific Data Area");
+ }
else
{
if (lsda_encoding == DW_EH_PE_aligned)
/* Pad the FDE out to an address sized boundary. */
ASM_OUTPUT_ALIGN (asm_out_file,
- floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
+ floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
ASM_OUTPUT_LABEL (asm_out_file, l2);
}
-#ifndef EH_FRAME_SECTION_NAME
- if (for_eh)
+ if (for_eh && targetm.terminate_dw2_eh_frame_info)
dw2_asm_output_data (4, 0, "End of Table");
-#endif
#ifdef MIPS_DEBUGGING_INFO
/* Work around Irix 6 assembler bug whereby labels at the end of a section
get a value of 0. Putting .align 0 after the label fixes it. */
the prologue. */
void
-dwarf2out_begin_prologue (line, file)
- unsigned int line ATTRIBUTE_UNUSED;
- const char *file ATTRIBUTE_UNUSED;
+dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file ATTRIBUTE_UNUSED)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
dw_fde_ref fde;
if (fde_table_in_use == fde_table_allocated)
{
fde_table_allocated += FDE_TABLE_INCREMENT;
- fde_table
- = (dw_fde_ref) xrealloc (fde_table,
- fde_table_allocated * sizeof (dw_fde_node));
+ fde_table = ggc_realloc (fde_table,
+ fde_table_allocated * sizeof (dw_fde_node));
+ memset (fde_table + fde_table_in_use, 0,
+ FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
}
/* Record the FDE associated with this function. */
fde->funcdef_number = current_function_funcdef_no;
fde->nothrow = current_function_nothrow;
fde->uses_eh_lsda = cfun->uses_eh_lsda;
+ fde->all_throwers_are_sibcalls = cfun->all_throwers_are_sibcalls;
args_size = old_args_size = 0;
been generated. */
void
-dwarf2out_end_epilogue (line, file)
- unsigned int line ATTRIBUTE_UNUSED;
- const char *file ATTRIBUTE_UNUSED;
+dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file ATTRIBUTE_UNUSED)
{
dw_fde_ref fde;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
}
void
-dwarf2out_frame_init ()
+dwarf2out_frame_init (void)
{
/* Allocate the initial hunk of the fde_table. */
- fde_table = (dw_fde_ref) xcalloc (FDE_TABLE_INCREMENT, sizeof (dw_fde_node));
+ fde_table = ggc_alloc_cleared (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
fde_table_allocated = FDE_TABLE_INCREMENT;
fde_table_in_use = 0;
}
void
-dwarf2out_frame_finish ()
+dwarf2out_frame_finish (void)
{
/* Output call frame information. */
if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
output_call_frame_info (1);
}
+#endif
\f
/* And now, the subset of the debugging information support code necessary
for emitting location expressions. */
+/* We need some way to distinguish DW_OP_addr with a direct symbol
+ relocation from DW_OP_addr with a dtp-relative symbol relocation. */
+#define INTERNAL_DW_OP_tls_addr (0x100 + DW_OP_addr)
+
+
typedef struct dw_val_struct *dw_val_ref;
typedef struct die_struct *dw_die_ref;
typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
can take on several forms. The forms that are used in this
implementation are listed below. */
-typedef enum
+enum dw_val_class
{
dw_val_class_addr,
dw_val_class_offset,
dw_val_class_lbl_id,
dw_val_class_lbl_offset,
dw_val_class_str
-}
-dw_val_class;
+};
/* Describe a double word constant value. */
/* ??? Every instance of long_long in the code really means CONST_DOUBLE. */
-typedef struct dw_long_long_struct
+typedef struct dw_long_long_struct GTY(())
{
unsigned long hi;
unsigned long low;
/* Describe a floating point constant value. */
-typedef struct dw_fp_struct
+typedef struct dw_fp_struct GTY(())
{
- long *array;
+ long * GTY((length ("%h.length"))) array;
unsigned length;
}
dw_float_const;
/* The dw_val_node describes an attribute's value, as it is
represented internally. */
-typedef struct dw_val_struct
+typedef struct dw_val_struct GTY(())
{
- dw_val_class val_class;
- union
+ enum dw_val_class val_class;
+ union dw_val_struct_union
{
- rtx val_addr;
- long unsigned val_offset;
- dw_loc_list_ref val_loc_list;
- dw_loc_descr_ref val_loc;
- long int val_int;
- long unsigned val_unsigned;
- dw_long_long_const val_long_long;
- dw_float_const val_float;
- struct
+ rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
+ unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
+ dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
+ dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
+ HOST_WIDE_INT GTY ((default (""))) val_int;
+ unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
+ dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
+ dw_float_const GTY ((tag ("dw_val_class_float"))) val_float;
+ struct dw_val_die_union
{
dw_die_ref die;
int external;
- } val_die_ref;
- unsigned val_fde_index;
- struct indirect_string_node *val_str;
- char *val_lbl_id;
- unsigned char val_flag;
+ } GTY ((tag ("dw_val_class_die_ref"))) val_die_ref;
+ unsigned GTY ((tag ("dw_val_class_fde_ref"))) val_fde_index;
+ struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str;
+ char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
+ unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
}
- v;
+ GTY ((desc ("%1.val_class"))) v;
}
dw_val_node;
/* Locations in memory are described using a sequence of stack machine
operations. */
-typedef struct dw_loc_descr_struct
+typedef struct dw_loc_descr_struct GTY(())
{
dw_loc_descr_ref dw_loc_next;
enum dwarf_location_atom dw_loc_opc;
/* Location lists are ranges + location descriptions for that range,
so you can track variables that are in different places over
their entire life. */
-typedef struct dw_loc_list_struct
+typedef struct dw_loc_list_struct GTY(())
{
dw_loc_list_ref dw_loc_next;
const char *begin; /* Label for begin address of range */
dw_loc_descr_ref expr;
} dw_loc_list_node;
-static const char *dwarf_stack_op_name PARAMS ((unsigned));
-static dw_loc_descr_ref new_loc_descr PARAMS ((enum dwarf_location_atom,
- unsigned long,
- unsigned long));
-static void add_loc_descr PARAMS ((dw_loc_descr_ref *,
- dw_loc_descr_ref));
-static unsigned long size_of_loc_descr PARAMS ((dw_loc_descr_ref));
-static unsigned long size_of_locs PARAMS ((dw_loc_descr_ref));
-static void output_loc_operands PARAMS ((dw_loc_descr_ref));
-static void output_loc_sequence PARAMS ((dw_loc_descr_ref));
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+static const char *dwarf_stack_op_name (unsigned);
+static dw_loc_descr_ref new_loc_descr (enum dwarf_location_atom,
+ unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
+static void add_loc_descr (dw_loc_descr_ref *, dw_loc_descr_ref);
+static unsigned long size_of_loc_descr (dw_loc_descr_ref);
+static unsigned long size_of_locs (dw_loc_descr_ref);
+static void output_loc_operands (dw_loc_descr_ref);
+static void output_loc_sequence (dw_loc_descr_ref);
/* Convert a DWARF stack opcode into its string name. */
static const char *
-dwarf_stack_op_name (op)
- unsigned op;
+dwarf_stack_op_name (unsigned int op)
{
switch (op)
{
case DW_OP_addr:
+ case INTERNAL_DW_OP_tls_addr:
return "DW_OP_addr";
case DW_OP_deref:
return "DW_OP_deref";
return "DW_OP_xderef_size";
case DW_OP_nop:
return "DW_OP_nop";
+ case DW_OP_push_object_address:
+ return "DW_OP_push_object_address";
+ case DW_OP_call2:
+ return "DW_OP_call2";
+ case DW_OP_call4:
+ return "DW_OP_call4";
+ case DW_OP_call_ref:
+ return "DW_OP_call_ref";
+ case DW_OP_GNU_push_tls_address:
+ return "DW_OP_GNU_push_tls_address";
default:
return "OP_<unknown>";
}
together to form more complicated location (address) descriptions. */
static inline dw_loc_descr_ref
-new_loc_descr (op, oprnd1, oprnd2)
- enum dwarf_location_atom op;
- unsigned long oprnd1;
- unsigned long oprnd2;
+new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
+ unsigned HOST_WIDE_INT oprnd2)
{
- /* Use xcalloc here so we clear out all of the long_long constant in
- the union. */
- dw_loc_descr_ref descr
- = (dw_loc_descr_ref) xcalloc (1, sizeof (dw_loc_descr_node));
+ dw_loc_descr_ref descr = ggc_alloc_cleared (sizeof (dw_loc_descr_node));
descr->dw_loc_opc = op;
descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
/* Add a location description term to a location description expression. */
static inline void
-add_loc_descr (list_head, descr)
- dw_loc_descr_ref *list_head;
- dw_loc_descr_ref descr;
+add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
{
dw_loc_descr_ref *d;
/* Return the size of a location descriptor. */
static unsigned long
-size_of_loc_descr (loc)
- dw_loc_descr_ref loc;
+size_of_loc_descr (dw_loc_descr_ref loc)
{
unsigned long size = 1;
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
+ case INTERNAL_DW_OP_tls_addr:
size += DWARF2_ADDR_SIZE;
break;
case DW_OP_const1u:
case DW_OP_xderef_size:
size += 1;
break;
+ case DW_OP_call2:
+ size += 2;
+ break;
+ case DW_OP_call4:
+ size += 4;
+ break;
+ case DW_OP_call_ref:
+ size += DWARF2_ADDR_SIZE;
+ break;
default:
break;
}
/* Return the size of a series of location descriptors. */
static unsigned long
-size_of_locs (loc)
- dw_loc_descr_ref loc;
+size_of_locs (dw_loc_descr_ref loc)
{
unsigned long size;
/* Output location description stack opcode's operands (if any). */
static void
-output_loc_operands (loc)
- dw_loc_descr_ref loc;
+output_loc_operands (dw_loc_descr_ref loc)
{
dw_val_ref val1 = &loc->dw_loc_oprnd1;
dw_val_ref val2 = &loc->dw_loc_oprnd2;
case DW_OP_skip:
case DW_OP_bra:
/* We currently don't make any attempt to make sure these are
- aligned properly like we do for the main unwind info, so
- don't support emitting things larger than a byte if we're
- only doing unwinding. */
+ aligned properly like we do for the main unwind info, so
+ don't support emitting things larger than a byte if we're
+ only doing unwinding. */
abort ();
#endif
case DW_OP_const1u:
case DW_OP_xderef_size:
dw2_asm_output_data (1, val1->v.val_int, NULL);
break;
+
+ case INTERNAL_DW_OP_tls_addr:
+#ifdef ASM_OUTPUT_DWARF_DTPREL
+ ASM_OUTPUT_DWARF_DTPREL (asm_out_file, DWARF2_ADDR_SIZE,
+ val1->v.val_addr);
+ fputc ('\n', asm_out_file);
+#else
+ abort ();
+#endif
+ break;
+
default:
/* Other codes have no operands. */
break;
/* Output a sequence of location operations. */
static void
-output_loc_sequence (loc)
- dw_loc_descr_ref loc;
+output_loc_sequence (dw_loc_descr_ref loc)
{
for (; loc != NULL; loc = loc->dw_loc_next)
{
description based on a cfi entry with a complex address. */
static void
-output_cfa_loc (cfi)
- dw_cfi_ref cfi;
+output_cfa_loc (dw_cfi_ref cfi)
{
dw_loc_descr_ref loc;
unsigned long size;
a dw_cfa_location. */
static struct dw_loc_descr_struct *
-build_cfa_loc (cfa)
- dw_cfa_location *cfa;
+build_cfa_loc (dw_cfa_location *cfa)
{
struct dw_loc_descr_struct *head, *tmp;
descriptor sequence. */
static void
-get_cfa_from_loc_descr (cfa, loc)
- dw_cfa_location *cfa;
- struct dw_loc_descr_struct *loc;
+get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_struct *loc)
{
struct dw_loc_descr_struct *ptr;
cfa->offset = 0;
#ifdef DWARF2_DEBUGGING_INFO
/* .debug_str support. */
-static hashnode indirect_string_alloc PARAMS ((hash_table *));
-static int output_indirect_string PARAMS ((struct cpp_reader *,
- hashnode, const PTR));
-
-
-static void dwarf2out_init PARAMS ((const char *));
-static void dwarf2out_finish PARAMS ((const char *));
-static void dwarf2out_define PARAMS ((unsigned int, const char *));
-static void dwarf2out_undef PARAMS ((unsigned int, const char *));
-static void dwarf2out_start_source_file PARAMS ((unsigned, const char *));
-static void dwarf2out_end_source_file PARAMS ((unsigned));
-static void dwarf2out_begin_block PARAMS ((unsigned, unsigned));
-static void dwarf2out_end_block PARAMS ((unsigned, unsigned));
-static bool dwarf2out_ignore_block PARAMS ((tree));
-static void dwarf2out_global_decl PARAMS ((tree));
-static void dwarf2out_abstract_function PARAMS ((tree));
+static int output_indirect_string (void **, void *);
+
+static void dwarf2out_init (const char *);
+static void dwarf2out_finish (const char *);
+static void dwarf2out_define (unsigned int, const char *);
+static void dwarf2out_undef (unsigned int, const char *);
+static void dwarf2out_start_source_file (unsigned, const char *);
+static void dwarf2out_end_source_file (unsigned);
+static void dwarf2out_begin_block (unsigned, unsigned);
+static void dwarf2out_end_block (unsigned, unsigned);
+static bool dwarf2out_ignore_block (tree);
+static void dwarf2out_global_decl (tree);
+static void dwarf2out_abstract_function (tree);
/* The debug hooks structure. */
emitting the abstract description of inline functions until
something tries to reference them. */
dwarf2out_abstract_function, /* outlining_inline_function */
- debug_nothing_rtx /* label */
+ debug_nothing_rtx, /* label */
+ debug_nothing_int /* handle_pch */
};
+#endif
\f
/* NOTE: In the comments in this file, many references are made to
"Debugging Information Entries". This term is abbreviated as `DIE'
entry. The label gives the PC value associated with
the line number entry. */
-typedef struct dw_line_info_struct
+typedef struct dw_line_info_struct GTY(())
{
unsigned long dw_file_num;
unsigned long dw_line_num;
/* Line information for functions in separate sections; each one gets its
own sequence. */
-typedef struct dw_separate_line_info_struct
+typedef struct dw_separate_line_info_struct GTY(())
{
unsigned long dw_file_num;
unsigned long dw_line_num;
a link to the next attribute in the chain, and an attribute value.
Attributes are typically linked below the DIE they modify. */
-typedef struct dw_attr_struct
+typedef struct dw_attr_struct GTY(())
{
enum dwarf_attribute dw_attr;
dw_attr_ref dw_attr_next;
/* The Debugging Information Entry (DIE) structure */
-typedef struct die_struct
+typedef struct die_struct GTY(())
{
enum dwarf_tag die_tag;
char *die_symbol;
/* The pubname structure */
-typedef struct pubname_struct
+typedef struct pubname_struct GTY(())
{
dw_die_ref die;
char *name;
}
pubname_entry;
-struct dw_ranges_struct
+struct dw_ranges_struct GTY(())
{
int block_num;
};
/* The limbo die list structure. */
-typedef struct limbo_die_struct
+typedef struct limbo_die_struct GTY(())
{
dw_die_ref die;
tree created_for;
#define ASM_COMMENT_START ";#"
#endif
-/* Define a macro which returns non-zero for a TYPE_DECL which was
+/* Define a macro which returns nonzero for a TYPE_DECL which was
implicitly generated for a tagged type.
Note that unlike the gcc front end (which generates a NULL named
language, and compiler version. */
/* Fixed size portion of the DWARF compilation unit header. */
-#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3)
+#define DWARF_COMPILE_UNIT_HEADER_SIZE \
+ (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
/* Fixed size portion of public names info. */
#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
/* Fixed size portion of the address range info. */
#define DWARF_ARANGES_HEADER_SIZE \
- (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, DWARF2_ADDR_SIZE * 2) \
- - DWARF_OFFSET_SIZE)
+ (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
+ DWARF2_ADDR_SIZE * 2) \
+ - DWARF_INITIAL_LENGTH_SIZE)
/* Size of padding portion in the address range info. It must be
aligned to twice the pointer size. */
#define DWARF_ARANGES_PAD_SIZE \
- (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, DWARF2_ADDR_SIZE * 2) \
- - (2 * DWARF_OFFSET_SIZE + 4))
+ (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
+ DWARF2_ADDR_SIZE * 2) \
+ - (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4))
/* Use assembler line directives if available. */
#ifndef DWARF2_ASM_LINE_DEBUG_INFO
is not made available by the GCC front-end. */
#define DWARF_LINE_DEFAULT_IS_STMT_START 1
+#ifdef DWARF2_DEBUGGING_INFO
/* This location is used by calc_die_sizes() to keep track
the offset of each DIE within the .debug_info section. */
static unsigned long next_die_offset;
+#endif
/* Record the root of the DIE's built for the current compilation unit. */
-static dw_die_ref comp_unit_die;
+static GTY(()) dw_die_ref comp_unit_die;
/* A list of DIEs with a NULL parent waiting to be relocated. */
-static limbo_die_node *limbo_die_list = 0;
-
-/* Structure used by lookup_filename to manage sets of filenames. */
-struct file_table
-{
- char **table;
- unsigned allocated;
- unsigned in_use;
- unsigned last_lookup_index;
-};
-
-/* Size (in elements) of increments by which we may expand the filename
- table. */
-#define FILE_TABLE_INCREMENT 64
+static GTY(()) limbo_die_node *limbo_die_list;
/* Filenames referenced by this compilation unit. */
-static struct file_table file_table;
-
-/* Local pointer to the name of the main input file. Initialized in
- dwarf2out_init. */
-static const char *primary_filename;
+static GTY(()) varray_type file_table;
+static GTY(()) varray_type file_table_emitted;
+static GTY(()) size_t file_table_last_lookup_index;
/* A pointer to the base of a table of references to DIE's that describe
declarations. The table is indexed by DECL_UID() which is a unique
number identifying each decl. */
-static dw_die_ref *decl_die_table;
+static GTY((length ("decl_die_table_allocated"))) dw_die_ref *decl_die_table;
/* Number of elements currently allocated for the decl_die_table. */
-static unsigned decl_die_table_allocated;
+static GTY(()) unsigned decl_die_table_allocated;
/* Number of elements in decl_die_table currently in use. */
-static unsigned decl_die_table_in_use;
+static GTY(()) unsigned decl_die_table_in_use;
/* Size (in elements) of increments by which we may expand the
decl_die_table. */
/* A pointer to the base of a list of references to DIE's that
are uniquely identified by their tag, presence/absence of
children DIE's, and list of attribute/value pairs. */
-static dw_die_ref *abbrev_die_table;
+static GTY((length ("abbrev_die_table_allocated")))
+ dw_die_ref *abbrev_die_table;
/* Number of elements currently allocated for abbrev_die_table. */
-static unsigned abbrev_die_table_allocated;
+static GTY(()) unsigned abbrev_die_table_allocated;
/* Number of elements in type_die_table currently in use. */
-static unsigned abbrev_die_table_in_use;
+static GTY(()) unsigned abbrev_die_table_in_use;
/* Size (in elements) of increments by which we may expand the
abbrev_die_table. */
/* A pointer to the base of a table that contains line information
for each source code line in .text in the compilation unit. */
-static dw_line_info_ref line_info_table;
+static GTY((length ("line_info_table_allocated")))
+ dw_line_info_ref line_info_table;
/* Number of elements currently allocated for line_info_table. */
-static unsigned line_info_table_allocated;
+static GTY(()) unsigned line_info_table_allocated;
-/* Number of elements in separate_line_info_table currently in use. */
-static unsigned separate_line_info_table_in_use;
+/* Number of elements in line_info_table currently in use. */
+static GTY(()) unsigned line_info_table_in_use;
/* A pointer to the base of a table that contains line information
for each source code line outside of .text in the compilation unit. */
-static dw_separate_line_info_ref separate_line_info_table;
+static GTY ((length ("separate_line_info_table_allocated")))
+ dw_separate_line_info_ref separate_line_info_table;
/* Number of elements currently allocated for separate_line_info_table. */
-static unsigned separate_line_info_table_allocated;
+static GTY(()) unsigned separate_line_info_table_allocated;
-/* Number of elements in line_info_table currently in use. */
-static unsigned line_info_table_in_use;
+/* Number of elements in separate_line_info_table currently in use. */
+static GTY(()) unsigned separate_line_info_table_in_use;
/* Size (in elements) of increments by which we may expand the
line_info_table. */
/* A pointer to the base of a table that contains a list of publicly
accessible names. */
-static pubname_ref pubname_table;
+static GTY ((length ("pubname_table_allocated"))) pubname_ref pubname_table;
/* Number of elements currently allocated for pubname_table. */
-static unsigned pubname_table_allocated;
+static GTY(()) unsigned pubname_table_allocated;
/* Number of elements in pubname_table currently in use. */
-static unsigned pubname_table_in_use;
+static GTY(()) unsigned pubname_table_in_use;
/* Size (in elements) of increments by which we may expand the
pubname_table. */
#define PUBNAME_TABLE_INCREMENT 64
/* Array of dies for which we should generate .debug_arange info. */
-static dw_die_ref *arange_table;
+static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table;
/* Number of elements currently allocated for arange_table. */
-static unsigned arange_table_allocated;
+static GTY(()) unsigned arange_table_allocated;
/* Number of elements in arange_table currently in use. */
-static unsigned arange_table_in_use;
+static GTY(()) unsigned arange_table_in_use;
/* Size (in elements) of increments by which we may expand the
arange_table. */
#define ARANGE_TABLE_INCREMENT 64
/* Array of dies for which we should generate .debug_ranges info. */
-static dw_ranges_ref ranges_table;
+static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table;
/* Number of elements currently allocated for ranges_table. */
-static unsigned ranges_table_allocated;
+static GTY(()) unsigned ranges_table_allocated;
/* Number of elements in ranges_table currently in use. */
-static unsigned ranges_table_in_use;
+static GTY(()) unsigned ranges_table_in_use;
/* Size (in elements) of increments by which we may expand the
ranges_table. */
#define RANGES_TABLE_INCREMENT 64
/* Whether we have location lists that need outputting */
-static unsigned have_location_lists;
+static GTY(()) unsigned have_location_lists;
+#ifdef DWARF2_DEBUGGING_INFO
/* Record whether the function being analyzed contains inlined functions. */
static int current_function_has_inlines;
+#endif
#if 0 && defined (MIPS_DEBUGGING_INFO)
static int comp_unit_has_inlines;
#endif
+/* Number of file tables emitted in maybe_emit_file(). */
+static GTY(()) int emitcount = 0;
+
+/* Number of internal labels generated by gen_internal_sym(). */
+static GTY(()) int label_num;
+
+#ifdef DWARF2_DEBUGGING_INFO
+
/* Forward declarations for functions defined in this file. */
-static int is_pseudo_reg PARAMS ((rtx));
-static tree type_main_variant PARAMS ((tree));
-static int is_tagged_type PARAMS ((tree));
-static const char *dwarf_tag_name PARAMS ((unsigned));
-static const char *dwarf_attr_name PARAMS ((unsigned));
-static const char *dwarf_form_name PARAMS ((unsigned));
+static int is_pseudo_reg (rtx);
+static tree type_main_variant (tree);
+static int is_tagged_type (tree);
+static const char *dwarf_tag_name (unsigned);
+static const char *dwarf_attr_name (unsigned);
+static const char *dwarf_form_name (unsigned);
#if 0
-static const char *dwarf_type_encoding_name PARAMS ((unsigned));
+static const char *dwarf_type_encoding_name (unsigned);
#endif
-static tree decl_ultimate_origin PARAMS ((tree));
-static tree block_ultimate_origin PARAMS ((tree));
-static tree decl_class_context PARAMS ((tree));
-static void add_dwarf_attr PARAMS ((dw_die_ref, dw_attr_ref));
-static inline dw_val_class AT_class PARAMS ((dw_attr_ref));
-static void add_AT_flag PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned));
-static inline unsigned AT_flag PARAMS ((dw_attr_ref));
-static void add_AT_int PARAMS ((dw_die_ref,
- enum dwarf_attribute, long));
-static inline long int AT_int PARAMS ((dw_attr_ref));
-static void add_AT_unsigned PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned long));
-static inline unsigned long AT_unsigned PARAMS ((dw_attr_ref));
-static void add_AT_long_long PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned long,
- unsigned long));
-static void add_AT_float PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned, long *));
-static void add_AT_string PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- const char *));
-static inline const char *AT_string PARAMS ((dw_attr_ref));
-static int AT_string_form PARAMS ((dw_attr_ref));
-static void add_AT_die_ref PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- dw_die_ref));
-static inline dw_die_ref AT_ref PARAMS ((dw_attr_ref));
-static inline int AT_ref_external PARAMS ((dw_attr_ref));
-static inline void set_AT_ref_external PARAMS ((dw_attr_ref, int));
-static void add_AT_fde_ref PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned));
-static void add_AT_loc PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- dw_loc_descr_ref));
-static inline dw_loc_descr_ref AT_loc PARAMS ((dw_attr_ref));
-static void add_AT_loc_list PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- dw_loc_list_ref));
-static inline dw_loc_list_ref AT_loc_list PARAMS ((dw_attr_ref));
-static void add_AT_addr PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- rtx));
-static inline rtx AT_addr PARAMS ((dw_attr_ref));
-static void add_AT_lbl_id PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- const char *));
-static void add_AT_lbl_offset PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- const char *));
-static void add_AT_offset PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned long));
-static void add_AT_range_list PARAMS ((dw_die_ref,
- enum dwarf_attribute,
- unsigned long));
-static inline const char *AT_lbl PARAMS ((dw_attr_ref));
-static dw_attr_ref get_AT PARAMS ((dw_die_ref,
- enum dwarf_attribute));
-static const char *get_AT_low_pc PARAMS ((dw_die_ref));
-static const char *get_AT_hi_pc PARAMS ((dw_die_ref));
-static const char *get_AT_string PARAMS ((dw_die_ref,
- enum dwarf_attribute));
-static int get_AT_flag PARAMS ((dw_die_ref,
- enum dwarf_attribute));
-static unsigned get_AT_unsigned PARAMS ((dw_die_ref,
- enum dwarf_attribute));
-static inline dw_die_ref get_AT_ref PARAMS ((dw_die_ref,
- enum dwarf_attribute));
-static int is_c_family PARAMS ((void));
-static int is_cxx PARAMS ((void));
-static int is_java PARAMS ((void));
-static int is_fortran PARAMS ((void));
-static void remove_AT PARAMS ((dw_die_ref,
- enum dwarf_attribute));
-static inline void free_die PARAMS ((dw_die_ref));
-static void remove_children PARAMS ((dw_die_ref));
-static void add_child_die PARAMS ((dw_die_ref, dw_die_ref));
-static dw_die_ref new_die PARAMS ((enum dwarf_tag, dw_die_ref,
- tree));
-static dw_die_ref lookup_type_die PARAMS ((tree));
-static void equate_type_number_to_die PARAMS ((tree, dw_die_ref));
-static dw_die_ref lookup_decl_die PARAMS ((tree));
-static void equate_decl_number_to_die PARAMS ((tree, dw_die_ref));
-static void print_spaces PARAMS ((FILE *));
-static void print_die PARAMS ((dw_die_ref, FILE *));
-static void print_dwarf_line_table PARAMS ((FILE *));
-static void reverse_die_lists PARAMS ((dw_die_ref));
-static void reverse_all_dies PARAMS ((dw_die_ref));
-static dw_die_ref push_new_compile_unit PARAMS ((dw_die_ref, dw_die_ref));
-static dw_die_ref pop_compile_unit PARAMS ((dw_die_ref));
-static void loc_checksum PARAMS ((dw_loc_descr_ref,
- struct md5_ctx *));
-static void attr_checksum PARAMS ((dw_attr_ref,
- struct md5_ctx *));
-static void die_checksum PARAMS ((dw_die_ref,
- struct md5_ctx *));
-static void compute_section_prefix PARAMS ((dw_die_ref));
-static int is_type_die PARAMS ((dw_die_ref));
-static int is_comdat_die PARAMS ((dw_die_ref));
-static int is_symbol_die PARAMS ((dw_die_ref));
-static void assign_symbol_names PARAMS ((dw_die_ref));
-static void break_out_includes PARAMS ((dw_die_ref));
-static void add_sibling_attributes PARAMS ((dw_die_ref));
-static void build_abbrev_table PARAMS ((dw_die_ref));
-static void output_location_lists PARAMS ((dw_die_ref));
-static int constant_size PARAMS ((long unsigned));
-static unsigned long size_of_die PARAMS ((dw_die_ref));
-static void calc_die_sizes PARAMS ((dw_die_ref));
-static void mark_dies PARAMS ((dw_die_ref));
-static void unmark_dies PARAMS ((dw_die_ref));
-static unsigned long size_of_pubnames PARAMS ((void));
-static unsigned long size_of_aranges PARAMS ((void));
-static enum dwarf_form value_format PARAMS ((dw_attr_ref));
-static void output_value_format PARAMS ((dw_attr_ref));
-static void output_abbrev_section PARAMS ((void));
-static void output_die_symbol PARAMS ((dw_die_ref));
-static void output_die PARAMS ((dw_die_ref));
-static void output_compilation_unit_header PARAMS ((void));
-static void output_comp_unit PARAMS ((dw_die_ref));
-static const char *dwarf2_name PARAMS ((tree, int));
-static void add_pubname PARAMS ((tree, dw_die_ref));
-static void output_pubnames PARAMS ((void));
-static void add_arange PARAMS ((tree, dw_die_ref));
-static void output_aranges PARAMS ((void));
-static unsigned int add_ranges PARAMS ((tree));
-static void output_ranges PARAMS ((void));
-static void output_line_info PARAMS ((void));
-static void output_file_names PARAMS ((void));
-static dw_die_ref base_type_die PARAMS ((tree));
-static tree root_type PARAMS ((tree));
-static int is_base_type PARAMS ((tree));
-static dw_die_ref modified_type_die PARAMS ((tree, int, int, dw_die_ref));
-static int type_is_enum PARAMS ((tree));
-static unsigned int reg_number PARAMS ((rtx));
-static dw_loc_descr_ref reg_loc_descriptor PARAMS ((rtx));
-static dw_loc_descr_ref int_loc_descriptor PARAMS ((HOST_WIDE_INT));
-static dw_loc_descr_ref based_loc_descr PARAMS ((unsigned, long));
-static int is_based_loc PARAMS ((rtx));
-static dw_loc_descr_ref mem_loc_descriptor PARAMS ((rtx, enum machine_mode mode));
-static dw_loc_descr_ref concat_loc_descriptor PARAMS ((rtx, rtx));
-static dw_loc_descr_ref loc_descriptor PARAMS ((rtx));
-static dw_loc_descr_ref loc_descriptor_from_tree PARAMS ((tree, int));
-static HOST_WIDE_INT ceiling PARAMS ((HOST_WIDE_INT, unsigned int));
-static tree field_type PARAMS ((tree));
-static unsigned int simple_type_align_in_bits PARAMS ((tree));
-static unsigned int simple_decl_align_in_bits PARAMS ((tree));
-static unsigned HOST_WIDE_INT simple_type_size_in_bits PARAMS ((tree));
-static HOST_WIDE_INT field_byte_offset PARAMS ((tree));
-static void add_AT_location_description PARAMS ((dw_die_ref,
- enum dwarf_attribute, rtx));
-static void add_data_member_location_attribute PARAMS ((dw_die_ref, tree));
-static void add_const_value_attribute PARAMS ((dw_die_ref, rtx));
-static rtx rtl_for_decl_location PARAMS ((tree));
-static void add_location_or_const_value_attribute PARAMS ((dw_die_ref, tree));
-static void tree_add_const_value_attribute PARAMS ((dw_die_ref, tree));
-static void add_name_attribute PARAMS ((dw_die_ref, const char *));
-static void add_bound_info PARAMS ((dw_die_ref,
- enum dwarf_attribute, tree));
-static void add_subscript_info PARAMS ((dw_die_ref, tree));
-static void add_byte_size_attribute PARAMS ((dw_die_ref, tree));
-static void add_bit_offset_attribute PARAMS ((dw_die_ref, tree));
-static void add_bit_size_attribute PARAMS ((dw_die_ref, tree));
-static void add_prototyped_attribute PARAMS ((dw_die_ref, tree));
-static void add_abstract_origin_attribute PARAMS ((dw_die_ref, tree));
-static void add_pure_or_virtual_attribute PARAMS ((dw_die_ref, tree));
-static void add_src_coords_attributes PARAMS ((dw_die_ref, tree));
-static void add_name_and_src_coords_attributes PARAMS ((dw_die_ref, tree));
-static void push_decl_scope PARAMS ((tree));
-static void pop_decl_scope PARAMS ((void));
-static dw_die_ref scope_die_for PARAMS ((tree, dw_die_ref));
-static inline int local_scope_p PARAMS ((dw_die_ref));
-static inline int class_scope_p PARAMS ((dw_die_ref));
-static void add_type_attribute PARAMS ((dw_die_ref, tree, int, int,
- dw_die_ref));
-static const char *type_tag PARAMS ((tree));
-static tree member_declared_type PARAMS ((tree));
+static tree decl_ultimate_origin (tree);
+static tree block_ultimate_origin (tree);
+static tree decl_class_context (tree);
+static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
+static inline enum dw_val_class AT_class (dw_attr_ref);
+static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
+static inline unsigned AT_flag (dw_attr_ref);
+static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
+static inline HOST_WIDE_INT AT_int (dw_attr_ref);
+static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
+static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
+static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
+ unsigned long);
+static void add_AT_float (dw_die_ref, enum dwarf_attribute, unsigned, long *);
+static hashval_t debug_str_do_hash (const void *);
+static int debug_str_eq (const void *, const void *);
+static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
+static inline const char *AT_string (dw_attr_ref);
+static int AT_string_form (dw_attr_ref);
+static void add_AT_die_ref (dw_die_ref, enum dwarf_attribute, dw_die_ref);
+static inline dw_die_ref AT_ref (dw_attr_ref);
+static inline int AT_ref_external (dw_attr_ref);
+static inline void set_AT_ref_external (dw_attr_ref, int);
+static void add_AT_fde_ref (dw_die_ref, enum dwarf_attribute, unsigned);
+static void add_AT_loc (dw_die_ref, enum dwarf_attribute, dw_loc_descr_ref);
+static inline dw_loc_descr_ref AT_loc (dw_attr_ref);
+static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
+ dw_loc_list_ref);
+static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
+static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
+static inline rtx AT_addr (dw_attr_ref);
+static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_lbl_offset (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
+ unsigned HOST_WIDE_INT);
+static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
+ unsigned long);
+static inline const char *AT_lbl (dw_attr_ref);
+static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
+static const char *get_AT_low_pc (dw_die_ref);
+static const char *get_AT_hi_pc (dw_die_ref);
+static const char *get_AT_string (dw_die_ref, enum dwarf_attribute);
+static int get_AT_flag (dw_die_ref, enum dwarf_attribute);
+static unsigned get_AT_unsigned (dw_die_ref, enum dwarf_attribute);
+static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
+static bool is_c_family (void);
+static bool is_cxx (void);
+static bool is_java (void);
+static bool is_fortran (void);
+static bool is_ada (void);
+static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static inline void free_die (dw_die_ref);
+static void remove_children (dw_die_ref);
+static void add_child_die (dw_die_ref, dw_die_ref);
+static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
+static dw_die_ref lookup_type_die (tree);
+static void equate_type_number_to_die (tree, dw_die_ref);
+static dw_die_ref lookup_decl_die (tree);
+static void equate_decl_number_to_die (tree, dw_die_ref);
+static void print_spaces (FILE *);
+static void print_die (dw_die_ref, FILE *);
+static void print_dwarf_line_table (FILE *);
+static void reverse_die_lists (dw_die_ref);
+static void reverse_all_dies (dw_die_ref);
+static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
+static dw_die_ref pop_compile_unit (dw_die_ref);
+static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
+static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *);
+static void die_checksum (dw_die_ref, struct md5_ctx *, int *);
+static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
+static int same_dw_val_p (dw_val_node *, dw_val_node *, int *);
+static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
+static int same_die_p (dw_die_ref, dw_die_ref, int *);
+static int same_die_p_wrap (dw_die_ref, dw_die_ref);
+static void compute_section_prefix (dw_die_ref);
+static int is_type_die (dw_die_ref);
+static int is_comdat_die (dw_die_ref);
+static int is_symbol_die (dw_die_ref);
+static void assign_symbol_names (dw_die_ref);
+static void break_out_includes (dw_die_ref);
+static hashval_t htab_cu_hash (const void *);
+static int htab_cu_eq (const void *, const void *);
+static void htab_cu_del (void *);
+static int check_duplicate_cu (dw_die_ref, htab_t, unsigned *);
+static void record_comdat_symbol_number (dw_die_ref, htab_t, unsigned);
+static void add_sibling_attributes (dw_die_ref);
+static void build_abbrev_table (dw_die_ref);
+static void output_location_lists (dw_die_ref);
+static int constant_size (long unsigned);
+static unsigned long size_of_die (dw_die_ref);
+static void calc_die_sizes (dw_die_ref);
+static void mark_dies (dw_die_ref);
+static void unmark_dies (dw_die_ref);
+static void unmark_all_dies (dw_die_ref);
+static unsigned long size_of_pubnames (void);
+static unsigned long size_of_aranges (void);
+static enum dwarf_form value_format (dw_attr_ref);
+static void output_value_format (dw_attr_ref);
+static void output_abbrev_section (void);
+static void output_die_symbol (dw_die_ref);
+static void output_die (dw_die_ref);
+static void output_compilation_unit_header (void);
+static void output_comp_unit (dw_die_ref, int);
+static const char *dwarf2_name (tree, int);
+static void add_pubname (tree, dw_die_ref);
+static void output_pubnames (void);
+static void add_arange (tree, dw_die_ref);
+static void output_aranges (void);
+static unsigned int add_ranges (tree);
+static void output_ranges (void);
+static void output_line_info (void);
+static void output_file_names (void);
+static dw_die_ref base_type_die (tree);
+static tree root_type (tree);
+static int is_base_type (tree);
+static bool is_ada_subrange_type (tree);
+static dw_die_ref subrange_type_die (tree);
+static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
+static int type_is_enum (tree);
+static unsigned int reg_number (rtx);
+static dw_loc_descr_ref reg_loc_descriptor (rtx);
+static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int);
+static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx);
+static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
+static dw_loc_descr_ref based_loc_descr (unsigned, HOST_WIDE_INT);
+static int is_based_loc (rtx);
+static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode);
+static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx);
+static dw_loc_descr_ref loc_descriptor (rtx);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
+static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
+static tree field_type (tree);
+static unsigned int simple_type_align_in_bits (tree);
+static unsigned int simple_decl_align_in_bits (tree);
+static unsigned HOST_WIDE_INT simple_type_size_in_bits (tree);
+static HOST_WIDE_INT field_byte_offset (tree);
+static void add_AT_location_description (dw_die_ref, enum dwarf_attribute,
+ dw_loc_descr_ref);
+static void add_data_member_location_attribute (dw_die_ref, tree);
+static void add_const_value_attribute (dw_die_ref, rtx);
+static rtx rtl_for_decl_location (tree);
+static void add_location_or_const_value_attribute (dw_die_ref, tree);
+static void tree_add_const_value_attribute (dw_die_ref, tree);
+static void add_name_attribute (dw_die_ref, const char *);
+static void add_comp_dir_attribute (dw_die_ref);
+static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
+static void add_subscript_info (dw_die_ref, tree);
+static void add_byte_size_attribute (dw_die_ref, tree);
+static void add_bit_offset_attribute (dw_die_ref, tree);
+static void add_bit_size_attribute (dw_die_ref, tree);
+static void add_prototyped_attribute (dw_die_ref, tree);
+static void add_abstract_origin_attribute (dw_die_ref, tree);
+static void add_pure_or_virtual_attribute (dw_die_ref, tree);
+static void add_src_coords_attributes (dw_die_ref, tree);
+static void add_name_and_src_coords_attributes (dw_die_ref, tree);
+static void push_decl_scope (tree);
+static void pop_decl_scope (void);
+static dw_die_ref scope_die_for (tree, dw_die_ref);
+static inline int local_scope_p (dw_die_ref);
+static inline int class_scope_p (dw_die_ref);
+static void add_type_attribute (dw_die_ref, tree, int, int, dw_die_ref);
+static const char *type_tag (tree);
+static tree member_declared_type (tree);
#if 0
-static const char *decl_start_label PARAMS ((tree));
+static const char *decl_start_label (tree);
#endif
-static void gen_array_type_die PARAMS ((tree, dw_die_ref));
-static void gen_set_type_die PARAMS ((tree, dw_die_ref));
+static void gen_array_type_die (tree, dw_die_ref);
+static void gen_set_type_die (tree, dw_die_ref);
#if 0
-static void gen_entry_point_die PARAMS ((tree, dw_die_ref));
+static void gen_entry_point_die (tree, dw_die_ref);
#endif
-static void gen_inlined_enumeration_type_die PARAMS ((tree, dw_die_ref));
-static void gen_inlined_structure_type_die PARAMS ((tree, dw_die_ref));
-static void gen_inlined_union_type_die PARAMS ((tree, dw_die_ref));
-static void gen_enumeration_type_die PARAMS ((tree, dw_die_ref));
-static dw_die_ref gen_formal_parameter_die PARAMS ((tree, dw_die_ref));
-static void gen_unspecified_parameters_die PARAMS ((tree, dw_die_ref));
-static void gen_formal_types_die PARAMS ((tree, dw_die_ref));
-static void gen_subprogram_die PARAMS ((tree, dw_die_ref));
-static void gen_variable_die PARAMS ((tree, dw_die_ref));
-static void gen_label_die PARAMS ((tree, dw_die_ref));
-static void gen_lexical_block_die PARAMS ((tree, dw_die_ref, int));
-static void gen_inlined_subroutine_die PARAMS ((tree, dw_die_ref, int));
-static void gen_field_die PARAMS ((tree, dw_die_ref));
-static void gen_ptr_to_mbr_type_die PARAMS ((tree, dw_die_ref));
-static dw_die_ref gen_compile_unit_die PARAMS ((const char *));
-static void gen_string_type_die PARAMS ((tree, dw_die_ref));
-static void gen_inheritance_die PARAMS ((tree, dw_die_ref));
-static void gen_member_die PARAMS ((tree, dw_die_ref));
-static void gen_struct_or_union_type_die PARAMS ((tree, dw_die_ref));
-static void gen_subroutine_type_die PARAMS ((tree, dw_die_ref));
-static void gen_typedef_die PARAMS ((tree, dw_die_ref));
-static void gen_type_die PARAMS ((tree, dw_die_ref));
-static void gen_tagged_type_instantiation_die PARAMS ((tree, dw_die_ref));
-static void gen_block_die PARAMS ((tree, dw_die_ref, int));
-static void decls_for_scope PARAMS ((tree, dw_die_ref, int));
-static int is_redundant_typedef PARAMS ((tree));
-static void gen_decl_die PARAMS ((tree, dw_die_ref));
-static unsigned lookup_filename PARAMS ((const char *));
-static void init_file_table PARAMS ((void));
-static void retry_incomplete_types PARAMS ((void));
-static void gen_type_die_for_member PARAMS ((tree, tree, dw_die_ref));
-static void splice_child_die PARAMS ((dw_die_ref, dw_die_ref));
-static int file_info_cmp PARAMS ((const void *, const void *));
-static dw_loc_list_ref new_loc_list PARAMS ((dw_loc_descr_ref,
- const char *, const char *,
- const char *, unsigned));
-static void add_loc_descr_to_loc_list PARAMS ((dw_loc_list_ref *,
- dw_loc_descr_ref,
- const char *, const char *, const char *));
-static void output_loc_list PARAMS ((dw_loc_list_ref));
-static char *gen_internal_sym PARAMS ((const char *));
-static void mark_limbo_die_list PARAMS ((void *));
+static void gen_inlined_enumeration_type_die (tree, dw_die_ref);
+static void gen_inlined_structure_type_die (tree, dw_die_ref);
+static void gen_inlined_union_type_die (tree, dw_die_ref);
+static void gen_enumeration_type_die (tree, dw_die_ref);
+static dw_die_ref gen_formal_parameter_die (tree, dw_die_ref);
+static void gen_unspecified_parameters_die (tree, dw_die_ref);
+static void gen_formal_types_die (tree, dw_die_ref);
+static void gen_subprogram_die (tree, dw_die_ref);
+static void gen_variable_die (tree, dw_die_ref);
+static void gen_label_die (tree, dw_die_ref);
+static void gen_lexical_block_die (tree, dw_die_ref, int);
+static void gen_inlined_subroutine_die (tree, dw_die_ref, int);
+static void gen_field_die (tree, dw_die_ref);
+static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
+static dw_die_ref gen_compile_unit_die (const char *);
+static void gen_string_type_die (tree, dw_die_ref);
+static void gen_inheritance_die (tree, tree, dw_die_ref);
+static void gen_member_die (tree, dw_die_ref);
+static void gen_struct_or_union_type_die (tree, dw_die_ref);
+static void gen_subroutine_type_die (tree, dw_die_ref);
+static void gen_typedef_die (tree, dw_die_ref);
+static void gen_type_die (tree, dw_die_ref);
+static void gen_tagged_type_instantiation_die (tree, dw_die_ref);
+static void gen_block_die (tree, dw_die_ref, int);
+static void decls_for_scope (tree, dw_die_ref, int);
+static int is_redundant_typedef (tree);
+static void gen_decl_die (tree, dw_die_ref);
+static unsigned lookup_filename (const char *);
+static void init_file_table (void);
+static void retry_incomplete_types (void);
+static void gen_type_die_for_member (tree, tree, dw_die_ref);
+static void splice_child_die (dw_die_ref, dw_die_ref);
+static int file_info_cmp (const void *, const void *);
+static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
+ const char *, const char *, unsigned);
+static void add_loc_descr_to_loc_list (dw_loc_list_ref *, dw_loc_descr_ref,
+ const char *, const char *,
+ const char *);
+static void output_loc_list (dw_loc_list_ref);
+static char *gen_internal_sym (const char *);
+
+static void prune_unmark_dies (dw_die_ref);
+static void prune_unused_types_mark (dw_die_ref, int);
+static void prune_unused_types_walk (dw_die_ref);
+static void prune_unused_types_walk_attribs (dw_die_ref);
+static void prune_unused_types_prune (dw_die_ref);
+static void prune_unused_types (void);
+static int maybe_emit_file (int);
/* Section names used to hold DWARF debugging information. */
#ifndef DEBUG_INFO_SECTION
#endif
/* Section flags for .debug_str section. */
-#ifdef HAVE_GAS_SHF_MERGE
#define DEBUG_STR_SECTION_FLAGS \
- (SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1)
-#else
-#define DEBUG_STR_SECTION_FLAGS SECTION_DEBUG
-#endif
+ (HAVE_GAS_SHF_MERGE && flag_merge_constants \
+ ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \
+ : SECTION_DEBUG)
/* Labels we insert at beginning sections we can reference instead of
the section names themselves. */
/* We allow a language front-end to designate a function that is to be
called to "demangle" any name before it it put into a DIE. */
-static const char *(*demangle_name_func) PARAMS ((const char *));
+static const char *(*demangle_name_func) (const char *);
void
-dwarf2out_set_demangle_name_func (func)
- const char *(*func) PARAMS ((const char *));
+dwarf2out_set_demangle_name_func (const char *(*func) (const char *))
{
demangle_name_func = func;
}
/* Test if rtl node points to a pseudo register. */
static inline int
-is_pseudo_reg (rtl)
- rtx rtl;
+is_pseudo_reg (rtx rtl)
{
return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
|| (GET_CODE (rtl) == SUBREG
removed. */
static inline tree
-type_main_variant (type)
- tree type;
+type_main_variant (tree type)
{
type = TYPE_MAIN_VARIANT (type);
return type;
}
-/* Return non-zero if the given type node represents a tagged type. */
+/* Return nonzero if the given type node represents a tagged type. */
static inline int
-is_tagged_type (type)
- tree type;
+is_tagged_type (tree type)
{
enum tree_code code = TREE_CODE (type);
/* Convert a DIE tag into its string name. */
static const char *
-dwarf_tag_name (tag)
- unsigned tag;
+dwarf_tag_name (unsigned int tag)
{
switch (tag)
{
/* Convert a DWARF attribute code into its string name. */
static const char *
-dwarf_attr_name (attr)
- unsigned attr;
+dwarf_attr_name (unsigned int attr)
{
switch (attr)
{
/* Convert a DWARF value form code into its string name. */
static const char *
-dwarf_form_name (form)
- unsigned form;
+dwarf_form_name (unsigned int form)
{
switch (form)
{
#if 0
static const char *
-dwarf_type_encoding_name (enc)
- unsigned enc;
+dwarf_type_encoding_name (unsigned enc)
{
switch (enc)
{
given block. */
static tree
-decl_ultimate_origin (decl)
- tree decl;
+decl_ultimate_origin (tree decl)
{
/* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
nodes in the function to point to themselves; ignore that if
given block. */
static tree
-block_ultimate_origin (block)
- tree block;
+block_ultimate_origin (tree block)
{
tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
parameter. */
static tree
-decl_class_context (decl)
- tree decl;
+decl_class_context (tree decl)
{
tree context = NULL_TREE;
addition order, and correct that in reverse_all_dies. */
static inline void
-add_dwarf_attr (die, attr)
- dw_die_ref die;
- dw_attr_ref attr;
+add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
{
if (die != NULL && attr != NULL)
{
}
}
-static inline dw_val_class
-AT_class (a)
- dw_attr_ref a;
+static inline enum dw_val_class
+AT_class (dw_attr_ref a)
{
return a->dw_attr_val.val_class;
}
/* Add a flag value attribute to a DIE. */
static inline void
-add_AT_flag (die, attr_kind, flag)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned flag;
+add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
}
static inline unsigned
-AT_flag (a)
- dw_attr_ref a;
+AT_flag (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_flag)
return a->dw_attr_val.v.val_flag;
/* Add a signed integer attribute value to a DIE. */
static inline void
-add_AT_int (die, attr_kind, int_val)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- long int int_val;
+add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
add_dwarf_attr (die, attr);
}
-static inline long int
-AT_int (a)
- dw_attr_ref a;
+static inline HOST_WIDE_INT
+AT_int (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_const)
return a->dw_attr_val.v.val_int;
/* Add an unsigned integer attribute value to a DIE. */
static inline void
-add_AT_unsigned (die, attr_kind, unsigned_val)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned long unsigned_val;
+add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned HOST_WIDE_INT unsigned_val)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
add_dwarf_attr (die, attr);
}
-static inline unsigned long
-AT_unsigned (a)
- dw_attr_ref a;
+static inline unsigned HOST_WIDE_INT
+AT_unsigned (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_unsigned_const)
return a->dw_attr_val.v.val_unsigned;
/* Add an unsigned double integer attribute value to a DIE. */
static inline void
-add_AT_long_long (die, attr_kind, val_hi, val_low)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned long val_hi;
- unsigned long val_low;
+add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
+ long unsigned int val_hi, long unsigned int val_low)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
/* Add a floating point attribute value to a DIE and return it. */
static inline void
-add_AT_float (die, attr_kind, length, array)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned length;
- long *array;
+add_AT_float (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned int length, long int *array)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
add_dwarf_attr (die, attr);
}
+/* Hash and equality functions for debug_str_hash. */
+
+static hashval_t
+debug_str_do_hash (const void *x)
+{
+ return htab_hash_string (((const struct indirect_string_node *)x)->str);
+}
+
+static int
+debug_str_eq (const void *x1, const void *x2)
+{
+ return strcmp ((((const struct indirect_string_node *)x1)->str),
+ (const char *)x2) == 0;
+}
+
/* Add a string attribute value to a DIE. */
static inline void
-add_AT_string (die, attr_kind, str)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- const char *str;
+add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
struct indirect_string_node *node;
+ void **slot;
if (! debug_str_hash)
- {
- debug_str_hash = ht_create (10);
- debug_str_hash->alloc_node = indirect_string_alloc;
- }
-
- node = (struct indirect_string_node *)
- ht_lookup (debug_str_hash, (const unsigned char *) str,
- strlen (str), HT_ALLOC);
+ debug_str_hash = htab_create_ggc (10, debug_str_do_hash,
+ debug_str_eq, NULL);
+
+ slot = htab_find_slot_with_hash (debug_str_hash, str,
+ htab_hash_string (str), INSERT);
+ if (*slot == NULL)
+ *slot = ggc_alloc_cleared (sizeof (struct indirect_string_node));
+ node = (struct indirect_string_node *) *slot;
+ node->str = ggc_strdup (str);
node->refcount++;
attr->dw_attr_next = NULL;
}
static inline const char *
-AT_string (a)
- dw_attr_ref a;
+AT_string (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_str)
- return (const char *) HT_STR (&a->dw_attr_val.v.val_str->id);
+ return a->dw_attr_val.v.val_str->str;
abort ();
}
or out-of-line in .debug_str section. */
static int
-AT_string_form (a)
- dw_attr_ref a;
+AT_string_form (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_str)
{
struct indirect_string_node *node;
unsigned int len;
- extern int const_labelno;
char label[32];
node = a->dw_attr_val.v.val_str;
if (node->form)
return node->form;
- len = HT_LEN (&node->id) + 1;
+ len = strlen (node->str) + 1;
/* If the string is shorter or equal to the size of the reference, it is
always better to put it inline. */
&& (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
return node->form = DW_FORM_string;
- ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
- ++const_labelno;
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
node->label = xstrdup (label);
return node->form = DW_FORM_strp;
/* Add a DIE reference attribute value to a DIE. */
static inline void
-add_AT_die_ref (die, attr_kind, targ_die)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- dw_die_ref targ_die;
+add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
}
static inline dw_die_ref
-AT_ref (a)
- dw_attr_ref a;
+AT_ref (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_die_ref)
return a->dw_attr_val.v.val_die_ref.die;
}
static inline int
-AT_ref_external (a)
- dw_attr_ref a;
+AT_ref_external (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_die_ref)
return a->dw_attr_val.v.val_die_ref.external;
}
static inline void
-set_AT_ref_external (a, i)
- dw_attr_ref a;
- int i;
+set_AT_ref_external (dw_attr_ref a, int i)
{
if (a && AT_class (a) == dw_val_class_die_ref)
a->dw_attr_val.v.val_die_ref.external = i;
/* Add an FDE reference attribute value to a DIE. */
static inline void
-add_AT_fde_ref (die, attr_kind, targ_fde)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned targ_fde;
+add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
/* Add a location description attribute value to a DIE. */
static inline void
-add_AT_loc (die, attr_kind, loc)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- dw_loc_descr_ref loc;
+add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
}
static inline dw_loc_descr_ref
-AT_loc (a)
- dw_attr_ref a;
+AT_loc (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_loc)
return a->dw_attr_val.v.val_loc;
}
static inline void
-add_AT_loc_list (die, attr_kind, loc_list)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- dw_loc_list_ref loc_list;
+add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
}
static inline dw_loc_list_ref
-AT_loc_list (a)
- dw_attr_ref a;
+AT_loc_list (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_loc_list)
return a->dw_attr_val.v.val_loc_list;
/* Add an address constant attribute value to a DIE. */
static inline void
-add_AT_addr (die, attr_kind, addr)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- rtx addr;
+add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
}
static inline rtx
-AT_addr (a)
- dw_attr_ref a;
+AT_addr (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_addr)
return a->dw_attr_val.v.val_addr;
/* Add a label identifier attribute value to a DIE. */
static inline void
-add_AT_lbl_id (die, attr_kind, lbl_id)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- const char *lbl_id;
+add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
/* Add a section offset attribute value to a DIE. */
static inline void
-add_AT_lbl_offset (die, attr_kind, label)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- const char *label;
+add_AT_lbl_offset (dw_die_ref die, enum dwarf_attribute attr_kind, const char *label)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
/* Add an offset attribute value to a DIE. */
static inline void
-add_AT_offset (die, attr_kind, offset)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned long offset;
+add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned HOST_WIDE_INT offset)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
/* Add an range_list attribute value to a DIE. */
static void
-add_AT_range_list (die, attr_kind, offset)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- unsigned long offset;
+add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
+ long unsigned int offset)
{
- dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
}
static inline const char *
-AT_lbl (a)
- dw_attr_ref a;
+AT_lbl (dw_attr_ref a)
{
if (a && (AT_class (a) == dw_val_class_lbl_id
|| AT_class (a) == dw_val_class_lbl_offset))
/* Get the attribute of type attr_kind. */
static inline dw_attr_ref
-get_AT (die, attr_kind)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
+get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
dw_die_ref spec = NULL;
cannot be represented as an assembler label identifier. */
static inline const char *
-get_AT_low_pc (die)
- dw_die_ref die;
+get_AT_low_pc (dw_die_ref die)
{
dw_attr_ref a = get_AT (die, DW_AT_low_pc);
cannot be represented as an assembler label identifier. */
static inline const char *
-get_AT_hi_pc (die)
- dw_die_ref die;
+get_AT_hi_pc (dw_die_ref die)
{
dw_attr_ref a = get_AT (die, DW_AT_high_pc);
NULL if it is not present. */
static inline const char *
-get_AT_string (die, attr_kind)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
+get_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
if it is not present. */
static inline int
-get_AT_flag (die, attr_kind)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
+get_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
if it is not present. */
static inline unsigned
-get_AT_unsigned (die, attr_kind)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
+get_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
}
static inline dw_die_ref
-get_AT_ref (die, attr_kind)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
+get_AT_ref (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
return a ? AT_ref (a) : NULL;
}
-static inline int
-is_c_family ()
+/* Return TRUE if the language is C or C++. */
+
+static inline bool
+is_c_family (void)
{
- unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_C || lang == DW_LANG_C89
|| lang == DW_LANG_C_plus_plus);
}
-static inline int
-is_cxx ()
+/* Return TRUE if the language is C++. */
+
+static inline bool
+is_cxx (void)
{
return (get_AT_unsigned (comp_unit_die, DW_AT_language)
== DW_LANG_C_plus_plus);
}
-static inline int
-is_fortran ()
+/* Return TRUE if the language is Fortran. */
+
+static inline bool
+is_fortran (void)
{
- unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
- return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
+ return lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90;
}
-static inline int
-is_java ()
+/* Return TRUE if the language is Java. */
+
+static inline bool
+is_java (void)
{
- unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
- return (lang == DW_LANG_Java);
+ return lang == DW_LANG_Java;
}
-/* Free up the memory used by A. */
+/* Return TRUE if the language is Ada. */
-static inline void free_AT PARAMS ((dw_attr_ref));
-static inline void
-free_AT (a)
- dw_attr_ref a;
+static inline bool
+is_ada (void)
{
- switch (AT_class (a))
- {
- case dw_val_class_str:
- if (a->dw_attr_val.v.val_str->refcount)
- a->dw_attr_val.v.val_str->refcount--;
- break;
-
- case dw_val_class_lbl_id:
- case dw_val_class_lbl_offset:
- free (a->dw_attr_val.v.val_lbl_id);
- break;
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
- case dw_val_class_float:
- free (a->dw_attr_val.v.val_float.array);
- break;
+ return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
+}
- default:
- break;
- }
+/* Free up the memory used by A. */
- free (a);
+static inline void free_AT (dw_attr_ref);
+static inline void
+free_AT (dw_attr_ref a)
+{
+ if (AT_class (a) == dw_val_class_str)
+ if (a->dw_attr_val.v.val_str->refcount)
+ a->dw_attr_val.v.val_str->refcount--;
}
/* Remove the specified attribute if present. */
static void
-remove_AT (die, attr_kind)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
+remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref *p;
dw_attr_ref removed = NULL;
/* Free up the memory used by DIE. */
static inline void
-free_die (die)
- dw_die_ref die;
+free_die (dw_die_ref die)
{
remove_children (die);
- free (die);
}
/* Discard the children of this DIE. */
static void
-remove_children (die)
- dw_die_ref die;
+remove_children (dw_die_ref die)
{
dw_die_ref child_die = die->die_child;
addition order, and correct that in reverse_all_dies. */
static inline void
-add_child_die (die, child_die)
- dw_die_ref die;
- dw_die_ref child_die;
+add_child_die (dw_die_ref die, dw_die_ref child_die)
{
if (die != NULL && child_die != NULL)
{
is the specification, to the front of PARENT's list of children. */
static void
-splice_child_die (parent, child)
- dw_die_ref parent, child;
+splice_child_die (dw_die_ref parent, dw_die_ref child)
{
dw_die_ref *p;
break;
}
+ child->die_parent = parent;
child->die_sib = parent->die_child;
parent->die_child = child;
}
/* Return a pointer to a newly created DIE node. */
static inline dw_die_ref
-new_die (tag_value, parent_die, t)
- enum dwarf_tag tag_value;
- dw_die_ref parent_die;
- tree t;
+new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
{
- dw_die_ref die = (dw_die_ref) xcalloc (1, sizeof (die_node));
+ dw_die_ref die = ggc_alloc_cleared (sizeof (die_node));
die->die_tag = tag_value;
{
limbo_die_node *limbo_node;
- limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node));
+ limbo_node = ggc_alloc_cleared (sizeof (limbo_die_node));
limbo_node->die = die;
limbo_node->created_for = t;
limbo_node->next = limbo_die_list;
/* Return the DIE associated with the given type specifier. */
static inline dw_die_ref
-lookup_type_die (type)
- tree type;
+lookup_type_die (tree type)
{
return TYPE_SYMTAB_DIE (type);
}
/* Equate a DIE to a given type specifier. */
static inline void
-equate_type_number_to_die (type, type_die)
- tree type;
- dw_die_ref type_die;
+equate_type_number_to_die (tree type, dw_die_ref type_die)
{
TYPE_SYMTAB_DIE (type) = type_die;
}
/* Return the DIE associated with a given declaration. */
static inline dw_die_ref
-lookup_decl_die (decl)
- tree decl;
+lookup_decl_die (tree decl)
{
unsigned decl_id = DECL_UID (decl);
/* Equate a DIE to a particular declaration. */
static void
-equate_decl_number_to_die (decl, decl_die)
- tree decl;
- dw_die_ref decl_die;
+equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
{
unsigned int decl_id = DECL_UID (decl);
unsigned int num_allocated;
/ DECL_DIE_TABLE_INCREMENT)
* DECL_DIE_TABLE_INCREMENT;
- decl_die_table
- = (dw_die_ref *) xrealloc (decl_die_table,
- sizeof (dw_die_ref) * num_allocated);
+ decl_die_table = ggc_realloc (decl_die_table,
+ sizeof (dw_die_ref) * num_allocated);
- memset ((char *) &decl_die_table[decl_die_table_allocated], 0,
+ memset (&decl_die_table[decl_die_table_allocated], 0,
(num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
decl_die_table_allocated = num_allocated;
}
/* Indent the line the number of spaces given by print_indent. */
static inline void
-print_spaces (outfile)
- FILE *outfile;
+print_spaces (FILE *outfile)
{
fprintf (outfile, "%*s", print_indent, "");
}
This routine is a debugging aid only. */
static void
-print_die (die, outfile)
- dw_die_ref die;
- FILE *outfile;
+print_die (dw_die_ref die, FILE *outfile)
{
dw_attr_ref a;
dw_die_ref c;
fprintf (outfile, "range list");
break;
case dw_val_class_const:
- fprintf (outfile, "%ld", AT_int (a));
+ fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
break;
case dw_val_class_unsigned_const:
- fprintf (outfile, "%lu", AT_unsigned (a));
+ fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
break;
case dw_val_class_long_long:
fprintf (outfile, "constant (%lu,%lu)",
This routine is a debugging aid only. */
static void
-print_dwarf_line_table (outfile)
- FILE *outfile;
+print_dwarf_line_table (FILE *outfile)
{
unsigned i;
dw_line_info_ref line_info;
{
line_info = &line_info_table[i];
fprintf (outfile, "%5d: ", i);
- fprintf (outfile, "%-20s", file_table.table[line_info->dw_file_num]);
+ fprintf (outfile, "%-20s",
+ VARRAY_CHAR_PTR (file_table, line_info->dw_file_num));
fprintf (outfile, "%6ld", line_info->dw_line_num);
fprintf (outfile, "\n");
}
/* Print the information collected for a given DIE. */
void
-debug_dwarf_die (die)
- dw_die_ref die;
+debug_dwarf_die (dw_die_ref die)
{
print_die (die, stderr);
}
This routine is a debugging aid only. */
void
-debug_dwarf ()
+debug_dwarf (void)
{
print_indent = 0;
print_die (comp_unit_die, stderr);
they are in order of addition. */
static void
-reverse_die_lists (die)
- dw_die_ref die;
+reverse_die_lists (dw_die_ref die)
{
dw_die_ref c, cp, cn;
dw_attr_ref a, ap, an;
recursively reverse all the dies. This is that routine. */
static void
-reverse_all_dies (die)
- dw_die_ref die;
+reverse_all_dies (dw_die_ref die)
{
dw_die_ref c;
DIE that marks the start of the DIEs for this include file. */
static dw_die_ref
-push_new_compile_unit (old_unit, bincl_die)
- dw_die_ref old_unit, bincl_die;
+push_new_compile_unit (dw_die_ref old_unit, dw_die_ref bincl_die)
{
const char *filename = get_AT_string (bincl_die, DW_AT_name);
dw_die_ref new_unit = gen_compile_unit_die (filename);
/* Close an include-file CU and reopen the enclosing one. */
static dw_die_ref
-pop_compile_unit (old_unit)
- dw_die_ref old_unit;
+pop_compile_unit (dw_die_ref old_unit)
{
dw_die_ref new_unit = old_unit->die_sib;
/* Calculate the checksum of a location expression. */
static inline void
-loc_checksum (loc, ctx)
- dw_loc_descr_ref loc;
- struct md5_ctx *ctx;
+loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
{
CHECKSUM (loc->dw_loc_opc);
CHECKSUM (loc->dw_loc_oprnd1);
/* Calculate the checksum of an attribute. */
static void
-attr_checksum (at, ctx)
- dw_attr_ref at;
- struct md5_ctx *ctx;
+attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
{
dw_loc_descr_ref loc;
rtx r;
break;
case dw_val_class_die_ref:
- if (AT_ref (at)->die_offset)
- CHECKSUM (AT_ref (at)->die_offset);
- /* FIXME else use target die name or something. */
+ die_checksum (AT_ref (at), ctx, mark);
+ break;
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
/* Calculate the checksum of a DIE. */
static void
-die_checksum (die, ctx)
- dw_die_ref die;
- struct md5_ctx *ctx;
+die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
{
dw_die_ref c;
dw_attr_ref a;
+ /* To avoid infinite recursion. */
+ if (die->die_mark)
+ {
+ CHECKSUM (die->die_mark);
+ return;
+ }
+ die->die_mark = ++(*mark);
+
CHECKSUM (die->die_tag);
for (a = die->die_attr; a; a = a->dw_attr_next)
- attr_checksum (a, ctx);
+ attr_checksum (a, ctx, mark);
for (c = die->die_child; c; c = c->die_sib)
- die_checksum (c, ctx);
+ die_checksum (c, ctx, mark);
}
#undef CHECKSUM
#undef CHECKSUM_STRING
-/* The prefix to attach to symbols on DIEs in the current comdat debug
- info section. */
-static char *comdat_symbol_id;
+/* Do the location expressions look same? */
+static inline int
+same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
+{
+ return loc1->dw_loc_opc == loc2->dw_loc_opc
+ && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
+ && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+}
-/* The index of the current symbol within the current comdat CU. */
-static unsigned int comdat_symbol_number;
+/* Do the values look the same? */
+static int
+same_dw_val_p (dw_val_node *v1, dw_val_node *v2, int *mark)
+{
+ dw_loc_descr_ref loc1, loc2;
+ rtx r1, r2;
+ unsigned i;
-/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
- children, and set comdat_symbol_id accordingly. */
+ if (v1->val_class != v2->val_class)
+ return 0;
-static void
-compute_section_prefix (unit_die)
- dw_die_ref unit_die;
-{
- const char *base = lbasename (get_AT_string (unit_die, DW_AT_name));
- char *name = (char *) alloca (strlen (base) + 64);
- char *p;
- int i;
- unsigned char checksum[16];
- struct md5_ctx ctx;
+ switch (v1->val_class)
+ {
+ case dw_val_class_const:
+ return v1->v.val_int == v2->v.val_int;
+ case dw_val_class_unsigned_const:
+ return v1->v.val_unsigned == v2->v.val_unsigned;
+ case dw_val_class_long_long:
+ return v1->v.val_long_long.hi == v2->v.val_long_long.hi
+ && v1->v.val_long_long.low == v2->v.val_long_long.low;
+ case dw_val_class_float:
+ if (v1->v.val_float.length != v2->v.val_float.length)
+ return 0;
+ for (i = 0; i < v1->v.val_float.length; i++)
+ if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
+ return 0;
+ return 1;
+ case dw_val_class_flag:
+ return v1->v.val_flag == v2->v.val_flag;
+ case dw_val_class_str:
+ return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
- /* Compute the checksum of the DIE, then append part of it as hex digits to
- the name filename of the unit. */
+ case dw_val_class_addr:
+ r1 = v1->v.val_addr;
+ r2 = v2->v.val_addr;
+ if (GET_CODE (r1) != GET_CODE (r2))
+ return 0;
+ switch (GET_CODE (r1))
+ {
+ case SYMBOL_REF:
+ return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
- md5_init_ctx (&ctx);
- die_checksum (unit_die, &ctx);
- md5_finish_ctx (&ctx, checksum);
+ default:
+ abort ();
+ }
- sprintf (name, "%s.", base);
- clean_symbol_name (name);
+ case dw_val_class_offset:
+ return v1->v.val_offset == v2->v.val_offset;
- p = name + strlen (name);
- for (i = 0; i < 4; i++)
- {
- sprintf (p, "%.2x", checksum[i]);
- p += 2;
- }
+ case dw_val_class_loc:
+ for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
+ loc1 && loc2;
+ loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
+ if (!same_loc_p (loc1, loc2, mark))
+ return 0;
+ return !loc1 && !loc2;
- comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
- comdat_symbol_number = 0;
+ case dw_val_class_die_ref:
+ return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+
+ case dw_val_class_fde_ref:
+ case dw_val_class_lbl_id:
+ case dw_val_class_lbl_offset:
+ return 1;
+
+ default:
+ return 1;
+ }
}
-/* Returns nonzero if DIE represents a type, in the sense of TYPE_P. */
+/* Do the attributes look the same? */
static int
-is_type_die (die)
- dw_die_ref die;
+same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
{
- switch (die->die_tag)
- {
- case DW_TAG_array_type:
- case DW_TAG_class_type:
+ if (at1->dw_attr != at2->dw_attr)
+ return 0;
+
+ /* We don't care about differences in file numbering. */
+ if (at1->dw_attr == DW_AT_decl_file
+ /* Or that this was compiled with a different compiler snapshot; if
+ the output is the same, that's what matters. */
+ || at1->dw_attr == DW_AT_producer)
+ return 1;
+
+ return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
+}
+
+/* Do the dies look the same? */
+
+static int
+same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+{
+ dw_die_ref c1, c2;
+ dw_attr_ref a1, a2;
+
+ /* To avoid infinite recursion. */
+ if (die1->die_mark)
+ return die1->die_mark == die2->die_mark;
+ die1->die_mark = die2->die_mark = ++(*mark);
+
+ if (die1->die_tag != die2->die_tag)
+ return 0;
+
+ for (a1 = die1->die_attr, a2 = die2->die_attr;
+ a1 && a2;
+ a1 = a1->dw_attr_next, a2 = a2->dw_attr_next)
+ if (!same_attr_p (a1, a2, mark))
+ return 0;
+ if (a1 || a2)
+ return 0;
+
+ for (c1 = die1->die_child, c2 = die2->die_child;
+ c1 && c2;
+ c1 = c1->die_sib, c2 = c2->die_sib)
+ if (!same_die_p (c1, c2, mark))
+ return 0;
+ if (c1 || c2)
+ return 0;
+
+ return 1;
+}
+
+/* Do the dies look the same? Wrapper around same_die_p. */
+
+static int
+same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
+{
+ int mark = 0;
+ int ret = same_die_p (die1, die2, &mark);
+
+ unmark_all_dies (die1);
+ unmark_all_dies (die2);
+
+ return ret;
+}
+
+/* The prefix to attach to symbols on DIEs in the current comdat debug
+ info section. */
+static char *comdat_symbol_id;
+
+/* The index of the current symbol within the current comdat CU. */
+static unsigned int comdat_symbol_number;
+
+/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
+ children, and set comdat_symbol_id accordingly. */
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+ const char *die_name = get_AT_string (unit_die, DW_AT_name);
+ const char *base = die_name ? lbasename (die_name) : "anonymous";
+ char *name = alloca (strlen (base) + 64);
+ char *p;
+ int i, mark;
+ unsigned char checksum[16];
+ struct md5_ctx ctx;
+
+ /* Compute the checksum of the DIE, then append part of it as hex digits to
+ the name filename of the unit. */
+
+ md5_init_ctx (&ctx);
+ mark = 0;
+ die_checksum (unit_die, &ctx, &mark);
+ unmark_all_dies (unit_die);
+ md5_finish_ctx (&ctx, checksum);
+
+ sprintf (name, "%s.", base);
+ clean_symbol_name (name);
+
+ p = name + strlen (name);
+ for (i = 0; i < 4; i++)
+ {
+ sprintf (p, "%.2x", checksum[i]);
+ p += 2;
+ }
+
+ comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
+ comdat_symbol_number = 0;
+}
+
+/* Returns nonzero if DIE represents a type, in the sense of TYPE_P. */
+
+static int
+is_type_die (dw_die_ref die)
+{
+ switch (die->die_tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
case DW_TAG_enumeration_type:
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
case DW_TAG_file_type:
case DW_TAG_packed_type:
case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
return 1;
default:
return 0;
compilations (functions). */
static int
-is_comdat_die (c)
- dw_die_ref c;
+is_comdat_die (dw_die_ref c)
{
/* I think we want to leave base types and __vtbl_ptr_type in the main CU, as
we do for stabs. The advantage is a greater likelihood of sharing between
compilation unit. */
static int
-is_symbol_die (c)
- dw_die_ref c;
+is_symbol_die (dw_die_ref c)
{
return (is_type_die (c)
|| (get_AT (c, DW_AT_declaration)
}
static char *
-gen_internal_sym (prefix)
- const char *prefix;
+gen_internal_sym (const char *prefix)
{
char buf[256];
- static int label_num;
ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
return xstrdup (buf);
/* Assign symbols to all worthy DIEs under DIE. */
static void
-assign_symbol_names (die)
- dw_die_ref die;
+assign_symbol_names (dw_die_ref die)
{
dw_die_ref c;
assign_symbol_names (c);
}
+struct cu_hash_table_entry
+{
+ dw_die_ref cu;
+ unsigned min_comdat_num, max_comdat_num;
+ struct cu_hash_table_entry *next;
+};
+
+/* Routines to manipulate hash table of CUs. */
+static hashval_t
+htab_cu_hash (const void *of)
+{
+ const struct cu_hash_table_entry *entry = of;
+
+ return htab_hash_string (entry->cu->die_symbol);
+}
+
+static int
+htab_cu_eq (const void *of1, const void *of2)
+{
+ const struct cu_hash_table_entry *entry1 = of1;
+ const struct die_struct *entry2 = of2;
+
+ return !strcmp (entry1->cu->die_symbol, entry2->die_symbol);
+}
+
+static void
+htab_cu_del (void *what)
+{
+ struct cu_hash_table_entry *next, *entry = what;
+
+ while (entry)
+ {
+ next = entry->next;
+ free (entry);
+ entry = next;
+ }
+}
+
+/* Check whether we have already seen this CU and set up SYM_NUM
+ accordingly. */
+static int
+check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num)
+{
+ struct cu_hash_table_entry dummy;
+ struct cu_hash_table_entry **slot, *entry, *last = &dummy;
+
+ dummy.max_comdat_num = 0;
+
+ slot = (struct cu_hash_table_entry **)
+ htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+ INSERT);
+ entry = *slot;
+
+ for (; entry; last = entry, entry = entry->next)
+ {
+ if (same_die_p_wrap (cu, entry->cu))
+ break;
+ }
+
+ if (entry)
+ {
+ *sym_num = entry->min_comdat_num;
+ return 1;
+ }
+
+ entry = xcalloc (1, sizeof (struct cu_hash_table_entry));
+ entry->cu = cu;
+ entry->min_comdat_num = *sym_num = last->max_comdat_num;
+ entry->next = *slot;
+ *slot = entry;
+
+ return 0;
+}
+
+/* Record SYM_NUM to record of CU in HTABLE. */
+static void
+record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num)
+{
+ struct cu_hash_table_entry **slot, *entry;
+
+ slot = (struct cu_hash_table_entry **)
+ htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+ NO_INSERT);
+ entry = *slot;
+
+ entry->max_comdat_num = sym_num;
+}
+
/* Traverse the DIE (which is always comp_unit_die), and set up
additional compilation units for each of the include files we see
bracketed by BINCL/EINCL. */
static void
-break_out_includes (die)
- dw_die_ref die;
+break_out_includes (dw_die_ref die)
{
dw_die_ref *ptr;
dw_die_ref unit = NULL;
- limbo_die_node *node;
+ limbo_die_node *node, **pnode;
+ htab_t cu_hash_table;
for (ptr = &(die->die_child); *ptr;)
{
#endif
assign_symbol_names (die);
- for (node = limbo_die_list; node; node = node->next)
+ cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del);
+ for (node = limbo_die_list, pnode = &limbo_die_list;
+ node;
+ node = node->next)
{
+ int is_dupl;
+
compute_section_prefix (node->die);
+ is_dupl = check_duplicate_cu (node->die, cu_hash_table,
+ &comdat_symbol_number);
assign_symbol_names (node->die);
+ if (is_dupl)
+ *pnode = node->next;
+ else
+ {
+ pnode = &node->next;
+ record_comdat_symbol_number (node->die, cu_hash_table,
+ comdat_symbol_number);
+ }
}
+ htab_delete (cu_hash_table);
}
/* Traverse the DIE and add a sibling attribute if it may have the
avoid generating sibling attributes for DIE's without children. */
static void
-add_sibling_attributes (die)
- dw_die_ref die;
+add_sibling_attributes (dw_die_ref die)
{
dw_die_ref c;
/* Output all location lists for the DIE and its children. */
static void
-output_location_lists (die)
- dw_die_ref die;
+output_location_lists (dw_die_ref die)
{
dw_die_ref c;
dw_attr_ref d_attr;
die are visited recursively. */
static void
-build_abbrev_table (die)
- dw_die_ref die;
+build_abbrev_table (dw_die_ref die)
{
unsigned long abbrev_id;
unsigned int n_alloc;
if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
{
n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
- abbrev_die_table
- = (dw_die_ref *) xrealloc (abbrev_die_table,
- sizeof (dw_die_ref) * n_alloc);
+ abbrev_die_table = ggc_realloc (abbrev_die_table,
+ sizeof (dw_die_ref) * n_alloc);
- memset ((char *) &abbrev_die_table[abbrev_die_table_allocated], 0,
+ memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
(n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
abbrev_die_table_allocated = n_alloc;
}
/* Return the power-of-two number of bytes necessary to represent VALUE. */
static int
-constant_size (value)
- long unsigned value;
+constant_size (long unsigned int value)
{
int log;
.debug_info section. */
static unsigned long
-size_of_die (die)
- dw_die_ref die;
+size_of_die (dw_die_ref die)
{
unsigned long size = 0;
dw_attr_ref a;
size += 1;
break;
case dw_val_class_die_ref:
- size += DWARF_OFFSET_SIZE;
+ if (AT_ref_external (a))
+ size += DWARF2_ADDR_SIZE;
+ else
+ size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_fde_ref:
size += DWARF_OFFSET_SIZE;
if (AT_string_form (a) == DW_FORM_strp)
size += DWARF_OFFSET_SIZE;
else
- size += HT_LEN (&a->dw_attr_val.v.val_str->id) + 1;
+ size += strlen (a->dw_attr_val.v.val_str->str) + 1;
break;
default:
abort ();
die_offset field in each DIE. */
static void
-calc_die_sizes (die)
- dw_die_ref die;
+calc_die_sizes (dw_die_ref die)
{
dw_die_ref c;
and use that as the flag, but ran into ordering problems. */
static void
-mark_dies (die)
- dw_die_ref die;
+mark_dies (dw_die_ref die)
{
dw_die_ref c;
+ if (die->die_mark)
+ abort ();
+
die->die_mark = 1;
for (c = die->die_child; c; c = c->die_sib)
mark_dies (c);
/* Clear the marks for a die and its children. */
static void
-unmark_dies (die)
- dw_die_ref die;
+unmark_dies (dw_die_ref die)
{
dw_die_ref c;
+ if (!die->die_mark)
+ abort ();
+
die->die_mark = 0;
for (c = die->die_child; c; c = c->die_sib)
unmark_dies (c);
}
+/* Clear the marks for a die, its children and referred dies. */
+
+static void
+unmark_all_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_attr_ref a;
+
+ if (!die->die_mark)
+ return;
+ die->die_mark = 0;
+
+ for (c = die->die_child; c; c = c->die_sib)
+ unmark_all_dies (c);
+
+ for (a = die->die_attr; a; a = a->dw_attr_next)
+ if (AT_class (a) == dw_val_class_die_ref)
+ unmark_all_dies (AT_ref (a));
+}
+
/* Return the size of the .debug_pubnames table generated for the
compilation unit. */
static unsigned long
-size_of_pubnames ()
+size_of_pubnames (void)
{
unsigned long size;
unsigned i;
/* Return the size of the information in the .debug_aranges section. */
static unsigned long
-size_of_aranges ()
+size_of_aranges (void)
{
unsigned long size;
/* Select the encoding of an attribute value. */
static enum dwarf_form
-value_format (a)
- dw_attr_ref a;
+value_format (dw_attr_ref a)
{
switch (a->dw_attr_val.val_class)
{
/* Output the encoding of an attribute value. */
static void
-output_value_format (a)
- dw_attr_ref a;
+output_value_format (dw_attr_ref a)
{
enum dwarf_form form = value_format (a);
table. */
static void
-output_abbrev_section ()
+output_abbrev_section (void)
{
unsigned long abbrev_id;
/* Output a symbol we can use to refer to this DIE from another CU. */
static inline void
-output_die_symbol (die)
- dw_die_ref die;
+output_die_symbol (dw_die_ref die)
{
char *sym = die->die_symbol;
/* We make these global, not weak; if the target doesn't support
.linkonce, it doesn't support combining the sections, so debugging
will break. */
- ASM_GLOBALIZE_LABEL (asm_out_file, sym);
+ (*targetm.asm_out.globalize_label) (asm_out_file, sym);
ASM_OUTPUT_LABEL (asm_out_file, sym);
}
this location list node, which is done for the head of the list only. */
static inline dw_loc_list_ref
-new_loc_list (expr, begin, end, section, gensym)
- dw_loc_descr_ref expr;
- const char *begin;
- const char *end;
- const char *section;
- unsigned gensym;
+new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
+ const char *section, unsigned int gensym)
{
- dw_loc_list_ref retlist
- = (dw_loc_list_ref) xcalloc (1, sizeof (dw_loc_list_node));
+ dw_loc_list_ref retlist = ggc_alloc_cleared (sizeof (dw_loc_list_node));
retlist->begin = begin;
retlist->end = end;
return retlist;
}
-/* Add a location description expression to a location list */
+/* Add a location description expression to a location list. */
static inline void
-add_loc_descr_to_loc_list (list_head, descr, begin, end, section)
- dw_loc_list_ref *list_head;
- dw_loc_descr_ref descr;
- const char *begin;
- const char *end;
- const char *section;
+add_loc_descr_to_loc_list (dw_loc_list_ref *list_head, dw_loc_descr_ref descr,
+ const char *begin, const char *end,
+ const char *section)
{
dw_loc_list_ref *d;
for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
;
- /* Add a new location list node to the list */
+ /* Add a new location list node to the list. */
*d = new_loc_list (descr, begin, end, section, 0);
}
-/* Output the location list given to us */
+/* Output the location list given to us. */
static void
-output_loc_list (list_head)
- dw_loc_list_ref list_head;
+output_loc_list (dw_loc_list_ref list_head)
{
dw_loc_list_ref curr = list_head;
the definitions of each child DIE. */
static void
-output_die (die)
- dw_die_ref die;
+output_die (dw_die_ref die)
{
dw_attr_ref a;
dw_die_ref c;
{
char *p = strchr (ranges_section_label, '\0');
- sprintf (p, "+0x%lx", a->dw_attr_val.v.val_offset);
+ sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
+ a->dw_attr_val.v.val_offset);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
"%s", name);
*p = '\0';
.debug_info section, and precedes the DIE descriptions. */
static void
-output_compilation_unit_header ()
+output_compilation_unit_header (void)
{
- dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset - DWARF_OFFSET_SIZE,
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE,
+ next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
"Length of Compilation Unit Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF version number");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
/* Output the compilation unit DIE and its children. */
static void
-output_comp_unit (die)
- dw_die_ref die;
+output_comp_unit (dw_die_ref die, int output_if_empty)
{
const char *secname;
+ char *oldsym, *tmp;
+
+ /* Unless we are outputting main CU, we may throw away empty ones. */
+ if (!output_if_empty && die->die_child == NULL)
+ return;
/* Even if there are no children of this DIE, we must output the information
about the compilation unit. Otherwise, on an empty translation unit, we
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
calc_die_sizes (die);
- if (die->die_symbol)
+ oldsym = die->die_symbol;
+ if (oldsym)
{
- char *tmp = (char *) alloca (strlen (die->die_symbol) + 24);
+ tmp = alloca (strlen (oldsym) + 24);
- sprintf (tmp, ".gnu.linkonce.wi.%s", die->die_symbol);
+ sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
secname = tmp;
die->die_symbol = NULL;
}
/* Leave the marks on the main CU, so we can check them in
output_pubnames. */
- if (die->die_symbol)
- unmark_dies (die);
+ if (oldsym)
+ {
+ unmark_dies (die);
+ die->die_symbol = oldsym;
+ }
}
/* The DWARF2 pubname for a nested thingy looks like "A::f". The
"A::f(int)". Let's drop the argument list, and maybe the scope. */
static const char *
-dwarf2_name (decl, scope)
- tree decl;
- int scope;
+dwarf2_name (tree decl, int scope)
{
return (*lang_hooks.decl_printable_name) (decl, scope ? 1 : 0);
}
/* Add a new entry to .debug_pubnames if appropriate. */
static void
-add_pubname (decl, die)
- tree decl;
- dw_die_ref die;
+add_pubname (tree decl, dw_die_ref die)
{
pubname_ref p;
{
pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
pubname_table
- = (pubname_ref) xrealloc (pubname_table,
- (pubname_table_allocated
- * sizeof (pubname_entry)));
+ = ggc_realloc (pubname_table,
+ (pubname_table_allocated * sizeof (pubname_entry)));
+ memset (pubname_table + pubname_table_in_use, 0,
+ PUBNAME_TABLE_INCREMENT * sizeof (pubname_entry));
}
p = &pubname_table[pubname_table_in_use++];
visible procedures. */
static void
-output_pubnames ()
+output_pubnames (void)
{
unsigned i;
unsigned long pubnames_length = size_of_pubnames ();
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
"Length of Public Names Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
/* Add a new entry to .debug_aranges if appropriate. */
static void
-add_arange (decl, die)
- tree decl;
- dw_die_ref die;
+add_arange (tree decl, dw_die_ref die)
{
if (! DECL_SECTION_NAME (decl))
return;
if (arange_table_in_use == arange_table_allocated)
{
arange_table_allocated += ARANGE_TABLE_INCREMENT;
- arange_table = (dw_die_ref *)
- xrealloc (arange_table, arange_table_allocated * sizeof (dw_die_ref));
+ arange_table = ggc_realloc (arange_table,
+ (arange_table_allocated
+ * sizeof (dw_die_ref)));
+ memset (arange_table + arange_table_in_use, 0,
+ ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref));
}
arange_table[arange_table_in_use++] = die;
text section generated for this compilation unit. */
static void
-output_aranges ()
+output_aranges (void)
{
unsigned i;
unsigned long aranges_length = size_of_aranges ();
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
"Length of Address Ranges Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
if (DWARF_ARANGES_PAD_SIZE)
{
/* Pad using a 2 byte words so that padding is correct for any
- pointer size. */
+ pointer size. */
dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
2 * DWARF2_ADDR_SIZE);
for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
was placed. */
static unsigned int
-add_ranges (block)
- tree block;
+add_ranges (tree block)
{
unsigned int in_use = ranges_table_in_use;
if (in_use == ranges_table_allocated)
{
ranges_table_allocated += RANGES_TABLE_INCREMENT;
- ranges_table = (dw_ranges_ref)
- xrealloc (ranges_table, (ranges_table_allocated
- * sizeof (struct dw_ranges_struct)));
+ ranges_table
+ = ggc_realloc (ranges_table, (ranges_table_allocated
+ * sizeof (struct dw_ranges_struct)));
+ memset (ranges_table + ranges_table_in_use, 0,
+ RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
}
ranges_table[in_use].block_num = (block ? BLOCK_NUMBER (block) : 0);
}
static void
-output_ranges ()
+output_ranges (void)
{
unsigned i;
static const char *const start_fmt = "Offset 0x%x";
the directories in the path. */
static int
-file_info_cmp (p1, p2)
- const void *p1;
- const void *p2;
+file_info_cmp (const void *p1, const void *p2)
{
const struct file_info *s1 = p1;
const struct file_info *s2 = p2;
slowdowns with many input files. */
static void
-output_file_names ()
+output_file_names (void)
{
struct file_info *files;
struct dir_info *dirs;
int *saved;
int *savehere;
int *backmap;
- int ndirs;
+ size_t ndirs;
int idx_offset;
- int i;
+ size_t i;
int idx;
+ /* Handle the case where file_table is empty. */
+ if (VARRAY_ACTIVE_SIZE (file_table) <= 1)
+ {
+ dw2_asm_output_data (1, 0, "End directory table");
+ dw2_asm_output_data (1, 0, "End file name table");
+ return;
+ }
+
/* Allocate the various arrays we need. */
- files = (struct file_info *) alloca (file_table.in_use
- * sizeof (struct file_info));
- dirs = (struct dir_info *) alloca (file_table.in_use
- * sizeof (struct dir_info));
+ files = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (struct file_info));
+ dirs = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (struct dir_info));
/* Sort the file names. */
- for (i = 1; i < (int) file_table.in_use; i++)
+ for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
{
char *f;
/* Skip all leading "./". */
- f = file_table.table[i];
+ f = VARRAY_CHAR_PTR (file_table, i);
while (f[0] == '.' && f[1] == '/')
f += 2;
files[i].fname = f == NULL ? files[i].path : f + 1;
}
- qsort (files + 1, file_table.in_use - 1, sizeof (files[0]), file_info_cmp);
+ qsort (files + 1, VARRAY_ACTIVE_SIZE (file_table) - 1,
+ sizeof (files[0]), file_info_cmp);
/* Find all the different directories used. */
dirs[0].path = files[1].path;
files[1].dir_idx = 0;
ndirs = 1;
- for (i = 2; i < (int) file_table.in_use; i++)
+ for (i = 2; i < VARRAY_ACTIVE_SIZE (file_table); i++)
if (files[i].fname - files[i].path == dirs[ndirs - 1].length
&& memcmp (dirs[ndirs - 1].path, files[i].path,
dirs[ndirs - 1].length) == 0)
}
else
{
- int j;
+ size_t j;
/* This is a new directory. */
dirs[ndirs].path = files[i].path;
where we would have to check out every combination of every single
possible prefix. Instead we use a heuristic which provides nearly optimal
results in most cases and never is much off. */
- saved = (int *) alloca (ndirs * sizeof (int));
- savehere = (int *) alloca (ndirs * sizeof (int));
+ saved = alloca (ndirs * sizeof (int));
+ savehere = alloca (ndirs * sizeof (int));
memset (saved, '\0', ndirs * sizeof (saved[0]));
for (i = 0; i < ndirs; i++)
{
- int j;
+ size_t j;
int total;
/* We can always save some space for the current directory. But this
int k;
k = dirs[j].prefix;
- while (k != -1 && k != i)
+ while (k != -1 && k != (int) i)
k = dirs[k].prefix;
- if (k == i)
+ if (k == (int) i)
{
/* Yes it is. We can possibly safe some memory but
writing the filenames in dirs[j] relative to
/* We have to emit them in the order they appear in the file_table array
since the index is used in the debug info generation. To do this
efficiently we generate a back-mapping of the indices first. */
- backmap = (int *) alloca (file_table.in_use * sizeof (int));
- for (i = 1; i < (int) file_table.in_use; i++)
+ backmap = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (int));
+ for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
{
backmap[files[i].file_idx] = i;
dirs[0].used = 0;
/* Now write all the file names. */
- for (i = 1; i < (int) file_table.in_use; i++)
+ for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
{
int file_idx = backmap[i];
int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
- "File Entry: 0x%x", i);
+ "File Entry: 0x%lx", (unsigned long) i);
/* Include directory index. */
dw2_asm_output_data_uleb128 (dirs[dir_idx].used, NULL);
information goes into the .debug_line section. */
static void
-output_line_info ()
+output_line_info (void)
{
char l1[20], l2[20], p1[20], p2[20];
char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
"Length of Source Line Info");
ASM_OUTPUT_LABEL (asm_out_file, l1);
prologue. */
/* Don't emit anything for redundant notes. Just updating the
- address doesn't accomplish anything, because we already assume
- that anything after the last address is this line. */
+ address doesn't accomplish anything, because we already assume
+ that anything after the last address is this line. */
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file)
continue;
else
{
/* This can handle any delta. This takes
- 4+DWARF2_ADDR_SIZE bytes. */
+ 4+DWARF2_ADDR_SIZE bytes. */
dw2_asm_output_data (1, 0, "DW_LNE_set_address");
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
current_file = line_info->dw_file_num;
dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
- file_table.table[current_file]);
+ VARRAY_CHAR_PTR (file_table,
+ current_file));
}
/* Emit debug info for the current line number, choosing the encoding
{
function = line_info->function;
- /* Set the address register to the first line in the function */
+ /* Set the address register to the first line in the function. */
dw2_asm_output_data (1, 0, "DW_LNE_set_address");
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
current_file = line_info->dw_file_num;
dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
- file_table.table[current_file]);
+ VARRAY_CHAR_PTR (file_table,
+ current_file));
}
/* Emit debug info for the current line number, choosing the encoding
Dwarf base (fundamental) types. */
static dw_die_ref
-base_type_die (type)
- tree type;
+base_type_die (tree type)
{
dw_die_ref base_type_result;
const char *type_name;
{
case INTEGER_TYPE:
/* Carefully distinguish the C character types, without messing
- up if the language is not C. Note that we check only for the names
- that contain spaces; other names might occur by coincidence in other
- languages. */
+ up if the language is not C. Note that we check only for the names
+ that contain spaces; other names might occur by coincidence in other
+ languages. */
if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
&& (type == char_type_node
|| ! strcmp (type_name, "signed char")
root type of the given type without the qualifiers. */
static tree
-root_type (type)
- tree type;
+root_type (tree type)
{
if (TREE_CODE (type) == ERROR_MARK)
return error_mark_node;
}
}
-/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the
+/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
given input type is a Dwarf "fundamental" type. Otherwise return null. */
static inline int
-is_base_type (type)
- tree type;
+is_base_type (tree type)
{
switch (TREE_CODE (type))
{
return 0;
}
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+ node, return the size in bits for the type if it is a constant, or else
+ return the alignment for the type if the type's size is not constant, or
+ else return BITS_PER_WORD if the type actually turns out to be an
+ ERROR_MARK node. */
+
+static inline unsigned HOST_WIDE_INT
+simple_type_size_in_bits (tree type)
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return BITS_PER_WORD;
+ else if (TYPE_SIZE (type) == NULL_TREE)
+ return 0;
+ else if (host_integerp (TYPE_SIZE (type), 1))
+ return tree_low_cst (TYPE_SIZE (type), 1);
+ else
+ return TYPE_ALIGN (type);
+}
+
+/* Return true if the debug information for the given type should be
+ emitted as a subrange type. */
+
+static inline bool
+is_ada_subrange_type (tree type)
+{
+ /* We do this for INTEGER_TYPEs that have names, parent types, and when
+ we are compiling Ada code. */
+ return (TREE_CODE (type) == INTEGER_TYPE
+ && TYPE_NAME (type) != 0 && TREE_TYPE (type) != 0
+ && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
+ && TREE_UNSIGNED (TREE_TYPE (type)) && is_ada ());
+}
+
+/* Given a pointer to a tree node for a subrange type, return a pointer
+ to a DIE that describes the given type. */
+
+static dw_die_ref
+subrange_type_die (tree type)
+{
+ dw_die_ref subtype_die;
+ dw_die_ref subrange_die;
+ tree name = TYPE_NAME (type);
+
+ subtype_die = base_type_die (TREE_TYPE (type));
+
+ if (TREE_CODE (name) == TYPE_DECL)
+ name = DECL_NAME (name);
+
+ subrange_die = new_die (DW_TAG_subrange_type, comp_unit_die, type);
+ add_name_attribute (subrange_die, IDENTIFIER_POINTER (name));
+ if (TYPE_MIN_VALUE (type) != NULL)
+ add_bound_info (subrange_die, DW_AT_lower_bound,
+ TYPE_MIN_VALUE (type));
+ if (TYPE_MAX_VALUE (type) != NULL)
+ add_bound_info (subrange_die, DW_AT_upper_bound,
+ TYPE_MAX_VALUE (type));
+ add_AT_die_ref (subrange_die, DW_AT_type, subtype_die);
+
+ return subrange_die;
+}
+
/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
entry that chains various modifiers in front of the given type. */
static dw_die_ref
-modified_type_die (type, is_const_type, is_volatile_type, context_die)
- tree type;
- int is_const_type;
- int is_volatile_type;
- dw_die_ref context_die;
+modified_type_die (tree type, int is_const_type, int is_volatile_type,
+ dw_die_ref context_die)
{
enum tree_code code = TREE_CODE (type);
dw_die_ref mod_type_die = NULL;
else if (code == POINTER_TYPE)
{
mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+ simple_type_size_in_bits (type) / BITS_PER_UNIT);
#if 0
add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
#endif
else if (code == REFERENCE_TYPE)
{
mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+ simple_type_size_in_bits (type) / BITS_PER_UNIT);
#if 0
add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
#endif
item_type = TREE_TYPE (type);
}
+ else if (is_ada_subrange_type (type))
+ mod_type_die = subrange_type_die (type);
else if (is_base_type (type))
mod_type_die = base_type_die (type);
else
an enumerated type. */
static inline int
-type_is_enum (type)
- tree type;
+type_is_enum (tree type)
{
return TREE_CODE (type) == ENUMERAL_TYPE;
}
/* Return the register number described by a given RTL node. */
static unsigned int
-reg_number (rtl)
- rtx rtl;
+reg_number (rtx rtl)
{
unsigned regno = REGNO (rtl);
}
/* Return a location descriptor that designates a machine register or
- zero if there is no such. */
+ zero if there is none. */
static dw_loc_descr_ref
-reg_loc_descriptor (rtl)
- rtx rtl;
+reg_loc_descriptor (rtx rtl)
{
- dw_loc_descr_ref loc_result = NULL;
unsigned reg;
+ rtx regs;
if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
return 0;
reg = reg_number (rtl);
- if (reg <= 31)
- loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
+ regs = (*targetm.dwarf_register_span) (rtl);
+
+ if (HARD_REGNO_NREGS (reg, GET_MODE (rtl)) > 1
+ || regs)
+ return multiple_reg_loc_descriptor (rtl, regs);
+ else
+ return one_reg_loc_descriptor (reg);
+}
+
+/* Return a location descriptor that designates a machine register for
+ a given hard register number. */
+
+static dw_loc_descr_ref
+one_reg_loc_descriptor (unsigned int regno)
+{
+ if (regno <= 31)
+ return new_loc_descr (DW_OP_reg0 + regno, 0, 0);
else
- loc_result = new_loc_descr (DW_OP_regx, reg, 0);
+ return new_loc_descr (DW_OP_regx, regno, 0);
+}
+
+/* Given an RTL of a register, return a location descriptor that
+ designates a value that spans more than one register. */
+
+static dw_loc_descr_ref
+multiple_reg_loc_descriptor (rtx rtl, rtx regs)
+{
+ int nregs, size, i;
+ unsigned reg;
+ dw_loc_descr_ref loc_result = NULL;
+
+ reg = reg_number (rtl);
+ nregs = HARD_REGNO_NREGS (reg, GET_MODE (rtl));
+
+ /* Simple, contiguous registers. */
+ if (regs == NULL_RTX)
+ {
+ size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+
+ loc_result = NULL;
+ while (nregs--)
+ {
+ dw_loc_descr_ref t;
+ t = one_reg_loc_descriptor (reg);
+ add_loc_descr (&loc_result, t);
+ add_loc_descr (&loc_result, new_loc_descr (DW_OP_piece, size, 0));
+ ++reg;
+ }
+ return loc_result;
+ }
+
+ /* Now onto stupid register sets in non contiguous locations. */
+
+ if (GET_CODE (regs) != PARALLEL)
+ abort ();
+
+ size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+ loc_result = NULL;
+
+ for (i = 0; i < XVECLEN (regs, 0); ++i)
+ {
+ dw_loc_descr_ref t;
+
+ t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)));
+ add_loc_descr (&loc_result, t);
+ size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+ add_loc_descr (&loc_result, new_loc_descr (DW_OP_piece, size, 0));
+ }
return loc_result;
}
/* Return a location descriptor that designates a constant. */
static dw_loc_descr_ref
-int_loc_descriptor (i)
- HOST_WIDE_INT i;
+int_loc_descriptor (HOST_WIDE_INT i)
{
enum dwarf_location_atom op;
/* Return a location descriptor that designates a base+offset location. */
static dw_loc_descr_ref
-based_loc_descr (reg, offset)
- unsigned reg;
- long int offset;
+based_loc_descr (unsigned int reg, HOST_WIDE_INT offset)
{
dw_loc_descr_ref loc_result;
/* For the "frame base", we use the frame pointer or stack pointer
/* Return true if this RTL expression describes a base+offset calculation. */
static inline int
-is_based_loc (rtl)
- rtx rtl;
+is_based_loc (rtx rtl)
{
return (GET_CODE (rtl) == PLUS
&& ((GET_CODE (XEXP (rtl, 0)) == REG
Return 0 if we can't represent the location. */
static dw_loc_descr_ref
-mem_loc_descriptor (rtl, mode)
- rtx rtl;
- enum machine_mode mode;
+mem_loc_descriptor (rtx rtl, enum machine_mode mode)
{
dw_loc_descr_ref mem_loc_result = NULL;
actually within the array. That's *not* necessarily the same as the
zeroth element of the array. */
-#ifdef ASM_SIMPLIFY_DWARF_ADDR
- rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
-#endif
+ rtl = (*targetm.delegitimize_address) (rtl);
switch (GET_CODE (rtl))
{
case SUBREG:
/* The case of a subreg may arise when we have a local (register)
- variable or a formal (register) parameter which doesn't quite fill
- up an entire register. For now, just assume that it is
- legitimate to make the Dwarf info refer to the whole register which
- contains the given subreg. */
+ variable or a formal (register) parameter which doesn't quite fill
+ up an entire register. For now, just assume that it is
+ legitimate to make the Dwarf info refer to the whole register which
+ contains the given subreg. */
rtl = SUBREG_REG (rtl);
/* ... fall through ... */
case REG:
/* Whenever a register number forms a part of the description of the
- method for calculating the (dynamic) address of a memory resident
- object, DWARF rules require the register number be referred to as
- a "base register". This distinction is not based in any way upon
- what category of register the hardware believes the given register
- belongs to. This is strictly DWARF terminology we're dealing with
- here. Note that in cases where the location of a memory-resident
- data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
- OP_CONST (0)) the actual DWARF location descriptor that we generate
- may just be OP_BASEREG (basereg). This may look deceptively like
- the object in question was allocated to a register (rather than in
- memory) so DWARF consumers need to be aware of the subtle
- distinction between OP_REG and OP_BASEREG. */
+ method for calculating the (dynamic) address of a memory resident
+ object, DWARF rules require the register number be referred to as
+ a "base register". This distinction is not based in any way upon
+ what category of register the hardware believes the given register
+ belongs to. This is strictly DWARF terminology we're dealing with
+ here. Note that in cases where the location of a memory-resident
+ data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+ OP_CONST (0)) the actual DWARF location descriptor that we generate
+ may just be OP_BASEREG (basereg). This may look deceptively like
+ the object in question was allocated to a register (rather than in
+ memory) so DWARF consumers need to be aware of the subtle
+ distinction between OP_REG and OP_BASEREG. */
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
mem_loc_result = based_loc_descr (reg_number (rtl), 0);
break;
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
+ case LO_SUM:
+ rtl = XEXP (rtl, 1);
+
+ /* ... fall through ... */
+
case LABEL_REF:
/* Some ports can transform a symbol ref into a label ref, because
- the symbol ref is too far away and has to be dumped into a constant
- pool. */
+ the symbol ref is too far away and has to be dumped into a constant
+ pool. */
case CONST:
case SYMBOL_REF:
/* Alternatively, the symbol in the constant pool might be referenced
case PRE_MODIFY:
/* Extract the PLUS expression nested inside and fall into
- PLUS code below. */
+ PLUS code below. */
rtl = XEXP (rtl, 1);
goto plus;
This is typically a complex variable. */
static dw_loc_descr_ref
-concat_loc_descriptor (x0, x1)
- rtx x0, x1;
+concat_loc_descriptor (rtx x0, rtx x1)
{
dw_loc_descr_ref cc_loc_result = NULL;
dw_loc_descr_ref x0_ref = loc_descriptor (x0);
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtl)
- rtx rtl;
+loc_descriptor (rtx rtl)
{
dw_loc_descr_ref loc_result = NULL;
{
case SUBREG:
/* The case of a subreg may arise when we have a local (register)
- variable or a formal (register) parameter which doesn't quite fill
- up an entire register. For now, just assume that it is
- legitimate to make the Dwarf info refer to the whole register which
- contains the given subreg. */
+ variable or a formal (register) parameter which doesn't quite fill
+ up an entire register. For now, just assume that it is
+ legitimate to make the Dwarf info refer to the whole register which
+ contains the given subreg. */
rtl = SUBREG_REG (rtl);
/* ... fall through ... */
descriptor, return 0. */
static dw_loc_descr_ref
-loc_descriptor_from_tree (loc, addressp)
- tree loc;
- int addressp;
+loc_descriptor_from_tree (tree loc, int addressp)
{
dw_loc_descr_ref ret, ret1;
int indirect_p = 0;
: 0);
case VAR_DECL:
+ if (DECL_THREAD_LOCAL (loc))
+ {
+ rtx rtl;
+
+#ifndef ASM_OUTPUT_DWARF_DTPREL
+ /* If this is not defined, we have no way to emit the data. */
+ return 0;
+#endif
+
+ /* The way DW_OP_GNU_push_tls_address is specified, we can only
+ look up addresses of objects in the current module. */
+ if (DECL_EXTERNAL (loc))
+ return 0;
+
+ rtl = rtl_for_decl_location (loc);
+ if (rtl == NULL_RTX)
+ return 0;
+
+ if (GET_CODE (rtl) != MEM)
+ return 0;
+ rtl = XEXP (rtl, 0);
+ if (! CONSTANT_P (rtl))
+ return 0;
+
+ ret = new_loc_descr (INTERNAL_DW_OP_tls_addr, 0, 0);
+ ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ ret->dw_loc_oprnd1.v.val_addr = rtl;
+
+ ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+ add_loc_descr (&ret, ret1);
+
+ indirect_p = 1;
+ break;
+ }
+ /* FALLTHRU */
+
case PARM_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
+ case MODIFY_EXPR:
return loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp);
case COMPONENT_REF:
return 0;
break;
+ case CONSTRUCTOR:
+ {
+ /* Get an RTL for this, if something has been emitted. */
+ rtx rtl = lookup_constant_def (loc);
+ enum machine_mode mode;
+
+ if (GET_CODE (rtl) != MEM)
+ return 0;
+ mode = GET_MODE (rtl);
+ rtl = XEXP (rtl, 0);
+
+ rtl = (*targetm.delegitimize_address) (rtl);
+
+ indirect_p = 1;
+ ret = mem_loc_descriptor (rtl, mode);
+ break;
+ }
+
case TRUTH_AND_EXPR:
case TRUTH_ANDIF_EXPR:
case BIT_AND_EXPR:
op = DW_OP_or;
goto do_binop;
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case ROUND_DIV_EXPR:
case TRUNC_DIV_EXPR:
op = DW_OP_div;
goto do_binop;
op = DW_OP_minus;
goto do_binop;
+ case FLOOR_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case ROUND_MOD_EXPR:
case TRUNC_MOD_EXPR:
op = DW_OP_mod;
goto do_binop;
break;
default:
+ /* Leave front-end specific codes as simply unknown. This comes
+ up, for instance, with the C STMT_EXPR. */
+ if ((unsigned int) TREE_CODE (loc)
+ >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
+ return 0;
+
+ /* Otherwise this is a generic code; we should just lists all of
+ these explicitly. Aborting means we forgot one. */
abort ();
}
which is not less than the value itself. */
static inline HOST_WIDE_INT
-ceiling (value, boundary)
- HOST_WIDE_INT value;
- unsigned int boundary;
+ceiling (HOST_WIDE_INT value, unsigned int boundary)
{
return (((value + boundary - 1) / boundary) * boundary);
}
ERROR_MARK node. */
static inline tree
-field_type (decl)
- tree decl;
+field_type (tree decl)
{
tree type;
be an ERROR_MARK node. */
static inline unsigned
-simple_type_align_in_bits (type)
- tree type;
+simple_type_align_in_bits (tree type)
{
return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
}
static inline unsigned
-simple_decl_align_in_bits (decl)
- tree decl;
+simple_decl_align_in_bits (tree decl)
{
return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
}
-/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
- node, return the size in bits for the type if it is a constant, or else
- return the alignment for the type if the type's size is not constant, or
- else return BITS_PER_WORD if the type actually turns out to be an
- ERROR_MARK node. */
-
-static inline unsigned HOST_WIDE_INT
-simple_type_size_in_bits (type)
- tree type;
-{
-
- if (TREE_CODE (type) == ERROR_MARK)
- return BITS_PER_WORD;
- else if (TYPE_SIZE (type) == NULL_TREE)
- return 0;
- else if (host_integerp (TYPE_SIZE (type), 1))
- return tree_low_cst (TYPE_SIZE (type), 1);
- else
- return TYPE_ALIGN (type);
-}
-
/* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
lowest addressed byte of the "containing object" for the given FIELD_DECL,
or return 0 if we are unable to determine what that offset is, either
just yet). */
static HOST_WIDE_INT
-field_byte_offset (decl)
- tree decl;
+field_byte_offset (tree decl)
{
unsigned int type_align_in_bits;
unsigned int decl_align_in_bits;
whole parameters. Note that the location attributes for struct fields are
generated by the routine `data_member_location_attribute' below. */
-static void
-add_AT_location_description (die, attr_kind, rtl)
- dw_die_ref die;
- enum dwarf_attribute attr_kind;
- rtx rtl;
+static inline void
+add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
+ dw_loc_descr_ref descr)
{
- dw_loc_descr_ref descr = loc_descriptor (rtl);
-
if (descr != 0)
add_AT_loc (die, attr_kind, descr);
}
function below.) */
static void
-add_data_member_location_attribute (die, decl)
- dw_die_ref die;
- tree decl;
+add_data_member_location_attribute (dw_die_ref die, tree decl)
{
- long offset;
+ HOST_WIDE_INT offset;
dw_loc_descr_ref loc_descr = 0;
if (TREE_CODE (decl) == TREE_VEC)
add_AT_loc (die, DW_AT_data_member_location, loc_descr);
}
-/* Attach an DW_AT_const_value attribute for a variable or a parameter which
+/* Attach a DW_AT_const_value attribute for a variable or a parameter which
does not have a "location" either in memory or in a register. These
things can arise in GNU C when a constant is passed as an actual parameter
to an inlined function. They can also arise in C++ where declared
constants do not necessarily get memory "homes". */
static void
-add_const_value_attribute (die, rtl)
- dw_die_ref die;
- rtx rtl;
+add_const_value_attribute (dw_die_ref die, rtx rtl)
{
switch (GET_CODE (rtl))
{
{
HOST_WIDE_INT val = INTVAL (rtl);
- /* ??? We really should be using HOST_WIDE_INT throughout. */
- if (val < 0 && (long) val == val)
- add_AT_int (die, DW_AT_const_value, (long) val);
- else if ((unsigned long) val == (unsigned HOST_WIDE_INT) val)
- add_AT_unsigned (die, DW_AT_const_value, (unsigned long) val);
- else
- {
-#if HOST_BITS_PER_LONG * 2 == HOST_BITS_PER_WIDE_INT
- add_AT_long_long (die, DW_AT_const_value,
- val >> HOST_BITS_PER_LONG, val);
-#else
- abort ();
-#endif
- }
+ if (val < 0)
+ add_AT_int (die, DW_AT_const_value, val);
+ else
+ add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
}
break;
case CONST_DOUBLE:
/* Note that a CONST_DOUBLE rtx could represent either an integer or a
- floating-point constant. A CONST_DOUBLE is used whenever the
- constant requires more than one word in order to be adequately
- represented. We output CONST_DOUBLEs as blocks. */
+ floating-point constant. A CONST_DOUBLE is used whenever the
+ constant requires more than one word in order to be adequately
+ represented. We output CONST_DOUBLEs as blocks. */
{
enum machine_mode mode = GET_MODE (rtl);
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
unsigned length = GET_MODE_SIZE (mode) / 4;
- long *array = (long *) xmalloc (sizeof (long) * length);
+ long *array = ggc_alloc (sizeof (long) * length);
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
- switch (mode)
- {
- case SFmode:
- REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]);
- break;
-
- case DFmode:
- REAL_VALUE_TO_TARGET_DOUBLE (rv, array);
- break;
-
- case XFmode:
- case TFmode:
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array);
- break;
-
- default:
- abort ();
- }
+ real_to_target (array, &rv, mode);
add_AT_float (die, DW_AT_const_value, length, array);
}
case PLUS:
/* In cases where an inlined instance of an inline function is passed
- the address of an `auto' variable (which is local to the caller) we
- can get a situation where the DECL_RTL of the artificial local
- variable (for the inlining) which acts as a stand-in for the
- corresponding formal parameter (of the inline function) will look
- like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
- exactly a compile-time constant expression, but it isn't the address
- of the (artificial) local variable either. Rather, it represents the
- *value* which the artificial local variable always has during its
- lifetime. We currently have no way to represent such quasi-constant
- values in Dwarf, so for now we just punt and generate nothing. */
+ the address of an `auto' variable (which is local to the caller) we
+ can get a situation where the DECL_RTL of the artificial local
+ variable (for the inlining) which acts as a stand-in for the
+ corresponding formal parameter (of the inline function) will look
+ like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
+ exactly a compile-time constant expression, but it isn't the address
+ of the (artificial) local variable either. Rather, it represents the
+ *value* which the artificial local variable always has during its
+ lifetime. We currently have no way to represent such quasi-constant
+ values in Dwarf, so for now we just punt and generate nothing. */
break;
default:
}
static rtx
-rtl_for_decl_location (decl)
- tree decl;
+rtl_for_decl_location (tree decl)
{
rtx rtl;
rtl = DECL_RTL_IF_SET (decl);
/* When generating abstract instances, ignore everything except
- constants and symbols living in memory. */
+ constants, symbols living in memory, and symbols living in
+ fixed registers. */
if (! reload_completed)
{
if (rtl
&& (CONSTANT_P (rtl)
|| (GET_CODE (rtl) == MEM
- && CONSTANT_P (XEXP (rtl, 0)))))
+ && CONSTANT_P (XEXP (rtl, 0)))
+ || (GET_CODE (rtl) == REG
+ && TREE_CODE (decl) == VAR_DECL
+ && TREE_STATIC (decl))))
{
-#ifdef ASM_SIMPLIFY_DWARF_ADDR
- rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
-#endif
+ rtl = (*targetm.delegitimize_address) (rtl);
return rtl;
}
rtl = NULL_RTX;
}
}
-#ifdef ASM_SIMPLIFY_DWARF_ADDR
if (rtl)
- rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
-#endif
+ rtl = (*targetm.delegitimize_address) (rtl);
+
+ /* If we don't look past the constant pool, we risk emitting a
+ reference to a constant pool entry that isn't referenced from
+ code, and thus is not emitted. */
+ if (rtl)
+ rtl = avoid_constant_pool_reference (rtl);
+
return rtl;
}
-/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value
+/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
data attribute for a variable or a parameter. We generate the
DW_AT_const_value attribute only in those cases where the given variable
or parameter does not have a true "location" either in memory or in a
function call evaluates to a compile-time constant address. */
static void
-add_location_or_const_value_attribute (die, decl)
- dw_die_ref die;
- tree decl;
+add_location_or_const_value_attribute (dw_die_ref die, tree decl)
{
rtx rtl;
+ dw_loc_descr_ref descr;
if (TREE_CODE (decl) == ERROR_MARK)
return;
if (rtl == NULL_RTX)
return;
- /* If we don't look past the constant pool, we risk emitting a
- reference to a constant pool entry that isn't referenced from
- code, and thus is not emitted. */
- rtl = avoid_constant_pool_reference (rtl);
-
switch (GET_CODE (rtl))
{
case ADDRESSOF:
- /* The address of a variable that was optimized away; don't emit
- anything. */
+ /* The address of a variable that was optimized away;
+ don't emit anything. */
break;
case CONST_INT:
break;
case MEM:
- case REG:
- case SUBREG:
- case CONCAT:
- add_AT_location_description (die, DW_AT_location, rtl);
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ {
+ /* Need loc_descriptor_from_tree since that's where we know
+ how to handle TLS variables. Want the object's address
+ since the top-level DW_AT_location assumes such. See
+ the confusion in loc_descriptor for reference. */
+ descr = loc_descriptor_from_tree (decl, 1);
+ }
+ else
+ {
+ case REG:
+ case SUBREG:
+ case CONCAT:
+ descr = loc_descriptor (rtl);
+ }
+ add_AT_location_description (die, DW_AT_location, descr);
break;
default:
we should tell the debugger about the constant value. */
static void
-tree_add_const_value_attribute (var_die, decl)
- dw_die_ref var_die;
- tree decl;
+tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
{
tree init = DECL_INITIAL (decl);
tree type = TREE_TYPE (decl);
}
}
-/* Generate an DW_AT_name attribute given some string value to be included as
+/* Generate a DW_AT_name attribute given some string value to be included as
the value of the attribute. */
-static inline void
-add_name_attribute (die, name_string)
- dw_die_ref die;
- const char *name_string;
+static void
+add_name_attribute (dw_die_ref die, const char *name_string)
{
if (name_string != NULL && *name_string != 0)
{
}
}
+/* Generate a DW_AT_comp_dir attribute for DIE. */
+
+static void
+add_comp_dir_attribute (dw_die_ref die)
+{
+ const char *wd = get_src_pwd ();
+ if (wd != NULL)
+ add_AT_string (die, DW_AT_comp_dir, wd);
+}
+
/* Given a tree node describing an array bound (either lower or upper) output
a representation for that bound. */
static void
-add_bound_info (subrange_die, bound_attr, bound)
- dw_die_ref subrange_die;
- enum dwarf_attribute bound_attr;
- tree bound;
+add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
{
switch (TREE_CODE (bound))
{
case SAVE_EXPR:
/* If optimization is turned on, the SAVE_EXPRs that describe how to
- access the upper bound values may be bogus. If they refer to a
- register, they may only describe how to get at these values at the
- points in the generated code right after they have just been
- computed. Worse yet, in the typical case, the upper bound values
- will not even *be* computed in the optimized code (though the
- number of elements will), so these SAVE_EXPRs are entirely
- bogus. In order to compensate for this fact, we check here to see
- if optimization is enabled, and if so, we don't add an attribute
- for the (unknown and unknowable) upper bound. This should not
- cause too much trouble for existing (stupid?) debuggers because
- they have to deal with empty upper bounds location descriptions
- anyway in order to be able to deal with incomplete array types.
- Of course an intelligent debugger (GDB?) should be able to
- comprehend that a missing upper bound specification in an array
- type used for a storage class `auto' local array variable
- indicates that the upper bound is both unknown (at compile- time)
- and unknowable (at run-time) due to optimization.
+ access the upper bound values may be bogus. If they refer to a
+ register, they may only describe how to get at these values at the
+ points in the generated code right after they have just been
+ computed. Worse yet, in the typical case, the upper bound values
+ will not even *be* computed in the optimized code (though the
+ number of elements will), so these SAVE_EXPRs are entirely
+ bogus. In order to compensate for this fact, we check here to see
+ if optimization is enabled, and if so, we don't add an attribute
+ for the (unknown and unknowable) upper bound. This should not
+ cause too much trouble for existing (stupid?) debuggers because
+ they have to deal with empty upper bounds location descriptions
+ anyway in order to be able to deal with incomplete array types.
+ Of course an intelligent debugger (GDB?) should be able to
+ comprehend that a missing upper bound specification in an array
+ type used for a storage class `auto' local array variable
+ indicates that the upper bound is both unknown (at compile- time)
+ and unknowable (at run-time) due to optimization.
We assume that a MEM rtx is safe because gcc wouldn't put the
value there unless it was going to be used repeatedly in the
add_AT_flag (decl_die, DW_AT_artificial, 1);
add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
- add_AT_location_description (decl_die, DW_AT_location, loc);
+ add_AT_location_description (decl_die, DW_AT_location,
+ loc_descriptor (loc));
add_AT_die_ref (subrange_die, bound_attr, decl_die);
}
includes information about the element type of type given array type. */
static void
-add_subscript_info (type_die, type)
- dw_die_ref type_die;
- tree type;
+add_subscript_info (dw_die_ref type_die, tree type)
{
#ifndef MIPS_DEBUGGING_INFO
unsigned dimension_number;
/* Arrays come in three flavors: Unspecified bounds, fixed bounds,
and (in GNU C only) variable bounds. Handle all three forms
- here. */
+ here. */
subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
if (domain)
{
lower = TYPE_MIN_VALUE (domain);
upper = TYPE_MAX_VALUE (domain);
- /* define the index type. */
+ /* Define the index type. */
if (TREE_TYPE (domain))
{
/* ??? This is probably an Ada unnamed subrange type. Ignore the
/* ??? If upper is NULL, the array has unspecified length,
but it does have a lower bound. This happens with Fortran
dimension arr(N:*)
- Since the debugger is definitely going to need to know N
+ Since the debugger is definitely going to need to know N
to produce useful results, go ahead and output the lower
bound solo, and hope the debugger can cope. */
}
static void
-add_byte_size_attribute (die, tree_node)
- dw_die_ref die;
- tree tree_node;
+add_byte_size_attribute (dw_die_ref die, tree tree_node)
{
unsigned size;
break;
case FIELD_DECL:
/* For a data member of a struct or union, the DW_AT_byte_size is
- generally given as the number of bytes normally allocated for an
- object of the *declared* type of the member itself. This is true
- even for bit-fields. */
+ generally given as the number of bytes normally allocated for an
+ object of the *declared* type of the member itself. This is true
+ even for bit-fields. */
size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
break;
default:
(See `byte_size_attribute' above). */
static inline void
-add_bit_offset_attribute (die, decl)
- dw_die_ref die;
- tree decl;
+add_bit_offset_attribute (dw_die_ref die, tree decl)
{
HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl);
tree type = DECL_BIT_FIELD_TYPE (decl);
which specifies the length in bits of the given field. */
static inline void
-add_bit_size_attribute (die, decl)
- dw_die_ref die;
- tree decl;
+add_bit_size_attribute (dw_die_ref die, tree decl)
{
/* Must be a field and a bit field. */
if (TREE_CODE (decl) != FIELD_DECL
attribute, if arg types are given for the parameters of a function. */
static inline void
-add_prototyped_attribute (die, func_type)
- dw_die_ref die;
- tree func_type;
+add_prototyped_attribute (dw_die_ref die, tree func_type)
{
if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
&& TYPE_ARG_TYPES (func_type) != NULL)
equate table. */
static inline void
-add_abstract_origin_attribute (die, origin)
- dw_die_ref die;
- tree origin;
+add_abstract_origin_attribute (dw_die_ref die, tree origin)
{
dw_die_ref origin_die = NULL;
function, if we're in an exception handler or some such; make
sure that the abstract function has been written out.
- Doing this for nested functions is wrong, however; functions are
+ Doing this for nested functions is wrong, however; functions are
distinct units, and our context might not even be inline. */
tree fn = origin;
/* We do not currently support the pure_virtual attribute. */
static inline void
-add_pure_or_virtual_attribute (die, func_decl)
- dw_die_ref die;
- tree func_decl;
+add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
{
if (DECL_VINDEX (func_decl))
{
/* Add source coordinate attributes for the given decl. */
static void
-add_src_coords_attributes (die, decl)
- dw_die_ref die;
- tree decl;
+add_src_coords_attributes (dw_die_ref die, tree decl)
{
unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
}
-/* Add an DW_AT_name attribute and source coordinate attribute for the
+/* Add a DW_AT_name attribute and source coordinate attribute for the
given decl, but only if it actually has a name. */
static void
-add_name_and_src_coords_attributes (die, decl)
- dw_die_ref die;
- tree decl;
+add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
{
tree decl_name;
/* Push a new declaration scope. */
static void
-push_decl_scope (scope)
- tree scope;
+push_decl_scope (tree scope)
{
VARRAY_PUSH_TREE (decl_scope_table, scope);
}
/* Pop a declaration scope. */
static inline void
-pop_decl_scope ()
+pop_decl_scope (void)
{
if (VARRAY_ACTIVE_SIZE (decl_scope_table) <= 0)
abort ();
the current active scope. */
static dw_die_ref
-scope_die_for (t, context_die)
- tree t;
- dw_die_ref context_die;
+scope_die_for (tree t, dw_die_ref context_die)
{
dw_die_ref scope_die = NULL;
tree containing_scope;
/* Returns nonzero if CONTEXT_DIE is internal to a function. */
static inline int
-local_scope_p (context_die)
- dw_die_ref context_die;
+local_scope_p (dw_die_ref context_die)
{
for (; context_die; context_die = context_die->die_parent)
if (context_die->die_tag == DW_TAG_inlined_subroutine
/* Returns nonzero if CONTEXT_DIE is a class. */
static inline int
-class_scope_p (context_die)
- dw_die_ref context_die;
+class_scope_p (dw_die_ref context_die)
{
return (context_die
&& (context_die->die_tag == DW_TAG_structure_type
/* Many forms of DIEs require a "type description" attribute. This
routine locates the proper "type descriptor" die for the type given
- by 'type', and adds an DW_AT_type attribute below the given die. */
+ by 'type', and adds a DW_AT_type attribute below the given die. */
static void
-add_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
- dw_die_ref object_die;
- tree type;
- int decl_const;
- int decl_volatile;
- dw_die_ref context_die;
+add_type_attribute (dw_die_ref object_die, tree type, int decl_const,
+ int decl_volatile, dw_die_ref context_die)
{
enum tree_code code = TREE_CODE (type);
dw_die_ref type_die = NULL;
was declared without a tag. */
static const char *
-type_tag (type)
- tree type;
+type_tag (tree type)
{
const char *name = 0;
t = TYPE_NAME (type);
/* The g++ front end makes the TYPE_NAME of *each* tagged type point to
- a TYPE_DECL node, regardless of whether or not a `typedef' was
- involved. */
+ a TYPE_DECL node, regardless of whether or not a `typedef' was
+ involved. */
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ! DECL_IGNORED_P (TYPE_NAME (type)))
t = DECL_NAME (TYPE_NAME (type));
for bit field types. */
static inline tree
-member_declared_type (member)
- tree member;
+member_declared_type (tree member)
{
return (DECL_BIT_FIELD_TYPE (member)
? DECL_BIT_FIELD_TYPE (member) : TREE_TYPE (member));
#if 0
static const char *
-decl_start_label (decl)
- tree decl;
+decl_start_label (tree decl)
{
rtx x;
const char *fnname;
the declaration trees passed in from dwarf2out_decl(). */
static void
-gen_array_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_array_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref scope_die = scope_die_for (type, context_die);
dw_die_ref array_die;
}
static void
-gen_set_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_set_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die
= new_die (DW_TAG_set_type, scope_die_for (type, context_die), type);
#if 0
static void
-gen_entry_point_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_entry_point_die (tree decl, dw_die_ref context_die)
{
tree origin = decl_ultimate_origin (decl);
dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die, decl);
emit full debugging info for them. */
static void
-retry_incomplete_types ()
+retry_incomplete_types (void)
{
int i;
/* Generate a DIE to represent an inlined instance of an enumeration type. */
static void
-gen_inlined_enumeration_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_inlined_enumeration_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = new_die (DW_TAG_enumeration_type, context_die, type);
/* Generate a DIE to represent an inlined instance of a structure type. */
static void
-gen_inlined_structure_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_inlined_structure_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = new_die (DW_TAG_structure_type, context_die, type);
/* Generate a DIE to represent an inlined instance of a union type. */
static void
-gen_inlined_union_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_inlined_union_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = new_die (DW_TAG_union_type, context_die, type);
DIE. */
static void
-gen_enumeration_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_enumeration_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = lookup_type_die (type);
add_name_attribute (enum_die,
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
- if (host_integerp (TREE_VALUE (link), 0))
+ if (host_integerp (TREE_VALUE (link),
+ TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (link)))))
{
if (tree_int_cst_sgn (TREE_VALUE (link)) < 0)
add_AT_int (enum_die, DW_AT_const_value,
tree_low_cst (TREE_VALUE (link), 0));
else
add_AT_unsigned (enum_die, DW_AT_const_value,
- tree_low_cst (TREE_VALUE (link), 0));
+ tree_low_cst (TREE_VALUE (link), 1));
}
}
}
argument type of some subprogram type. */
static dw_die_ref
-gen_formal_parameter_die (node, context_die)
- tree node;
- dw_die_ref context_die;
+gen_formal_parameter_die (tree node, dw_die_ref context_die)
{
dw_die_ref parm_die
= new_die (DW_TAG_formal_parameter, context_die, node);
at the end of an (ANSI prototyped) formal parameters list. */
static void
-gen_unspecified_parameters_die (decl_or_type, context_die)
- tree decl_or_type;
- dw_die_ref context_die;
+gen_unspecified_parameters_die (tree decl_or_type, dw_die_ref context_die)
{
new_die (DW_TAG_unspecified_parameters, context_die, decl_or_type);
}
those which appear as part of a function *definition*). */
static void
-gen_formal_types_die (function_or_method_type, context_die)
- tree function_or_method_type;
- dw_die_ref context_die;
+gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
{
tree link;
tree formal_type = NULL;
trick; we need to attach the member declaration by hand. */
static void
-gen_type_die_for_member (type, member, context_die)
- tree type, member;
- dw_die_ref context_die;
+gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
{
gen_type_die (type, context_die);
may later generate inlined and/or out-of-line instances of. */
static void
-dwarf2out_abstract_function (decl)
- tree decl;
+dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
tree save_fn;
decl = DECL_ORIGIN (decl);
old_die = lookup_decl_die (decl);
- if (old_die && get_AT_unsigned (old_die, DW_AT_inline))
+ if (old_die && get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
block-local). */
static void
-gen_subprogram_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_subprogram_die (tree decl, dw_die_ref context_die)
{
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
tree origin = decl_ultimate_origin (decl);
/* We can have a normal definition following an inline one in the
case of redefinition of GNU C extern inlines.
It seems reasonable to use AT_specification in this case. */
- && !get_AT_unsigned (old_die, DW_AT_inline))
+ && !get_AT (old_die, DW_AT_inline))
{
/* ??? This can happen if there is a bug in the program, for
instance, if it has duplicate function definitions. Ideally,
if (declaration)
{
- if (!old_die || !get_AT_unsigned (old_die, DW_AT_inline))
+ if (!old_die || !get_AT (old_die, DW_AT_inline))
{
add_AT_flag (subr_die, DW_AT_declaration, 1);
}
else if (DECL_ABSTRACT (decl))
{
- if (DECL_INLINE (decl) && !flag_no_inline)
+ if (DECL_DECLARED_INLINE_P (decl))
{
- /* ??? Checking DECL_DEFER_OUTPUT is correct for static
- inline functions, but not for extern inline functions.
- We can't get this completely correct because information
- about whether the function was declared inline is not
- saved anywhere. */
- if (DECL_DEFER_OUTPUT (decl))
+ if (cgraph_function_possibly_inlined_p (decl))
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
else
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
}
else
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
+ {
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+ else
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
+ }
equate_decl_number_to_die (decl, subr_die);
}
else if (!DECL_EXTERNAL (decl))
{
- if (!old_die || !get_AT_unsigned (old_die, DW_AT_inline))
+ if (!old_die || !get_AT (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
#endif
/* Define the "frame base" location for this routine. We use the
- frame pointer or stack pointer registers, since the RTL for local
- variables is relative to one of them. */
+ frame pointer or stack pointer registers, since the RTL for local
+ variables is relative to one of them. */
fp_reg
= frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
is not part of the state saved/restored for inline functions. */
if (current_function_needs_context)
add_AT_location_description (subr_die, DW_AT_static_link,
- lookup_static_chain (decl));
+ loc_descriptor (lookup_static_chain (decl)));
#endif
}
gen_formal_types_die (decl, subr_die);
else
{
- /* Generate DIEs to represent all known formal parameters */
+ /* Generate DIEs to represent all known formal parameters. */
tree arg_decls = DECL_ARGUMENTS (decl);
tree parm;
/* When generating DIEs, generate the unspecified_parameters DIE
- instead if we come across the arg "__builtin_va_alist" */
+ instead if we come across the arg "__builtin_va_alist" */
for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
if (TREE_CODE (parm) == PARM_DECL)
{
}
/* Decide whether we need an unspecified_parameters DIE at the end.
- There are 2 more cases to do this for: 1) the ansi ... declaration -
- this is detectable when the end of the arg list is not a
- void_type_node 2) an unprototyped function declaration (not a
- definition). This just means that we have no info about the
- parameters at all. */
+ There are 2 more cases to do this for: 1) the ansi ... declaration -
+ this is detectable when the end of the arg list is not a
+ void_type_node 2) an unprototyped function declaration (not a
+ definition). This just means that we have no info about the
+ parameters at all. */
fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (fn_arg_types != NULL)
{
- /* this is the prototyped case, check for ... */
+ /* This is the prototyped case, check for.... */
if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
gen_unspecified_parameters_die (decl, subr_die);
}
/* Generate a DIE to represent a declared data object. */
static void
-gen_variable_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_variable_die (tree decl, dw_die_ref context_die)
{
tree origin = decl_ultimate_origin (decl);
dw_die_ref var_die = new_die (DW_TAG_variable, context_die, decl);
/* Generate a DIE to represent a label identifier. */
static void
-gen_label_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_label_die (tree decl, dw_die_ref context_die)
{
tree origin = decl_ultimate_origin (decl);
dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
insn = DECL_RTL (decl);
/* Deleted labels are programmer specified labels which have been
- eliminated because of various optimisations. We still emit them
+ eliminated because of various optimizations. We still emit them
here so that it is possible to put breakpoints on them. */
if (GET_CODE (insn) == CODE_LABEL
|| ((GET_CODE (insn) == NOTE
/* Generate a DIE for a lexical block. */
static void
-gen_lexical_block_die (stmt, context_die, depth)
- tree stmt;
- dw_die_ref context_die;
- int depth;
+gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
{
dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
/* Generate a DIE for an inlined subprogram. */
static void
-gen_inlined_subroutine_die (stmt, context_die, depth)
- tree stmt;
- dw_die_ref context_die;
- int depth;
+gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
{
+ tree decl = block_ultimate_origin (stmt);
+
+ /* Emit info for the abstract instance first, if we haven't yet. We
+ must emit this even if the block is abstract, otherwise when we
+ emit the block below (or elsewhere), we may end up trying to emit
+ a die whose origin die hasn't been emitted, and crashing. */
+ dwarf2out_abstract_function (decl);
+
if (! BLOCK_ABSTRACT (stmt))
{
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
- tree decl = block_ultimate_origin (stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- /* Emit info for the abstract instance first, if we haven't yet. */
- dwarf2out_abstract_function (decl);
-
add_abstract_origin_attribute (subr_die, decl);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
/* Generate a DIE for a field in a record, or structure. */
static void
-gen_field_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_field_die (tree decl, dw_die_ref context_die)
{
- dw_die_ref decl_die = new_die (DW_TAG_member, context_die, decl);
+ dw_die_ref decl_die;
+
+ if (TREE_TYPE (decl) == error_mark_node)
+ return;
+ decl_die = new_die (DW_TAG_member, context_die, decl);
add_name_and_src_coords_attributes (decl_die, decl);
add_type_attribute (decl_die, member_declared_type (decl),
TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
represent certain things in other languages (e.g. Pascal) someday. */
static void
-gen_pointer_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_pointer_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref ptr_die
= new_die (DW_TAG_pointer_type, scope_die_for (type, context_die), type);
represent certain things in other languages (e.g. Pascal) someday. */
static void
-gen_reference_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_reference_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref ref_die
= new_die (DW_TAG_reference_type, scope_die_for (type, context_die), type);
/* Generate a DIE for a pointer to a member type. */
static void
-gen_ptr_to_mbr_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref ptr_die
= new_die (DW_TAG_ptr_to_member_type,
/* Generate the DIE for the compilation unit. */
static dw_die_ref
-gen_compile_unit_die (filename)
- const char *filename;
+gen_compile_unit_die (const char *filename)
{
dw_die_ref die;
char producer[250];
- const char *wd = getpwd ();
const char *language_string = lang_hooks.name;
int language;
die = new_die (DW_TAG_compile_unit, NULL, NULL);
- add_name_attribute (die, filename);
- if (wd != NULL && filename[0] != DIR_SEPARATOR)
- add_AT_string (die, DW_AT_comp_dir, wd);
+ if (filename)
+ {
+ add_name_attribute (die, filename);
+ /* Don't add cwd for <built-in>. */
+ if (filename[0] != DIR_SEPARATOR && filename[0] != '<')
+ add_comp_dir_attribute (die);
+ }
sprintf (producer, "%s %s", language_string, version_string);
if (strcmp (language_string, "GNU C++") == 0)
language = DW_LANG_C_plus_plus;
else if (strcmp (language_string, "GNU Ada") == 0)
- language = DW_LANG_Ada83;
+ language = DW_LANG_Ada95;
else if (strcmp (language_string, "GNU F77") == 0)
language = DW_LANG_Fortran77;
else if (strcmp (language_string, "GNU Pascal") == 0)
/* Generate a DIE for a string type. */
static void
-gen_string_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_string_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die
= new_die (DW_TAG_string_type, scope_die_for (type, context_die), type);
/* Generate the DIE for a base class. */
static void
-gen_inheritance_die (binfo, context_die)
- tree binfo;
- dw_die_ref context_die;
+gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
{
dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
if (TREE_VIA_VIRTUAL (binfo))
add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
- if (TREE_VIA_PUBLIC (binfo))
+ if (access == access_public_node)
add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
- else if (TREE_VIA_PROTECTED (binfo))
+ else if (access == access_protected_node)
add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
}
/* Generate a DIE for a class member. */
static void
-gen_member_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_member_die (tree type, dw_die_ref context_die)
{
tree member;
+ tree binfo = TYPE_BINFO (type);
dw_die_ref child;
/* If this is not an incomplete type, output descriptions of each of its
the TREE node representing the appropriate (containing) type. */
/* First output info about the base classes. */
- if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
+ if (binfo && BINFO_BASETYPES (binfo))
{
- tree bases = TYPE_BINFO_BASETYPES (type);
+ tree bases = BINFO_BASETYPES (binfo);
+ tree accesses = BINFO_BASEACCESSES (binfo);
int n_bases = TREE_VEC_LENGTH (bases);
int i;
for (i = 0; i < n_bases; i++)
- gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die);
+ gen_inheritance_die (TREE_VEC_ELT (bases, i),
+ (accesses ? TREE_VEC_ELT (accesses, i)
+ : access_public_node), context_die);
}
/* Now output info about the data members and type members. */
member DIEs needed by later specification DIEs. */
static void
-gen_struct_or_union_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_struct_or_union_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = lookup_type_die (type);
dw_die_ref scope_die = 0;
if (complete)
{
/* Prevent infinite recursion in cases where the type of some member of
- this type is expressed in terms of this type itself. */
+ this type is expressed in terms of this type itself. */
TREE_ASM_WRITTEN (type) = 1;
add_byte_size_attribute (type_die, type);
if (TYPE_STUB_DECL (type) != NULL_TREE)
/* Generate a DIE for a subroutine _type_. */
static void
-gen_subroutine_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_subroutine_type_die (tree type, dw_die_ref context_die)
{
tree return_type = TREE_TYPE (type);
dw_die_ref subr_die
gen_formal_types_die (type, subr_die);
}
-/* Generate a DIE for a type definition */
+/* Generate a DIE for a type definition. */
static void
-gen_typedef_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_typedef_die (tree decl, dw_die_ref context_die)
{
dw_die_ref type_die;
tree origin;
/* Generate a type description DIE. */
static void
-gen_type_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_type_die (tree type, dw_die_ref context_die)
{
int need_pop;
if (type == NULL_TREE || type == error_mark_node)
return;
- /* We are going to output a DIE to represent the unqualified version
- of this type (i.e. without any const or volatile qualifiers) so
- get the main variant (i.e. the unqualified version) of this type
- now. (Vectors are special because the debugging info is in the
- cloned type itself). */
- if (TREE_CODE (type) != VECTOR_TYPE)
- type = type_main_variant (type);
-
- if (TREE_ASM_WRITTEN (type))
- return;
-
if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
{
+ if (TREE_ASM_WRITTEN (type))
+ return;
+
/* Prevent broken recursion; we can't hand off to the same type. */
if (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) == type)
abort ();
return;
}
+ /* We are going to output a DIE to represent the unqualified version
+ of this type (i.e. without any const or volatile qualifiers) so
+ get the main variant (i.e. the unqualified version) of this type
+ now. (Vectors are special because the debugging info is in the
+ cloned type itself). */
+ if (TREE_CODE (type) != VECTOR_TYPE)
+ type = type_main_variant (type);
+
+ if (TREE_ASM_WRITTEN (type))
+ return;
+
switch (TREE_CODE (type))
{
case ERROR_MARK:
TREE_ASM_WRITTEN (type) = 1;
/* For these types, all that is required is that we output a DIE (or a
- set of DIEs) to represent the "basis" type. */
+ set of DIEs) to represent the "basis" type. */
gen_type_die (TREE_TYPE (type), context_die);
break;
gen_type_die (TREE_TYPE (type), context_die);
/* Now output a DIE to represent this pointer-to-data-member type
- itself. */
+ itself. */
gen_ptr_to_mbr_type_die (type, context_die);
break;
case UNION_TYPE:
case QUAL_UNION_TYPE:
/* If this is a nested type whose containing class hasn't been written
- out yet, writing it out will cover this one, too. This does not apply
- to instantiations of member class templates; they need to be added to
- the containing class as they are generated. FIXME: This hurts the
- idea of combining type decls from multiple TUs, since we can't predict
- what set of template instantiations we'll get. */
+ out yet, writing it out will cover this one, too. This does not apply
+ to instantiations of member class templates; they need to be added to
+ the containing class as they are generated. FIXME: This hurts the
+ idea of combining type decls from multiple TUs, since we can't predict
+ what set of template instantiations we'll get. */
if (TYPE_CONTEXT (type)
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
/* Generate a DIE for a tagged type instantiation. */
static void
-gen_tagged_type_instantiation_die (type, context_die)
- tree type;
- dw_die_ref context_die;
+gen_tagged_type_instantiation_die (tree type, dw_die_ref context_die)
{
if (type == NULL_TREE || type == error_mark_node)
return;
things which are local to the given block. */
static void
-gen_block_die (stmt, context_die, depth)
- tree stmt;
- dw_die_ref context_die;
- int depth;
+gen_block_die (tree stmt, dw_die_ref context_die, int depth)
{
int must_output_die = 0;
tree origin;
else
{
/* In the case where the current block represents an inlining of the
- "body block" of an inline function, we must *NOT* output any DIE for
- this block because we have already output a DIE to represent the whole
- inlined function scope and the "body block" of any function doesn't
- really represent a different scope according to ANSI C rules. So we
- check here to make sure that this block does not represent a "body
- block inlining" before trying to set the MUST_OUTPUT_DIE flag. */
+ "body block" of an inline function, we must *NOT* output any DIE for
+ this block because we have already output a DIE to represent the whole
+ inlined function scope and the "body block" of any function doesn't
+ really represent a different scope according to ANSI C rules. So we
+ check here to make sure that this block does not represent a "body
+ block inlining" before trying to set the MUST_OUTPUT_DIE flag. */
if (! is_body_block (origin ? origin : stmt))
{
/* Determine if this block directly contains any "significant"
all of its sub-blocks. */
static void
-decls_for_scope (stmt, context_die, depth)
- tree stmt;
- dw_die_ref context_die;
- int depth;
+decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
{
tree decl;
tree subblocks;
gen_decl_die (decl, context_die);
}
+ /* If we're at -g1, we're not interested in subblocks. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
/* Output the DIEs to represent all sub-blocks (and the items declared
therein) of this block. */
for (subblocks = BLOCK_SUBBLOCKS (stmt);
/* Is this a typedef we can avoid emitting? */
static inline int
-is_redundant_typedef (decl)
- tree decl;
+is_redundant_typedef (tree decl)
{
if (TYPE_DECL_IS_STUB (decl))
return 1;
/* Generate Dwarf debug information for a decl described by DECL. */
static void
-gen_decl_die (decl, context_die)
- tree decl;
- dw_die_ref context_die;
+gen_decl_die (tree decl, dw_die_ref context_die)
{
tree origin;
case CONST_DECL:
/* The individual enumerators of an enum type get output when we output
- the Dwarf representation of the relevant enum type itself. */
+ the Dwarf representation of the relevant enum type itself. */
break;
case FUNCTION_DECL:
/* If we're emitting an out-of-line copy of an inline function,
emit info for the abstract instance and set up to refer to it. */
- else if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl)
+ else if (cgraph_function_possibly_inlined_p (decl)
+ && ! DECL_ABSTRACT (decl)
&& ! class_scope_p (context_die)
/* dwarf2out_abstract_function won't emit a die if this is just
a declaration. We must avoid setting DECL_ABSTRACT_ORIGIN in
case TYPE_DECL:
/* If we are in terse mode, don't generate any DIEs to represent any
- actual typedefs. */
+ actual typedefs. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
/* In the special case of a TYPE_DECL node representing the declaration
- of some type tag, if the given TYPE_DECL is marked as having been
- instantiated from some other (original) TYPE_DECL node (e.g. one which
- was generated within the original definition of an inline function) we
- have to generate a special (abbreviated) DW_TAG_structure_type,
- DW_TAG_union_type, or DW_TAG_enumeration_type DIE here. */
+ of some type tag, if the given TYPE_DECL is marked as having been
+ instantiated from some other (original) TYPE_DECL node (e.g. one which
+ was generated within the original definition of an inline function) we
+ have to generate a special (abbreviated) DW_TAG_structure_type,
+ DW_TAG_union_type, or DW_TAG_enumeration_type DIE here. */
if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
{
gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
case VAR_DECL:
/* If we are in terse mode, don't generate any DIEs to represent any
- variable declarations or definitions. */
+ variable declarations or definitions. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
/* Output any DIEs that are needed to specify the type of this data
- object. */
+ object. */
gen_type_die (TREE_TYPE (decl), context_die);
/* And its containing type. */
gen_type_die_for_member (origin, decl, context_die);
/* Now output the DIE to represent the data object itself. This gets
- complicated because of the possibility that the VAR_DECL really
- represents an inlined instance of a formal parameter for an inline
- function. */
+ complicated because of the possibility that the VAR_DECL really
+ represents an inlined instance of a formal parameter for an inline
+ function. */
origin = decl_ultimate_origin (decl);
if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
gen_formal_parameter_die (decl, context_die);
break;
default:
+ if ((int)TREE_CODE (decl) > NUM_TREE_CODES)
+ /* Probably some frontend-internal decl. Assume we don't care. */
+ break;
abort ();
}
}
-
-static void
-mark_limbo_die_list (ptr)
- void *ptr ATTRIBUTE_UNUSED;
-{
- limbo_die_node *node;
- for (node = limbo_die_list; node; node = node->next)
- ggc_mark_tree (node->created_for);
-}
\f
/* Add Ada "use" clause information for SGI Workshop debugger. */
void
-dwarf2out_add_library_unit_info (filename, context_list)
- const char *filename;
- const char *context_list;
+dwarf2out_add_library_unit_info (const char *filename, const char *context_list)
{
unsigned int file_index;
compilation proper has finished. */
static void
-dwarf2out_global_decl (decl)
- tree decl;
+dwarf2out_global_decl (tree decl)
{
/* Output DWARF2 information for file-scope tentative data object
declarations, file-scope (extern) function declarations (which had no
/* Write the debugging output for DECL. */
void
-dwarf2out_decl (decl)
- tree decl;
+dwarf2out_decl (tree decl)
{
dw_die_ref context_die = comp_unit_die;
case FUNCTION_DECL:
/* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
- builtin function. Explicit programmer-supplied declarations of
- these same functions should NOT be ignored however. */
+ builtin function. Explicit programmer-supplied declarations of
+ these same functions should NOT be ignored however. */
if (DECL_EXTERNAL (decl) && DECL_BUILT_IN (decl))
return;
/* What we would really like to do here is to filter out all mere
- file-scope declarations of file-scope functions which are never
- referenced later within this translation unit (and keep all of ones
- that *are* referenced later on) but we aren't clairvoyant, so we have
- no idea which functions will be referenced in the future (i.e. later
- on within the current translation unit). So here we just ignore all
- file-scope function declarations which are not also definitions. If
- and when the debugger needs to know something about these functions,
- it will have to hunt around and find the DWARF information associated
- with the definition of the function.
+ file-scope declarations of file-scope functions which are never
+ referenced later within this translation unit (and keep all of ones
+ that *are* referenced later on) but we aren't clairvoyant, so we have
+ no idea which functions will be referenced in the future (i.e. later
+ on within the current translation unit). So here we just ignore all
+ file-scope function declarations which are not also definitions. If
+ and when the debugger needs to know something about these functions,
+ it will have to hunt around and find the DWARF information associated
+ with the definition of the function.
We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
- nodes represent definitions and which ones represent mere
- declarations. We have to check DECL_INITIAL instead. That's because
- the C front-end supports some weird semantics for "extern inline"
- function definitions. These can get inlined within the current
- translation unit (an thus, we need to generate Dwarf info for their
- abstract instances so that the Dwarf info for the concrete inlined
- instances can have something to refer to) but the compiler never
- generates any out-of-lines instances of such things (despite the fact
- that they *are* definitions).
+ nodes represent definitions and which ones represent mere
+ declarations. We have to check DECL_INITIAL instead. That's because
+ the C front-end supports some weird semantics for "extern inline"
+ function definitions. These can get inlined within the current
+ translation unit (an thus, we need to generate Dwarf info for their
+ abstract instances so that the Dwarf info for the concrete inlined
+ instances can have something to refer to) but the compiler never
+ generates any out-of-lines instances of such things (despite the fact
+ that they *are* definitions).
The important point is that the C front-end marks these "extern
inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
/* If we're a nested function, initially use a parent of NULL; if we're
a plain function, this will be fixed up in decls_for_scope. If
we're a method, it will be ignored, since we already have a DIE. */
- if (decl_function_context (decl))
+ if (decl_function_context (decl)
+ /* But if we're in terse mode, we don't care about scope. */
+ && debug_info_level > DINFO_LEVEL_TERSE)
context_die = NULL;
break;
case VAR_DECL:
/* Ignore this VAR_DECL if it refers to a file-scope extern data object
- declaration and if the declaration was never even referenced from
- within this entire compilation unit. We suppress these DIEs in
- order to save space in the .debug section (by eliminating entries
- which are probably useless). Note that we must not suppress
- block-local extern declarations (whether used or not) because that
- would screw-up the debugger's name lookup mechanism and cause it to
- miss things which really ought to be in scope at a given point. */
+ declaration and if the declaration was never even referenced from
+ within this entire compilation unit. We suppress these DIEs in
+ order to save space in the .debug section (by eliminating entries
+ which are probably useless). Note that we must not suppress
+ block-local extern declarations (whether used or not) because that
+ would screw-up the debugger's name lookup mechanism and cause it to
+ miss things which really ought to be in scope at a given point. */
if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
return;
/* If we are in terse mode, don't generate any DIEs to represent any
- variable declarations or definitions. */
+ variable declarations or definitions. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
break;
return;
/* Don't bother trying to generate any DIEs to represent any of the
- normal built-in types for the language we are compiling. */
+ normal built-in types for the language we are compiling. */
if (DECL_SOURCE_LINE (decl) == 0)
{
/* OK, we need to generate one for `bool' so GDB knows what type
- comparisons have. */
+ comparisons have. */
if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
== DW_LANG_C_plus_plus)
&& TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
a lexical block. */
static void
-dwarf2out_begin_block (line, blocknum)
- unsigned int line ATTRIBUTE_UNUSED;
- unsigned int blocknum;
+dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
+ unsigned int blocknum)
{
function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
lexical block. */
static void
-dwarf2out_end_block (line, blocknum)
- unsigned int line ATTRIBUTE_UNUSED;
- unsigned int blocknum;
+dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
we may end up calling them anyway. */
static bool
-dwarf2out_ignore_block (block)
- tree block;
+dwarf2out_ignore_block (tree block)
{
tree decl;
all searches. */
static unsigned
-lookup_filename (file_name)
- const char *file_name;
+lookup_filename (const char *file_name)
{
- unsigned i;
-
- /* ??? Why isn't DECL_SOURCE_FILE left null instead. */
- if (strcmp (file_name, "<internal>") == 0
- || strcmp (file_name, "<built-in>") == 0)
- return 0;
+ size_t i, n;
+ char *save_file_name;
/* Check to see if the file name that was searched on the previous
call matches this file name. If so, return the index. */
- if (file_table.last_lookup_index != 0)
- if (0 == strcmp (file_name,
- file_table.table[file_table.last_lookup_index]))
- return file_table.last_lookup_index;
+ if (file_table_last_lookup_index != 0)
+ {
+ const char *last
+ = VARRAY_CHAR_PTR (file_table, file_table_last_lookup_index);
+ if (strcmp (file_name, last) == 0)
+ return file_table_last_lookup_index;
+ }
/* Didn't match the previous lookup, search the table */
- for (i = 1; i < file_table.in_use; i++)
- if (strcmp (file_name, file_table.table[i]) == 0)
+ n = VARRAY_ACTIVE_SIZE (file_table);
+ for (i = 1; i < n; i++)
+ if (strcmp (file_name, VARRAY_CHAR_PTR (file_table, i)) == 0)
{
- file_table.last_lookup_index = i;
+ file_table_last_lookup_index = i;
return i;
}
- /* Prepare to add a new table entry by making sure there is enough space in
- the table to do so. If not, expand the current table. */
- if (i == file_table.allocated)
- {
- file_table.allocated = i + FILE_TABLE_INCREMENT;
- file_table.table = (char **)
- xrealloc (file_table.table, file_table.allocated * sizeof (char *));
- }
-
/* Add the new entry to the end of the filename table. */
- file_table.table[i] = xstrdup (file_name);
- file_table.in_use = i + 1;
- file_table.last_lookup_index = i;
+ file_table_last_lookup_index = n;
+ save_file_name = (char *) ggc_strdup (file_name);
+ VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
+ VARRAY_PUSH_UINT (file_table_emitted, 0);
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ return i;
+}
+
+static int
+maybe_emit_file (int fileno)
+{
+ if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
{
- fprintf (asm_out_file, "\t.file %u ", i);
- output_quoted_string (asm_out_file, file_name);
- fputc ('\n', asm_out_file);
+ if (!VARRAY_UINT (file_table_emitted, fileno))
+ {
+ VARRAY_UINT (file_table_emitted, fileno) = ++emitcount;
+ fprintf (asm_out_file, "\t.file %u ",
+ VARRAY_UINT (file_table_emitted, fileno));
+ output_quoted_string (asm_out_file,
+ VARRAY_CHAR_PTR (file_table, fileno));
+ fputc ('\n', asm_out_file);
+ }
+ return VARRAY_UINT (file_table_emitted, fileno);
}
-
- return i;
+ else
+ return fileno;
}
static void
-init_file_table ()
+init_file_table (void)
{
/* Allocate the initial hunk of the file_table. */
- file_table.table = (char **) xcalloc (FILE_TABLE_INCREMENT, sizeof (char *));
- file_table.allocated = FILE_TABLE_INCREMENT;
+ VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
+ VARRAY_UINT_INIT (file_table_emitted, 64, "file_table_emitted");
/* Skip the first entry - file numbers begin at 1. */
- file_table.in_use = 1;
- file_table.last_lookup_index = 0;
+ VARRAY_PUSH_CHAR_PTR (file_table, NULL);
+ VARRAY_PUSH_UINT (file_table_emitted, 0);
+ file_table_last_lookup_index = 0;
}
/* Output a label to mark the beginning of a source code line entry
'line_info_table' for later output of the .debug_line section. */
static void
-dwarf2out_source_line (line, filename)
- unsigned int line;
- const char *filename;
+dwarf2out_source_line (unsigned int line, const char *filename)
{
- if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ if (debug_info_level >= DINFO_LEVEL_NORMAL
+ && line != 0)
{
function_section (current_function_decl);
{
unsigned file_num = lookup_filename (filename);
+ file_num = maybe_emit_file (file_num);
+
/* Emit the .loc directive understood by GNU as. */
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
else if (DECL_SECTION_NAME (current_function_decl))
{
dw_separate_line_info_ref line_info;
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
+ (*targetm.asm_out.internal_label) (asm_out_file, SEPARATE_LINE_CODE_LABEL,
separate_line_info_table_in_use);
/* expand the line info table if necessary */
{
separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
separate_line_info_table
- = (dw_separate_line_info_ref)
- xrealloc (separate_line_info_table,
- separate_line_info_table_allocated
- * sizeof (dw_separate_line_info_entry));
+ = ggc_realloc (separate_line_info_table,
+ separate_line_info_table_allocated
+ * sizeof (dw_separate_line_info_entry));
+ memset (separate_line_info_table
+ + separate_line_info_table_in_use,
+ 0,
+ (LINE_INFO_TABLE_INCREMENT
+ * sizeof (dw_separate_line_info_entry)));
}
/* Add the new entry at the end of the line_info_table. */
{
dw_line_info_ref line_info;
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
+ (*targetm.asm_out.internal_label) (asm_out_file, LINE_CODE_LABEL,
line_info_table_in_use);
/* Expand the line info table if necessary. */
{
line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
line_info_table
- = (dw_line_info_ref)
- xrealloc (line_info_table,
- (line_info_table_allocated
- * sizeof (dw_line_info_entry)));
+ = ggc_realloc (line_info_table,
+ (line_info_table_allocated
+ * sizeof (dw_line_info_entry)));
+ memset (line_info_table + line_info_table_in_use, 0,
+ LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
}
/* Add the new entry at the end of the line_info_table. */
/* Record the beginning of a new source file. */
static void
-dwarf2out_start_source_file (lineno, filename)
- unsigned int lineno;
- const char *filename;
+dwarf2out_start_source_file (unsigned int lineno, const char *filename)
{
if (flag_eliminate_dwarf2_dups)
{
/* Record the beginning of the file for break_out_includes. */
- dw_die_ref bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die, NULL);
+ dw_die_ref bincl_die;
+
+ bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die, NULL);
add_AT_string (bincl_die, DW_AT_name, filename);
}
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
lineno);
+ maybe_emit_file (lookup_filename (filename));
dw2_asm_output_data_uleb128 (lookup_filename (filename),
"Filename we just started");
}
/* Record the end of a source file. */
static void
-dwarf2out_end_source_file (lineno)
- unsigned int lineno ATTRIBUTE_UNUSED;
+dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
{
if (flag_eliminate_dwarf2_dups)
/* Record the end of the file for break_out_includes. */
initial whitespace, #, whitespace, directive-name, whitespace part. */
static void
-dwarf2out_define (lineno, buffer)
- unsigned lineno ATTRIBUTE_UNUSED;
- const char *buffer ATTRIBUTE_UNUSED;
+dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
+ const char *buffer ATTRIBUTE_UNUSED)
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
initial whitespace, #, whitespace, directive-name, whitespace part. */
static void
-dwarf2out_undef (lineno, buffer)
- unsigned lineno ATTRIBUTE_UNUSED;
- const char *buffer ATTRIBUTE_UNUSED;
+dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
+ const char *buffer ATTRIBUTE_UNUSED)
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
/* Set up for Dwarf output at the start of compilation. */
static void
-dwarf2out_init (main_input_filename)
- const char *main_input_filename;
+dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
{
init_file_table ();
- /* Remember the name of the primary input file. */
- primary_filename = main_input_filename;
-
- /* Add it to the file table first, under the assumption that we'll
- be emitting line number data for it first, which avoids having
- to add an initial DW_LNS_set_file. */
- lookup_filename (main_input_filename);
-
/* Allocate the initial hunk of the decl_die_table. */
- decl_die_table
- = (dw_die_ref *) xcalloc (DECL_DIE_TABLE_INCREMENT, sizeof (dw_die_ref));
+ decl_die_table = ggc_alloc_cleared (DECL_DIE_TABLE_INCREMENT
+ * sizeof (dw_die_ref));
decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
decl_die_table_in_use = 0;
VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");
/* Allocate the initial hunk of the abbrev_die_table. */
- abbrev_die_table
- = (dw_die_ref *) xcalloc (ABBREV_DIE_TABLE_INCREMENT,
- sizeof (dw_die_ref));
+ abbrev_die_table = ggc_alloc_cleared (ABBREV_DIE_TABLE_INCREMENT
+ * sizeof (dw_die_ref));
abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
/* Zero-th entry is allocated, but unused */
abbrev_die_table_in_use = 1;
/* Allocate the initial hunk of the line_info_table. */
- line_info_table
- = (dw_line_info_ref) xcalloc (LINE_INFO_TABLE_INCREMENT,
- sizeof (dw_line_info_entry));
+ line_info_table = ggc_alloc_cleared (LINE_INFO_TABLE_INCREMENT
+ * sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
/* Zero-th entry is allocated, but unused */
value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
will (typically) be a relative pathname and that this pathname should be
taken as being relative to the directory from which the compiler was
- invoked when the given (base) source file was compiled. */
- comp_unit_die = gen_compile_unit_die (main_input_filename);
+ invoked when the given (base) source file was compiled. We will fill
+ in this value in dwarf2out_finish. */
+ comp_unit_die = gen_compile_unit_die (NULL);
VARRAY_TREE_INIT (incomplete_types, 64, "incomplete_types");
VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray");
- ggc_add_root (&limbo_die_list, 1, 1, mark_limbo_die_list);
-
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
DEBUG_ABBREV_SECTION_LABEL, 0);
}
}
-/* Allocate a string in .debug_str hash table. */
-
-static hashnode
-indirect_string_alloc (tab)
- hash_table *tab ATTRIBUTE_UNUSED;
-{
- struct indirect_string_node *node;
-
- node = xmalloc (sizeof (struct indirect_string_node));
- node->refcount = 0;
- node->form = 0;
- node->label = NULL;
-
- return (hashnode) node;
-}
-
/* A helper function for dwarf2out_finish called through
ht_forall. Emit one queued .debug_str string. */
static int
-output_indirect_string (pfile, h, v)
- struct cpp_reader *pfile ATTRIBUTE_UNUSED;
- hashnode h;
- const PTR v ATTRIBUTE_UNUSED;
+output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
{
- struct indirect_string_node *node = (struct indirect_string_node *) h;
+ struct indirect_string_node *node = (struct indirect_string_node *) *h;
if (node->form == DW_FORM_strp)
{
named_section_flags (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS);
ASM_OUTPUT_LABEL (asm_out_file, node->label);
- assemble_string ((const char *) HT_STR (&node->id),
- HT_LEN (&node->id) + 1);
+ assemble_string (node->str, strlen (node->str) + 1);
}
return 1;
}
+
+
+/* Clear the marks for a die and its children.
+ Be cool if the mark isn't set. */
+
+static void
+prune_unmark_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+ die->die_mark = 0;
+ for (c = die->die_child; c; c = c->die_sib)
+ prune_unmark_dies (c);
+}
+
+
+/* Given DIE that we're marking as used, find any other dies
+ it references as attributes and mark them as used. */
+
+static void
+prune_unused_types_walk_attribs (dw_die_ref die)
+{
+ dw_attr_ref a;
+
+ for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ {
+ if (a->dw_attr_val.val_class == dw_val_class_die_ref)
+ {
+ /* A reference to another DIE.
+ Make sure that it will get emitted. */
+ prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
+ }
+ else if (a->dw_attr == DW_AT_decl_file)
+ {
+ /* A reference to a file. Make sure the file name is emitted. */
+ a->dw_attr_val.v.val_unsigned =
+ maybe_emit_file (a->dw_attr_val.v.val_unsigned);
+ }
+ }
+}
+
+
+/* Mark DIE as being used. If DOKIDS is true, then walk down
+ to DIE's children. */
+
+static void
+prune_unused_types_mark (dw_die_ref die, int dokids)
+{
+ dw_die_ref c;
+
+ if (die->die_mark == 0)
+ {
+ /* We haven't done this node yet. Mark it as used. */
+ die->die_mark = 1;
+
+ /* We also have to mark its parents as used.
+ (But we don't want to mark our parents' kids due to this.) */
+ if (die->die_parent)
+ prune_unused_types_mark (die->die_parent, 0);
+
+ /* Mark any referenced nodes. */
+ prune_unused_types_walk_attribs (die);
+ }
+
+ if (dokids && die->die_mark != 2)
+ {
+ /* We need to walk the children, but haven't done so yet.
+ Remember that we've walked the kids. */
+ die->die_mark = 2;
+
+ /* Walk them. */
+ for (c = die->die_child; c; c = c->die_sib)
+ {
+ /* If this is an array type, we need to make sure our
+ kids get marked, even if they're types. */
+ if (die->die_tag == DW_TAG_array_type)
+ prune_unused_types_mark (c, 1);
+ else
+ prune_unused_types_walk (c);
+ }
+ }
+}
+
+
+/* Walk the tree DIE and mark types that we actually use. */
+
+static void
+prune_unused_types_walk (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ /* Don't do anything if this node is already marked. */
+ if (die->die_mark)
+ return;
+
+ switch (die->die_tag) {
+ case DW_TAG_const_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
+ case DW_TAG_array_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ case DW_TAG_friend:
+ case DW_TAG_variant_part:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_string_type:
+ case DW_TAG_set_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_file_type:
+ /* It's a type node --- don't mark it. */
+ return;
+
+ default:
+ /* Mark everything else. */
+ break;
+ }
+
+ die->die_mark = 1;
+
+ /* Now, mark any dies referenced from here. */
+ prune_unused_types_walk_attribs (die);
+
+ /* Mark children. */
+ for (c = die->die_child; c; c = c->die_sib)
+ prune_unused_types_walk (c);
+}
+
+
+/* Remove from the tree DIE any dies that aren't marked. */
+
+static void
+prune_unused_types_prune (dw_die_ref die)
+{
+ dw_die_ref c, p, n;
+ if (!die->die_mark)
+ abort();
+
+ p = NULL;
+ for (c = die->die_child; c; c = n)
+ {
+ n = c->die_sib;
+ if (c->die_mark)
+ {
+ prune_unused_types_prune (c);
+ p = c;
+ }
+ else
+ {
+ if (p)
+ p->die_sib = n;
+ else
+ die->die_child = n;
+ free_die (c);
+ }
+ }
+}
+
+
+/* Remove dies representing declarations that we never use. */
+
+static void
+prune_unused_types (void)
+{
+ unsigned int i;
+ limbo_die_node *node;
+
+ /* Clear all the marks. */
+ prune_unmark_dies (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ prune_unmark_dies (node->die);
+
+ /* Set the mark on nodes that are actually used. */
+ prune_unused_types_walk (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ prune_unused_types_walk (node->die);
+
+ /* Also set the mark on nodes referenced from the
+ pubname_table or arange_table. */
+ for (i = 0; i < pubname_table_in_use; i++)
+ prune_unused_types_mark (pubname_table[i].die, 1);
+ for (i = 0; i < arange_table_in_use; i++)
+ prune_unused_types_mark (arange_table[i], 1);
+
+ /* Get rid of nodes that aren't marked. */
+ prune_unused_types_prune (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ prune_unused_types_prune (node->die);
+
+ /* Leave the marks clear. */
+ prune_unmark_dies (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ prune_unmark_dies (node->die);
+}
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
static void
-dwarf2out_finish (input_filename)
- const char *input_filename ATTRIBUTE_UNUSED;
+dwarf2out_finish (const char *filename)
{
limbo_die_node *node, *next_node;
dw_die_ref die = 0;
+ /* Add the name for the main input file now. We delayed this from
+ dwarf2out_init to avoid complications with PCH. */
+ add_name_attribute (comp_unit_die, filename);
+ if (filename[0] != DIR_SEPARATOR)
+ add_comp_dir_attribute (comp_unit_die);
+ else if (get_AT (comp_unit_die, DW_AT_comp_dir) == NULL)
+ {
+ size_t i;
+ for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
+ if (VARRAY_CHAR_PTR (file_table, i)[0] != DIR_SEPARATOR
+ /* Don't add cwd for <built-in>. */
+ && VARRAY_CHAR_PTR (file_table, i)[0] != '<')
+ {
+ add_comp_dir_attribute (comp_unit_die);
+ break;
+ }
+ }
+
/* Traverse the limbo die list, and add parent/child links. The only
dies without parents that should be here are concrete instances of
inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
else
abort ();
}
-
- free (node);
}
limbo_die_list = NULL;
we'll see the end of an include file before the beginning. */
reverse_all_dies (comp_unit_die);
+ if (flag_eliminate_unused_debug_types)
+ prune_unused_types ();
+
/* Generate separate CUs for each of the include files we've seen.
They will go into limbo_die_list. */
if (flag_eliminate_dwarf2_dups)
/* Output a terminator label for the .text section. */
text_section ();
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
+ (*targetm.asm_out.internal_label) (asm_out_file, TEXT_END_LABEL, 0);
/* Output the source line correspondence table. We must do this
even if there is no line information. Otherwise, on an empty
/* Output all of the compilation units. We put the main one last so that
the offsets are available to output_pubnames. */
for (node = limbo_die_list; node; node = node->next)
- output_comp_unit (node->die);
+ output_comp_unit (node->die, 0);
- output_comp_unit (comp_unit_die);
+ output_comp_unit (comp_unit_die, 0);
/* Output the abbreviation table. */
named_section_flags (DEBUG_ABBREV_SECTION, SECTION_DEBUG);
/* If we emitted any DW_FORM_strp form attribute, output the string
table too. */
if (debug_str_hash)
- ht_forall (debug_str_hash, output_indirect_string, NULL);
+ htab_traverse (debug_str_hash, output_indirect_string, NULL);
}
#else