#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "version.h"
#include "options.h"
#include "flags.h"
#include "real.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "insn-config.h"
#include "reload.h"
#include "function.h"
#include "output.h"
#include "expr.h"
#include "libfuncs.h"
#include "except.h"
#include "dwarf2.h"
#include "dwarf2out.h"
#include "dwarf2asm.h"
#include "toplev.h"
#include "varray.h"
#include "ggc.h"
#include "md5.h"
#include "tm_p.h"
#include "diagnostic.h"
#include "debug.h"
#include "target.h"
#include "langhooks.h"
#include "hashtab.h"
#include "cgraph.h"
#include "input.h"
#ifdef DWARF2_DEBUGGING_INFO
static void dwarf2out_source_line (unsigned int, const char *);
#endif
#ifndef DWARF2_FRAME_INFO
# ifdef DWARF2_DEBUGGING_INFO
# define DWARF2_FRAME_INFO \
(write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
# else
# define DWARF2_FRAME_INFO 0
# endif
#endif
#ifndef DWARF2_FRAME_REG_OUT
#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
#endif
int
dwarf2out_do_frame (void)
{
return (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
|| DWARF2_FRAME_INFO
#ifdef DWARF2_UNWIND_INFO
|| (DWARF2_UNWIND_INFO
&& (flag_unwind_tables
|| (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
#endif
);
}
#ifndef PTR_SIZE
#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
#endif
static GTY(()) VEC(rtx,gc) *used_rtx_array;
static GTY(()) VEC(tree,gc) *incomplete_types;
static GTY(()) VEC(tree,gc) *decl_scope_table;
static GTY(()) section *debug_info_section;
static GTY(()) section *debug_abbrev_section;
static GTY(()) section *debug_aranges_section;
static GTY(()) section *debug_macinfo_section;
static GTY(()) section *debug_line_section;
static GTY(()) section *debug_loc_section;
static GTY(()) section *debug_pubnames_section;
static GTY(()) section *debug_pubtypes_section;
static GTY(()) section *debug_str_section;
static GTY(()) section *debug_ranges_section;
static GTY(()) section *debug_frame_section;
static GTY(()) section *debug_inlined_section;
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
#endif
typedef struct dw_cfi_struct *dw_cfi_ref;
typedef struct dw_fde_struct *dw_fde_ref;
typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref;
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 int 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 GTY(())
{
dw_cfi_ref dw_cfi_next;
enum dwarf_call_frame_info dw_cfi_opc;
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;
typedef struct cfa_loc GTY(())
{
HOST_WIDE_INT offset;
HOST_WIDE_INT base_offset;
unsigned int reg;
int indirect;
} dw_cfa_location;
typedef struct dw_fde_struct GTY(())
{
tree decl;
const char *dw_fde_begin;
const char *dw_fde_current_label;
const char *dw_fde_end;
const char *dw_fde_hot_section_label;
const char *dw_fde_hot_section_end_label;
const char *dw_fde_unlikely_section_label;
const char *dw_fde_unlikely_section_end_label;
bool dw_fde_switched_sections;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
unsigned all_throwers_are_sibcalls : 1;
unsigned nothrow : 1;
unsigned uses_eh_lsda : 1;
}
dw_fde_node;
#define MAX_ARTIFICIAL_LABEL_BYTES 30
#ifndef DWARF2_ADDR_SIZE
#define DWARF2_ADDR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
#endif
#ifndef DWARF_OFFSET_SIZE
#define DWARF_OFFSET_SIZE 4
#endif
#ifndef DWARF_INITIAL_LENGTH_SIZE
#define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12)
#endif
#define DWARF_VERSION 2
#define DWARF_ROUND(SIZE,BOUNDARY) \
((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
#ifndef DWARF_CIE_DATA_ALIGNMENT
#ifdef STACK_GROWS_DOWNWARD
#define DWARF_CIE_DATA_ALIGNMENT (-((int) UNITS_PER_WORD))
#else
#define DWARF_CIE_DATA_ALIGNMENT ((int) UNITS_PER_WORD)
#endif
#endif
#if HOST_BITS_PER_WIDE_INT >= 64
#define DWARF_CIE_ID \
(unsigned HOST_WIDE_INT) (DWARF_OFFSET_SIZE == 4 ? DW_CIE_ID : DW64_CIE_ID)
#else
#define DWARF_CIE_ID DW_CIE_ID
#endif
static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
static GTY(()) unsigned fde_table_allocated;
static GTY(()) unsigned fde_table_in_use;
#define FDE_TABLE_INCREMENT 256
static GTY(()) dw_cfi_ref cie_cfi_head;
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
static unsigned current_funcdef_fde;
#endif
struct indirect_string_node GTY(())
{
const char *str;
unsigned int refcount;
unsigned int form;
bool is_fn_name;
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)
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, bool);
static void flush_queued_reg_saves (void);
static bool clobbers_queued_reg_save (rtx);
static void dwarf2out_frame_debug_expr (rtx, const char *);
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
(dw_cfa_location *, HOST_WIDE_INT);
static void def_cfa_1 (const char *, dw_cfa_location *);
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
#endif
#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
#ifndef DEBUG_FRAME_SECTION
#define DEBUG_FRAME_SECTION ".debug_frame"
#endif
#ifndef FUNC_BEGIN_LABEL
#define FUNC_BEGIN_LABEL "LFB"
#endif
#ifndef FUNC_END_LABEL
#define FUNC_END_LABEL "LFE"
#endif
#ifndef FRAME_BEGIN_LABEL
#define FRAME_BEGIN_LABEL "Lframe"
#endif
#define CIE_AFTER_SIZE_LABEL "LSCIE"
#define CIE_END_LABEL "LECIE"
#define FDE_LABEL "LSFDE"
#define FDE_AFTER_SIZE_LABEL "LASFDE"
#define FDE_END_LABEL "LEFDE"
#define LINE_NUMBER_BEGIN_LABEL "LSLT"
#define LINE_NUMBER_END_LABEL "LELT"
#define LN_PROLOG_AS_LABEL "LASLTP"
#define LN_PROLOG_END_LABEL "LELTP"
#define DIE_LABEL_PREFIX "DW"
#ifndef DWARF_FRAME_RETURN_COLUMN
#ifdef PC_REGNUM
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM)
#else
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGISTERS
#endif
#endif
#ifndef DWARF_FRAME_REGNUM
#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
#endif
#define DW_ISA_UNKNOWN 0
#define DW_ISA_ARM_thumb 1
#define DW_ISA_ARM_arm 2
#define DW_ISA_USE_STMT_LIST -1
rtx
expand_builtin_dwarf_sp_column (void)
{
unsigned int dwarf_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1));
}
static inline char *
stripattributes (const char *s)
{
char *stripped = XNEWVEC (char, strlen (s) + 2);
char *p = stripped;
*p++ = '*';
while (*s && *s != ',')
*p++ = *s++;
*p = '\0';
return stripped;
}
void
expand_builtin_init_dwarf_reg_sizes (tree address)
{
unsigned int i;
enum machine_mode mode = TYPE_MODE (char_type_node);
rtx addr = expand_normal (address);
rtx mem = gen_rtx_MEM (BLKmode, addr);
bool wrote_return_column = false;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int rnum = DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), 1);
if (rnum < DWARF_FRAME_REGISTERS)
{
HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
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_mode (size, mode));
}
}
#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
gcc_assert (wrote_return_column);
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));
}
}
static const char *
dwarf_cfi_name (unsigned int cfi_opc)
{
switch (cfi_opc)
{
case DW_CFA_advance_loc:
return "DW_CFA_advance_loc";
case DW_CFA_offset:
return "DW_CFA_offset";
case DW_CFA_restore:
return "DW_CFA_restore";
case DW_CFA_nop:
return "DW_CFA_nop";
case DW_CFA_set_loc:
return "DW_CFA_set_loc";
case DW_CFA_advance_loc1:
return "DW_CFA_advance_loc1";
case DW_CFA_advance_loc2:
return "DW_CFA_advance_loc2";
case DW_CFA_advance_loc4:
return "DW_CFA_advance_loc4";
case DW_CFA_offset_extended:
return "DW_CFA_offset_extended";
case DW_CFA_restore_extended:
return "DW_CFA_restore_extended";
case DW_CFA_undefined:
return "DW_CFA_undefined";
case DW_CFA_same_value:
return "DW_CFA_same_value";
case DW_CFA_register:
return "DW_CFA_register";
case DW_CFA_remember_state:
return "DW_CFA_remember_state";
case DW_CFA_restore_state:
return "DW_CFA_restore_state";
case DW_CFA_def_cfa:
return "DW_CFA_def_cfa";
case DW_CFA_def_cfa_register:
return "DW_CFA_def_cfa_register";
case DW_CFA_def_cfa_offset:
return "DW_CFA_def_cfa_offset";
case DW_CFA_def_cfa_expression:
return "DW_CFA_def_cfa_expression";
case DW_CFA_expression:
return "DW_CFA_expression";
case DW_CFA_offset_extended_sf:
return "DW_CFA_offset_extended_sf";
case DW_CFA_def_cfa_sf:
return "DW_CFA_def_cfa_sf";
case DW_CFA_def_cfa_offset_sf:
return "DW_CFA_def_cfa_offset_sf";
case DW_CFA_MIPS_advance_loc8:
return "DW_CFA_MIPS_advance_loc8";
case DW_CFA_GNU_window_save:
return "DW_CFA_GNU_window_save";
case DW_CFA_GNU_args_size:
return "DW_CFA_GNU_args_size";
case DW_CFA_GNU_negative_offset_extended:
return "DW_CFA_GNU_negative_offset_extended";
default:
return "DW_CFA_<unknown>";
}
}
static inline dw_cfi_ref
new_cfi (void)
{
dw_cfi_ref cfi = ggc_alloc (sizeof (dw_cfi_node));
cfi->dw_cfi_next = NULL;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
return cfi;
}
static inline void
add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi)
{
dw_cfi_ref *p;
for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
;
*p = cfi;
}
char *
dwarf2out_cfi_label (void)
{
static char label[20];
ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
ASM_OUTPUT_LABEL (asm_out_file, label);
return label;
}
static void
add_fde_cfi (const char *label, dw_cfi_ref cfi)
{
if (label)
{
dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
if (*label == 0)
label = dwarf2out_cfi_label ();
if (fde->dw_fde_current_label == NULL
|| strcmp (label, fde->dw_fde_current_label) != 0)
{
dw_cfi_ref xcfi;
label = xstrdup (label);
xcfi = new_cfi ();
xcfi->dw_cfi_opc = fde->dw_fde_current_label
? DW_CFA_advance_loc4
: DW_CFA_set_loc;
xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
add_cfi (&fde->dw_fde_cfi, xcfi);
fde->dw_fde_current_label = label;
}
add_cfi (&fde->dw_fde_cfi, cfi);
}
else
add_cfi (&cie_cfi_head, cfi);
}
static void
lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc)
{
switch (cfi->dw_cfi_opc)
{
case DW_CFA_def_cfa_offset:
loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
break;
case DW_CFA_def_cfa_offset_sf:
loc->offset
= cfi->dw_cfi_oprnd1.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
break;
case DW_CFA_def_cfa_register:
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
break;
case DW_CFA_def_cfa:
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
break;
case DW_CFA_def_cfa_sf:
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
loc->offset
= cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
break;
case DW_CFA_def_cfa_expression:
get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
break;
default:
break;
}
}
static void
lookup_cfa (dw_cfa_location *loc)
{
dw_cfi_ref cfi;
loc->reg = INVALID_REGNUM;
loc->offset = 0;
loc->indirect = 0;
loc->base_offset = 0;
for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
lookup_cfa_1 (cfi, loc);
if (fde_table_in_use)
{
dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
lookup_cfa_1 (cfi, loc);
}
}
static dw_cfa_location cfa;
static dw_cfa_location cfa_store;
static HOST_WIDE_INT args_size;
static HOST_WIDE_INT old_args_size;
void
dwarf2out_def_cfa (const char *label, unsigned int reg, HOST_WIDE_INT offset)
{
dw_cfa_location loc;
loc.indirect = 0;
loc.base_offset = 0;
loc.reg = reg;
loc.offset = offset;
def_cfa_1 (label, &loc);
}
static bool
cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
{
return (loc1->reg == loc2->reg
&& loc1->offset == loc2->offset
&& loc1->indirect == loc2->indirect
&& (loc1->indirect == 0
|| loc1->base_offset == loc2->base_offset));
}
static void
def_cfa_1 (const char *label, dw_cfa_location *loc_p)
{
dw_cfi_ref cfi;
dw_cfa_location old_cfa, loc;
cfa = *loc_p;
loc = *loc_p;
if (cfa_store.reg == loc.reg && loc.indirect == 0)
cfa_store.offset = loc.offset;
loc.reg = DWARF_FRAME_REGNUM (loc.reg);
lookup_cfa (&old_cfa);
if (cfa_equal_p (&loc, &old_cfa))
return;
cfi = new_cfi ();
if (loc.reg == old_cfa.reg && !loc.indirect)
{
if (loc.offset < 0)
{
HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
cfi->dw_cfi_oprnd1.dw_cfi_offset = f_offset;
}
else
{
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
}
}
#ifndef MIPS_DEBUGGING_INFO
else if (loc.offset == old_cfa.offset
&& old_cfa.reg != INVALID_REGNUM
&& !loc.indirect)
{
cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
}
#endif
else if (loc.indirect == 0)
{
if (loc.offset < 0)
{
HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
cfi->dw_cfi_oprnd2.dw_cfi_offset = f_offset;
}
else
{
cfi->dw_cfi_opc = DW_CFA_def_cfa;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
}
}
else
{
struct dw_loc_descr_struct *loc_list;
cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
loc_list = build_cfa_loc (&loc, 0);
cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
}
add_fde_cfi (label, cfi);
}
static void
reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
{
dw_cfi_ref cfi = new_cfi ();
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
if (sreg == INVALID_REGNUM)
{
if (reg & ~0x3f)
cfi->dw_cfi_opc = DW_CFA_offset_extended;
else
cfi->dw_cfi_opc = DW_CFA_offset;
#ifdef ENABLE_CHECKING
{
HOST_WIDE_INT check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
gcc_assert (check_offset * DWARF_CIE_DATA_ALIGNMENT == offset);
}
#endif
offset /= DWARF_CIE_DATA_ALIGNMENT;
if (offset < 0)
cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
}
else if (sreg == reg)
cfi->dw_cfi_opc = DW_CFA_same_value;
else
{
cfi->dw_cfi_opc = DW_CFA_register;
cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
}
add_fde_cfi (label, cfi);
}
void
dwarf2out_window_save (const char *label)
{
dw_cfi_ref cfi = new_cfi ();
cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
add_fde_cfi (label, cfi);
}
void
dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
{
dw_cfi_ref cfi;
if (size == old_args_size)
return;
old_args_size = size;
cfi = new_cfi ();
cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
add_fde_cfi (label, cfi);
}
void
dwarf2out_reg_save (const char *label, unsigned int reg, HOST_WIDE_INT offset)
{
reg_save (label, DWARF_FRAME_REGNUM (reg), INVALID_REGNUM, offset);
}
void
dwarf2out_return_save (const char *label, HOST_WIDE_INT offset)
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, INVALID_REGNUM, offset);
}
void
dwarf2out_return_reg (const char *label, unsigned int sreg)
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM (sreg), 0);
}
static void
initial_return_save (rtx rtl)
{
unsigned int reg = INVALID_REGNUM;
HOST_WIDE_INT offset = 0;
switch (GET_CODE (rtl))
{
case REG:
reg = DWARF_FRAME_REGNUM (REGNO (rtl));
break;
case MEM:
rtl = XEXP (rtl, 0);
switch (GET_CODE (rtl))
{
case REG:
gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM);
offset = 0;
break;
case PLUS:
gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
offset = INTVAL (XEXP (rtl, 1));
break;
case MINUS:
gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
offset = -INTVAL (XEXP (rtl, 1));
break;
default:
gcc_unreachable ();
}
break;
case PLUS:
gcc_assert (GET_CODE (XEXP (rtl, 1)) == CONST_INT);
initial_return_save (XEXP (rtl, 0));
return;
default:
gcc_unreachable ();
}
if (reg != DWARF_FRAME_RETURN_COLUMN)
reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
}
static HOST_WIDE_INT
stack_adjust_offset (rtx pattern)
{
rtx src = SET_SRC (pattern);
rtx dest = SET_DEST (pattern);
HOST_WIDE_INT offset = 0;
enum rtx_code code;
if (dest == stack_pointer_rtx)
{
code = GET_CODE (src);
if (! (code == PLUS || code == MINUS)
|| XEXP (src, 0) != stack_pointer_rtx
|| GET_CODE (XEXP (src, 1)) != CONST_INT)
return 0;
offset = INTVAL (XEXP (src, 1));
if (code == PLUS)
offset = -offset;
}
else if (MEM_P (dest))
{
src = XEXP (dest, 0);
code = GET_CODE (src);
switch (code)
{
case PRE_MODIFY:
case POST_MODIFY:
if (XEXP (src, 0) == stack_pointer_rtx)
{
rtx val = XEXP (XEXP (src, 1), 1);
gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS
&& GET_CODE (val) == CONST_INT);
offset = -INTVAL (val);
break;
}
return 0;
case PRE_DEC:
case POST_DEC:
if (XEXP (src, 0) == stack_pointer_rtx)
{
offset = GET_MODE_SIZE (GET_MODE (dest));
break;
}
return 0;
case PRE_INC:
case POST_INC:
if (XEXP (src, 0) == stack_pointer_rtx)
{
offset = -GET_MODE_SIZE (GET_MODE (dest));
break;
}
return 0;
default:
return 0;
}
}
else
return 0;
return offset;
}
static void
dwarf2out_stack_adjust (rtx insn, bool after_p)
{
HOST_WIDE_INT offset;
const char *label;
int i;
if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
return;
if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
{
if (CALL_P (insn) && !after_p)
{
insn = PATTERN (insn);
if (GET_CODE (insn) == PARALLEL)
insn = XVECEXP (insn, 0, 0);
if (GET_CODE (insn) == SET)
insn = SET_SRC (insn);
gcc_assert (GET_CODE (insn) == CALL);
dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
}
return;
}
if (CALL_P (insn) && !after_p)
{
if (!flag_asynchronous_unwind_tables)
dwarf2out_args_size ("", args_size);
return;
}
else if (BARRIER_P (insn))
{
#ifdef STACK_GROWS_DOWNWARD
offset = -args_size;
#else
offset = args_size;
#endif
}
else if (GET_CODE (PATTERN (insn)) == SET)
offset = stack_adjust_offset (PATTERN (insn));
else if (GET_CODE (PATTERN (insn)) == PARALLEL
|| GET_CODE (PATTERN (insn)) == SEQUENCE)
{
for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i));
}
else
return;
if (offset == 0)
return;
if (cfa.reg == STACK_POINTER_REGNUM)
cfa.offset += offset;
#ifndef STACK_GROWS_DOWNWARD
offset = -offset;
#endif
args_size += offset;
if (args_size < 0)
args_size = 0;
label = dwarf2out_cfi_label ();
def_cfa_1 (label, &cfa);
if (flag_asynchronous_unwind_tables)
dwarf2out_args_size (label, args_size);
}
#endif
struct queued_reg_save GTY(())
{
struct queued_reg_save *next;
rtx reg;
HOST_WIDE_INT cfa_offset;
rtx saved_reg;
};
static GTY(()) struct queued_reg_save *queued_reg_saves;
struct reg_saved_in_data GTY(()) {
rtx orig_reg;
rtx saved_in_reg;
};
static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4];
static GTY(()) size_t num_regs_saved_in_regs;
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
static const char *last_reg_save_label;
static void
queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
{
struct queued_reg_save *q;
for (q = queued_reg_saves; q != NULL; q = q->next)
if (REGNO (q->reg) == REGNO (reg))
break;
if (q == NULL)
{
q = ggc_alloc (sizeof (*q));
q->next = queued_reg_saves;
queued_reg_saves = q;
}
q->reg = reg;
q->cfa_offset = offset;
q->saved_reg = sreg;
last_reg_save_label = label;
}
static void
flush_queued_reg_saves (void)
{
struct queued_reg_save *q;
for (q = queued_reg_saves; q; q = q->next)
{
size_t i;
unsigned int reg, sreg;
for (i = 0; i < num_regs_saved_in_regs; i++)
if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
break;
if (q->saved_reg && i == num_regs_saved_in_regs)
{
gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
num_regs_saved_in_regs++;
}
if (i != num_regs_saved_in_regs)
{
regs_saved_in_regs[i].orig_reg = q->reg;
regs_saved_in_regs[i].saved_in_reg = q->saved_reg;
}
reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
if (q->saved_reg)
sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
else
sreg = INVALID_REGNUM;
reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
}
queued_reg_saves = NULL;
last_reg_save_label = NULL;
}
static bool
clobbers_queued_reg_save (rtx insn)
{
struct queued_reg_save *q;
for (q = queued_reg_saves; q; q = q->next)
{
size_t i;
if (modified_in_p (q->reg, insn))
return true;
for (i = 0; i < num_regs_saved_in_regs; i++)
if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg)
&& modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn))
return true;
}
return false;
}
void
dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg)
{
size_t i;
unsigned int regno, sregno;
for (i = 0; i < num_regs_saved_in_regs; i++)
if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg))
break;
if (i == num_regs_saved_in_regs)
{
gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
num_regs_saved_in_regs++;
}
regs_saved_in_regs[i].orig_reg = reg;
regs_saved_in_regs[i].saved_in_reg = sreg;
regno = DWARF_FRAME_REGNUM (REGNO (reg));
sregno = DWARF_FRAME_REGNUM (REGNO (sreg));
reg_save (label, regno, sregno, 0);
}
static rtx
reg_saved_in (rtx reg)
{
unsigned int regn = REGNO (reg);
size_t i;
struct queued_reg_save *q;
for (q = queued_reg_saves; q; q = q->next)
if (q->saved_reg && regn == REGNO (q->saved_reg))
return q->reg;
for (i = 0; i < num_regs_saved_in_regs; i++)
if (regs_saved_in_regs[i].saved_in_reg
&& regn == REGNO (regs_saved_in_regs[i].saved_in_reg))
return regs_saved_in_regs[i].orig_reg;
return NULL_RTX;
}
static dw_cfa_location cfa_temp;
static void
dwarf2out_frame_debug_expr (rtx expr, const char *label)
{
rtx src, dest;
HOST_WIDE_INT offset;
if (GET_CODE (expr) == PARALLEL || GET_CODE (expr) == SEQUENCE)
{
int par_index;
int limit = XVECLEN (expr, 0);
for (par_index = 0; par_index < limit; par_index++)
if (GET_CODE (XVECEXP (expr, 0, par_index)) == SET
&& (RTX_FRAME_RELATED_P (XVECEXP (expr, 0, par_index))
|| par_index == 0))
dwarf2out_frame_debug_expr (XVECEXP (expr, 0, par_index), label);
return;
}
gcc_assert (GET_CODE (expr) == SET);
src = SET_SRC (expr);
dest = SET_DEST (expr);
if (REG_P (src))
{
rtx rsi = reg_saved_in (src);
if (rsi)
src = rsi;
}
switch (GET_CODE (dest))
{
case REG:
switch (GET_CODE (src))
{
case REG:
if (cfa.reg == (unsigned) REGNO (src))
{
cfa.reg = REGNO (dest);
cfa_temp.reg = cfa.reg;
cfa_temp.offset = cfa.offset;
}
else
{
gcc_assert (!fixed_regs [REGNO (dest)]
|| (DWARF_FRAME_REGNUM (REGNO (src))
== DWARF_FRAME_RETURN_COLUMN));
queue_reg_save (label, src, dest, 0);
}
break;
case PLUS:
case MINUS:
case LO_SUM:
if (dest == stack_pointer_rtx)
{
switch (GET_CODE (XEXP (src, 1)))
{
case CONST_INT:
offset = INTVAL (XEXP (src, 1));
break;
case REG:
gcc_assert ((unsigned) REGNO (XEXP (src, 1))
== cfa_temp.reg);
offset = cfa_temp.offset;
break;
default:
gcc_unreachable ();
}
if (XEXP (src, 0) == hard_frame_pointer_rtx)
{
gcc_assert (cfa.reg == (unsigned) HARD_FRAME_POINTER_REGNUM);
cfa.reg = STACK_POINTER_REGNUM;
}
else if (GET_CODE (src) == LO_SUM)
;
else
gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
if (GET_CODE (src) != MINUS)
offset = -offset;
if (cfa.reg == STACK_POINTER_REGNUM)
cfa.offset += offset;
if (cfa_store.reg == STACK_POINTER_REGNUM)
cfa_store.offset += offset;
}
else if (dest == hard_frame_pointer_rtx)
{
gcc_assert (frame_pointer_needed);
gcc_assert (REG_P (XEXP (src, 0))
&& (unsigned) REGNO (XEXP (src, 0)) == cfa.reg
&& GET_CODE (XEXP (src, 1)) == CONST_INT);
offset = INTVAL (XEXP (src, 1));
if (GET_CODE (src) != MINUS)
offset = -offset;
cfa.offset += offset;
cfa.reg = HARD_FRAME_POINTER_REGNUM;
}
else
{
gcc_assert (GET_CODE (src) != MINUS);
if (REG_P (XEXP (src, 0))
&& REGNO (XEXP (src, 0)) == cfa.reg
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
offset = - INTVAL (XEXP (src, 1));
cfa.offset += offset;
cfa.reg = REGNO (dest);
cfa_temp.reg = cfa.reg;
cfa_temp.offset = cfa.offset;
}
else if (REG_P (XEXP (src, 0))
&& REGNO (XEXP (src, 0)) == cfa_temp.reg
&& XEXP (src, 1) == stack_pointer_rtx)
{
gcc_assert (cfa.reg == STACK_POINTER_REGNUM);
cfa_store.reg = REGNO (dest);
cfa_store.offset = cfa.offset - cfa_temp.offset;
}
else if (GET_CODE (src) == LO_SUM
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
cfa_temp.reg = REGNO (dest);
cfa_temp.offset = INTVAL (XEXP (src, 1));
}
else
gcc_unreachable ();
}
break;
case CONST_INT:
cfa_temp.reg = REGNO (dest);
cfa_temp.offset = INTVAL (src);
break;
case IOR:
gcc_assert (REG_P (XEXP (src, 0))
&& (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg
&& GET_CODE (XEXP (src, 1)) == CONST_INT);
if ((unsigned) REGNO (dest) != cfa_temp.reg)
cfa_temp.reg = REGNO (dest);
cfa_temp.offset |= INTVAL (XEXP (src, 1));
break;
case HIGH:
break;
case UNSPEC:
case UNSPEC_VOLATILE:
gcc_assert (targetm.dwarf_handle_frame_unspec);
targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
return;
default:
gcc_unreachable ();
}
def_cfa_1 (label, &cfa);
break;
case MEM:
gcc_assert (REG_P (src));
switch (GET_CODE (XEXP (dest, 0)))
{
case PRE_MODIFY:
gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
== CONST_INT);
offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
&& cfa_store.reg == STACK_POINTER_REGNUM);
cfa_store.offset += offset;
if (cfa.reg == STACK_POINTER_REGNUM)
cfa.offset = cfa_store.offset;
offset = -cfa_store.offset;
break;
case PRE_INC:
case PRE_DEC:
offset = GET_MODE_SIZE (GET_MODE (dest));
if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
offset = -offset;
gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
&& cfa_store.reg == STACK_POINTER_REGNUM);
cfa_store.offset += offset;
if (cfa.reg == STACK_POINTER_REGNUM)
cfa.offset = cfa_store.offset;
offset = -cfa_store.offset;
break;
case PLUS:
case MINUS:
case LO_SUM:
{
int regno;
gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT
&& REG_P (XEXP (XEXP (dest, 0), 0)));
offset = INTVAL (XEXP (XEXP (dest, 0), 1));
if (GET_CODE (XEXP (dest, 0)) == MINUS)
offset = -offset;
regno = REGNO (XEXP (XEXP (dest, 0), 0));
if (cfa_store.reg == (unsigned) regno)
offset -= cfa_store.offset;
else
{
gcc_assert (cfa_temp.reg == (unsigned) regno);
offset -= cfa_temp.offset;
}
}
break;
case REG:
{
int regno = REGNO (XEXP (dest, 0));
if (cfa_store.reg == (unsigned) regno)
offset = -cfa_store.offset;
else
{
gcc_assert (cfa_temp.reg == (unsigned) regno);
offset = -cfa_temp.offset;
}
}
break;
case POST_INC:
gcc_assert (cfa_temp.reg
== (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)));
offset = -cfa_temp.offset;
cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
break;
default:
gcc_unreachable ();
}
if (REGNO (src) != STACK_POINTER_REGNUM
&& REGNO (src) != HARD_FRAME_POINTER_REGNUM
&& (unsigned) REGNO (src) == cfa.reg)
{
if (cfa.offset == 0)
{
def_cfa_1 (label, &cfa);
queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset);
break;
}
else
{
rtx x = XEXP (dest, 0);
if (!REG_P (x))
x = XEXP (x, 0);
gcc_assert (REG_P (x));
cfa.reg = REGNO (x);
cfa.base_offset = offset;
cfa.indirect = 1;
def_cfa_1 (label, &cfa);
break;
}
}
def_cfa_1 (label, &cfa);
queue_reg_save (label, src, NULL_RTX, offset);
break;
default:
gcc_unreachable ();
}
}
void
dwarf2out_frame_debug (rtx insn, bool after_p)
{
const char *label;
rtx src;
if (insn == NULL_RTX)
{
size_t i;
flush_queued_reg_saves ();
lookup_cfa (&cfa);
gcc_assert (cfa.reg
== (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
cfa.reg = STACK_POINTER_REGNUM;
cfa_store = cfa;
cfa_temp.reg = -1;
cfa_temp.offset = 0;
for (i = 0; i < num_regs_saved_in_regs; i++)
{
regs_saved_in_regs[i].orig_reg = NULL_RTX;
regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
}
num_regs_saved_in_regs = 0;
return;
}
if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
flush_queued_reg_saves ();
if (! RTX_FRAME_RELATED_P (insn))
{
if (!ACCUMULATE_OUTGOING_ARGS)
dwarf2out_stack_adjust (insn, after_p);
return;
}
label = dwarf2out_cfi_label ();
src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
if (src)
insn = XEXP (src, 0);
else
insn = PATTERN (insn);
dwarf2out_frame_debug_expr (insn, label);
}
#endif
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:
gcc_unreachable ();
}
}
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)
static void
switch_to_eh_frame_section (void)
{
tree label;
#ifdef EH_FRAME_SECTION_NAME
if (eh_frame_section == 0)
{
int flags;
if (EH_TABLES_CAN_BE_READ_ONLY)
{
int fde_encoding;
int per_encoding;
int lsda_encoding;
fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (1,
0);
per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (2,
1);
lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (0,
0);
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);
}
else
flags = SECTION_WRITE;
eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
}
#endif
if (eh_frame_section)
switch_to_section (eh_frame_section);
else
{
switch_to_section (data_section);
\
label = get_file_function_name ("F");
\
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
targetm.asm_out.globalize_label (asm_out_file,
IDENTIFIER_POINTER (label));
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
}
}
static void
output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
{
unsigned long r;
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 " HOST_WIDE_INT_PRINT_HEX,
cfi->dw_cfi_oprnd1.dw_cfi_offset);
else if (cfi->dw_cfi_opc == DW_CFA_offset)
{
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
"DW_CFA_offset, column 0x%lx", r);
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
}
else if (cfi->dw_cfi_opc == DW_CFA_restore)
{
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
"DW_CFA_restore, column 0x%lx", r);
}
else
{
dw2_asm_output_data (1, cfi->dw_cfi_opc,
"%s", dwarf_cfi_name (cfi->dw_cfi_opc));
switch (cfi->dw_cfi_opc)
{
case DW_CFA_set_loc:
if (for_eh)
dw2_asm_output_encoded_addr_rtx (
ASM_PREFERRED_EH_DATA_FORMAT (1, 0),
gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
false, NULL);
else
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc1:
dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label, NULL);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc2:
dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label, NULL);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc4:
dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label, NULL);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_MIPS_advance_loc8:
dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label, NULL);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_offset_extended:
case DW_CFA_def_cfa:
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data_uleb128 (r, NULL);
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
break;
case DW_CFA_offset_extended_sf:
case DW_CFA_def_cfa_sf:
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data_uleb128 (r, NULL);
dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
break;
case DW_CFA_restore_extended:
case DW_CFA_undefined:
case DW_CFA_same_value:
case DW_CFA_def_cfa_register:
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data_uleb128 (r, NULL);
break;
case DW_CFA_register:
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data_uleb128 (r, NULL);
r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, for_eh);
dw2_asm_output_data_uleb128 (r, NULL);
break;
case DW_CFA_def_cfa_offset:
case DW_CFA_GNU_args_size:
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
break;
case DW_CFA_def_cfa_offset_sf:
dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
break;
case DW_CFA_GNU_window_save:
break;
case DW_CFA_def_cfa_expression:
case DW_CFA_expression:
output_cfa_loc (cfi);
break;
case DW_CFA_GNU_negative_offset_extended:
gcc_unreachable ();
default:
break;
}
}
}
static void
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];
bool any_lsda_needed = false;
char augmentation[6];
int augmentation_size;
int fde_encoding = DW_EH_PE_absptr;
int per_encoding = DW_EH_PE_absptr;
int lsda_encoding = DW_EH_PE_absptr;
int return_reg;
if (fde_table_in_use == 0)
return;
if (TARGET_USES_WEAK_UNWIND_INFO
&& ! flag_asynchronous_unwind_tables
\
&& flag_exceptions
\
&& for_eh)
for (i = 0; i < fde_table_in_use; i++)
if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
&& !fde_table[i].uses_eh_lsda
&& ! DECL_WEAK (fde_table[i].decl))
targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
for_eh, 1);
if (for_eh)
{
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 = true;
else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
any_eh_needed = true;
else if (! fde_table[i].nothrow
&& ! fde_table[i].all_throwers_are_sibcalls)
any_eh_needed = true;
if (! any_eh_needed)
return;
}
if (flag_debug_asm)
app_enable ();
if (for_eh)
switch_to_eh_frame_section ();
else
{
if (!debug_frame_section)
debug_frame_section = get_section (DEBUG_FRAME_SECTION,
SECTION_DEBUG, NULL);
switch_to_section (debug_frame_section);
}
ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
dw2_asm_output_data (4, 0xffffffff,
"Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"Length of Common Information Entry");
ASM_OUTPUT_LABEL (asm_out_file, l1);
dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
(for_eh ? 0 : DWARF_CIE_ID),
"CIE Identifier Tag");
dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
augmentation[0] = 0;
augmentation_size = 0;
if (for_eh)
{
char *p;
fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (1, 0);
per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (2, 1);
lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (0, 0);
p = augmentation + 1;
if (eh_personality_libfunc)
{
*p++ = 'P';
augmentation_size += 1 + size_of_encoded_value (per_encoding);
}
if (any_lsda_needed)
{
*p++ = 'L';
augmentation_size += 1;
}
if (fde_encoding != DW_EH_PE_absptr)
{
*p++ = 'R';
augmentation_size += 1;
}
if (p > augmentation + 1)
{
augmentation[0] = 'z';
*p = '\0';
}
if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned)
{
int offset = ( 4
+ 4
+ 1
+ strlen (augmentation) + 1
+ size_of_uleb128 (1)
+ size_of_sleb128 (DWARF_CIE_DATA_ALIGNMENT)
+ 1
+ 1
+ 1 );
int pad = -offset & (PTR_SIZE - 1);
augmentation_size += pad;
gcc_assert (size_of_uleb128 (augmentation_size) == 1);
}
}
dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
"CIE Data Alignment Factor");
return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
if (DW_CIE_VERSION == 1)
dw2_asm_output_data (1, return_reg, "CIE RA Column");
else
dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
if (augmentation[0])
{
dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
if (eh_personality_libfunc)
{
dw2_asm_output_data (1, per_encoding, "Personality (%s)",
eh_data_format_name (per_encoding));
dw2_asm_output_encoded_addr_rtx (per_encoding,
eh_personality_libfunc,
true, NULL);
}
if (any_lsda_needed)
dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
eh_data_format_name (lsda_encoding));
if (fde_encoding != DW_EH_PE_absptr)
dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
eh_data_format_name (fde_encoding));
}
for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
output_cfi (cfi, NULL, for_eh);
ASM_OUTPUT_ALIGN (asm_out_file,
floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE));
ASM_OUTPUT_LABEL (asm_out_file, l2);
for (i = 0; i < fde_table_in_use; i++)
{
fde = &fde_table[i];
if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
&& (fde->nothrow || fde->all_throwers_are_sibcalls)
&& ! (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
&& !fde->uses_eh_lsda)
continue;
targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh, 0);
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);
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
dw2_asm_output_data (4, 0xffffffff,
"Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"FDE Length");
ASM_OUTPUT_LABEL (asm_out_file, l1);
if (for_eh)
dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
else
dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
debug_frame_section, "FDE CIE offset");
if (for_eh)
{
rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin);
SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
dw2_asm_output_encoded_addr_rtx (fde_encoding,
sym_ref,
false,
"FDE initial location");
if (fde->dw_fde_switched_sections)
{
rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
fde->dw_fde_unlikely_section_label);
rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
fde->dw_fde_hot_section_label);
SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3, false,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_hot_section_end_label,
fde->dw_fde_hot_section_label,
"FDE address range");
dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2, false,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_unlikely_section_end_label,
fde->dw_fde_unlikely_section_label,
"FDE address range");
}
else
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
"FDE initial location");
if (fde->dw_fde_switched_sections)
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
fde->dw_fde_hot_section_label,
"FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_hot_section_end_label,
fde->dw_fde_hot_section_label,
"FDE address range");
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
fde->dw_fde_unlikely_section_label,
"FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_unlikely_section_end_label,
fde->dw_fde_unlikely_section_label,
"FDE address range");
}
else
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
}
if (augmentation[0])
{
if (any_lsda_needed)
{
int size = size_of_encoded_value (lsda_encoding);
if (lsda_encoding == DW_EH_PE_aligned)
{
int offset = ( 4
+ 4
+ 2 * size_of_encoded_value (fde_encoding)
+ 1 );
int pad = -offset & (PTR_SIZE - 1);
size += pad;
gcc_assert (size_of_uleb128 (size) == 1);
}
dw2_asm_output_data_uleb128 (size, "Augmentation size");
if (fde->uses_eh_lsda)
{
ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
fde->funcdef_number);
dw2_asm_output_encoded_addr_rtx (
lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
false, "Language Specific Data Area");
}
else
{
if (lsda_encoding == DW_EH_PE_aligned)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
dw2_asm_output_data
(size_of_encoded_value (lsda_encoding), 0,
"Language Specific Data Area (none)");
}
}
else
dw2_asm_output_data_uleb128 (0, "Augmentation size");
}
fde->dw_fde_current_label = fde->dw_fde_begin;
for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
output_cfi (cfi, fde, for_eh);
ASM_OUTPUT_ALIGN (asm_out_file,
floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
ASM_OUTPUT_LABEL (asm_out_file, l2);
}
if (for_eh && targetm.terminate_dw2_eh_frame_info)
dw2_asm_output_data (4, 0, "End of Table");
#ifdef MIPS_DEBUGGING_INFO
ASM_OUTPUT_ALIGN (asm_out_file, 0);
#endif
if (flag_debug_asm)
app_disable ();
}
void
dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
char * dup_label;
dw_fde_ref fde;
current_function_func_begin_label = NULL;
#ifdef TARGET_UNWIND_INFO
if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
&& ! dwarf2out_do_frame ())
return;
#else
if (! dwarf2out_do_frame ())
return;
#endif
switch_to_section (function_section (current_function_decl));
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
dup_label = xstrdup (label);
current_function_func_begin_label = dup_label;
#ifdef TARGET_UNWIND_INFO
if (! dwarf2out_do_frame ())
return;
#endif
if (fde_table_in_use == fde_table_allocated)
{
fde_table_allocated += FDE_TABLE_INCREMENT;
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));
}
current_funcdef_fde = fde_table_in_use;
fde = &fde_table[fde_table_in_use++];
fde->decl = current_function_decl;
fde->dw_fde_begin = dup_label;
fde->dw_fde_current_label = dup_label;
fde->dw_fde_hot_section_label = NULL;
fde->dw_fde_hot_section_end_label = NULL;
fde->dw_fde_unlikely_section_label = NULL;
fde->dw_fde_unlikely_section_end_label = NULL;
fde->dw_fde_switched_sections = false;
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
fde->funcdef_number = current_function_funcdef_no;
fde->nothrow = TREE_NOTHROW (current_function_decl);
fde->uses_eh_lsda = cfun->uses_eh_lsda;
fde->all_throwers_are_sibcalls = cfun->all_throwers_are_sibcalls;
args_size = old_args_size = 0;
#ifdef DWARF2_DEBUGGING_INFO
if (file)
dwarf2out_source_line (line, file);
#endif
}
void
dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED)
{
dw_fde_ref fde;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
current_function_funcdef_no);
ASM_OUTPUT_LABEL (asm_out_file, label);
fde = &fde_table[fde_table_in_use - 1];
fde->dw_fde_end = xstrdup (label);
}
void
dwarf2out_frame_init (void)
{
fde_table = ggc_alloc_cleared (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
fde_table_allocated = FDE_TABLE_INCREMENT;
fde_table_in_use = 0;
dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
#ifdef DWARF2_UNWIND_INFO
if (DWARF2_UNWIND_INFO)
initial_return_save (INCOMING_RETURN_ADDR_RTX);
#endif
}
void
dwarf2out_frame_finish (void)
{
if (DWARF2_FRAME_INFO)
output_call_frame_info (0);
#ifndef TARGET_UNWIND_INFO
if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
output_call_frame_info (1);
#endif
}
#endif
struct dwarf_file_data GTY(())
{
const char * filename;
int emitted_number;
};
#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;
typedef struct dw_loc_list_struct *dw_loc_list_ref;
enum dw_val_class
{
dw_val_class_addr,
dw_val_class_offset,
dw_val_class_loc,
dw_val_class_loc_list,
dw_val_class_range_list,
dw_val_class_const,
dw_val_class_unsigned_const,
dw_val_class_long_long,
dw_val_class_vec,
dw_val_class_flag,
dw_val_class_die_ref,
dw_val_class_fde_ref,
dw_val_class_lbl_id,
dw_val_class_lineptr,
dw_val_class_str,
dw_val_class_macptr,
dw_val_class_file
};
typedef struct dw_long_long_struct GTY(())
{
unsigned long hi;
unsigned long low;
}
dw_long_long_const;
typedef struct dw_vec_struct GTY(())
{
unsigned char * GTY((length ("%h.length"))) array;
unsigned length;
unsigned elt_size;
}
dw_vec_const;
typedef struct dw_val_struct GTY(())
{
enum dw_val_class val_class;
union dw_val_struct_union
{
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_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
struct dw_val_die_union
{
dw_die_ref die;
int external;
} 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;
struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
}
GTY ((desc ("%1.val_class"))) v;
}
dw_val_node;
typedef struct dw_loc_descr_struct GTY(())
{
dw_loc_descr_ref dw_loc_next;
enum dwarf_location_atom dw_loc_opc;
dw_val_node dw_loc_oprnd1;
dw_val_node dw_loc_oprnd2;
int dw_loc_addr;
}
dw_loc_descr_node;
typedef struct dw_loc_list_struct GTY(())
{
dw_loc_list_ref dw_loc_next;
const char *begin;
const char *end;
char *ll_symbol;
const char *section;
dw_loc_descr_ref expr;
} dw_loc_list_node;
#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);
static const char *
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";
case DW_OP_const1u:
return "DW_OP_const1u";
case DW_OP_const1s:
return "DW_OP_const1s";
case DW_OP_const2u:
return "DW_OP_const2u";
case DW_OP_const2s:
return "DW_OP_const2s";
case DW_OP_const4u:
return "DW_OP_const4u";
case DW_OP_const4s:
return "DW_OP_const4s";
case DW_OP_const8u:
return "DW_OP_const8u";
case DW_OP_const8s:
return "DW_OP_const8s";
case DW_OP_constu:
return "DW_OP_constu";
case DW_OP_consts:
return "DW_OP_consts";
case DW_OP_dup:
return "DW_OP_dup";
case DW_OP_drop:
return "DW_OP_drop";
case DW_OP_over:
return "DW_OP_over";
case DW_OP_pick:
return "DW_OP_pick";
case DW_OP_swap:
return "DW_OP_swap";
case DW_OP_rot:
return "DW_OP_rot";
case DW_OP_xderef:
return "DW_OP_xderef";
case DW_OP_abs:
return "DW_OP_abs";
case DW_OP_and:
return "DW_OP_and";
case DW_OP_div:
return "DW_OP_div";
case DW_OP_minus:
return "DW_OP_minus";
case DW_OP_mod:
return "DW_OP_mod";
case DW_OP_mul:
return "DW_OP_mul";
case DW_OP_neg:
return "DW_OP_neg";
case DW_OP_not:
return "DW_OP_not";
case DW_OP_or:
return "DW_OP_or";
case DW_OP_plus:
return "DW_OP_plus";
case DW_OP_plus_uconst:
return "DW_OP_plus_uconst";
case DW_OP_shl:
return "DW_OP_shl";
case DW_OP_shr:
return "DW_OP_shr";
case DW_OP_shra:
return "DW_OP_shra";
case DW_OP_xor:
return "DW_OP_xor";
case DW_OP_bra:
return "DW_OP_bra";
case DW_OP_eq:
return "DW_OP_eq";
case DW_OP_ge:
return "DW_OP_ge";
case DW_OP_gt:
return "DW_OP_gt";
case DW_OP_le:
return "DW_OP_le";
case DW_OP_lt:
return "DW_OP_lt";
case DW_OP_ne:
return "DW_OP_ne";
case DW_OP_skip:
return "DW_OP_skip";
case DW_OP_lit0:
return "DW_OP_lit0";
case DW_OP_lit1:
return "DW_OP_lit1";
case DW_OP_lit2:
return "DW_OP_lit2";
case DW_OP_lit3:
return "DW_OP_lit3";
case DW_OP_lit4:
return "DW_OP_lit4";
case DW_OP_lit5:
return "DW_OP_lit5";
case DW_OP_lit6:
return "DW_OP_lit6";
case DW_OP_lit7:
return "DW_OP_lit7";
case DW_OP_lit8:
return "DW_OP_lit8";
case DW_OP_lit9:
return "DW_OP_lit9";
case DW_OP_lit10:
return "DW_OP_lit10";
case DW_OP_lit11:
return "DW_OP_lit11";
case DW_OP_lit12:
return "DW_OP_lit12";
case DW_OP_lit13:
return "DW_OP_lit13";
case DW_OP_lit14:
return "DW_OP_lit14";
case DW_OP_lit15:
return "DW_OP_lit15";
case DW_OP_lit16:
return "DW_OP_lit16";
case DW_OP_lit17:
return "DW_OP_lit17";
case DW_OP_lit18:
return "DW_OP_lit18";
case DW_OP_lit19:
return "DW_OP_lit19";
case DW_OP_lit20:
return "DW_OP_lit20";
case DW_OP_lit21:
return "DW_OP_lit21";
case DW_OP_lit22:
return "DW_OP_lit22";
case DW_OP_lit23:
return "DW_OP_lit23";
case DW_OP_lit24:
return "DW_OP_lit24";
case DW_OP_lit25:
return "DW_OP_lit25";
case DW_OP_lit26:
return "DW_OP_lit26";
case DW_OP_lit27:
return "DW_OP_lit27";
case DW_OP_lit28:
return "DW_OP_lit28";
case DW_OP_lit29:
return "DW_OP_lit29";
case DW_OP_lit30:
return "DW_OP_lit30";
case DW_OP_lit31:
return "DW_OP_lit31";
case DW_OP_reg0:
return "DW_OP_reg0";
case DW_OP_reg1:
return "DW_OP_reg1";
case DW_OP_reg2:
return "DW_OP_reg2";
case DW_OP_reg3:
return "DW_OP_reg3";
case DW_OP_reg4:
return "DW_OP_reg4";
case DW_OP_reg5:
return "DW_OP_reg5";
case DW_OP_reg6:
return "DW_OP_reg6";
case DW_OP_reg7:
return "DW_OP_reg7";
case DW_OP_reg8:
return "DW_OP_reg8";
case DW_OP_reg9:
return "DW_OP_reg9";
case DW_OP_reg10:
return "DW_OP_reg10";
case DW_OP_reg11:
return "DW_OP_reg11";
case DW_OP_reg12:
return "DW_OP_reg12";
case DW_OP_reg13:
return "DW_OP_reg13";
case DW_OP_reg14:
return "DW_OP_reg14";
case DW_OP_reg15:
return "DW_OP_reg15";
case DW_OP_reg16:
return "DW_OP_reg16";
case DW_OP_reg17:
return "DW_OP_reg17";
case DW_OP_reg18:
return "DW_OP_reg18";
case DW_OP_reg19:
return "DW_OP_reg19";
case DW_OP_reg20:
return "DW_OP_reg20";
case DW_OP_reg21:
return "DW_OP_reg21";
case DW_OP_reg22:
return "DW_OP_reg22";
case DW_OP_reg23:
return "DW_OP_reg23";
case DW_OP_reg24:
return "DW_OP_reg24";
case DW_OP_reg25:
return "DW_OP_reg25";
case DW_OP_reg26:
return "DW_OP_reg26";
case DW_OP_reg27:
return "DW_OP_reg27";
case DW_OP_reg28:
return "DW_OP_reg28";
case DW_OP_reg29:
return "DW_OP_reg29";
case DW_OP_reg30:
return "DW_OP_reg30";
case DW_OP_reg31:
return "DW_OP_reg31";
case DW_OP_breg0:
return "DW_OP_breg0";
case DW_OP_breg1:
return "DW_OP_breg1";
case DW_OP_breg2:
return "DW_OP_breg2";
case DW_OP_breg3:
return "DW_OP_breg3";
case DW_OP_breg4:
return "DW_OP_breg4";
case DW_OP_breg5:
return "DW_OP_breg5";
case DW_OP_breg6:
return "DW_OP_breg6";
case DW_OP_breg7:
return "DW_OP_breg7";
case DW_OP_breg8:
return "DW_OP_breg8";
case DW_OP_breg9:
return "DW_OP_breg9";
case DW_OP_breg10:
return "DW_OP_breg10";
case DW_OP_breg11:
return "DW_OP_breg11";
case DW_OP_breg12:
return "DW_OP_breg12";
case DW_OP_breg13:
return "DW_OP_breg13";
case DW_OP_breg14:
return "DW_OP_breg14";
case DW_OP_breg15:
return "DW_OP_breg15";
case DW_OP_breg16:
return "DW_OP_breg16";
case DW_OP_breg17:
return "DW_OP_breg17";
case DW_OP_breg18:
return "DW_OP_breg18";
case DW_OP_breg19:
return "DW_OP_breg19";
case DW_OP_breg20:
return "DW_OP_breg20";
case DW_OP_breg21:
return "DW_OP_breg21";
case DW_OP_breg22:
return "DW_OP_breg22";
case DW_OP_breg23:
return "DW_OP_breg23";
case DW_OP_breg24:
return "DW_OP_breg24";
case DW_OP_breg25:
return "DW_OP_breg25";
case DW_OP_breg26:
return "DW_OP_breg26";
case DW_OP_breg27:
return "DW_OP_breg27";
case DW_OP_breg28:
return "DW_OP_breg28";
case DW_OP_breg29:
return "DW_OP_breg29";
case DW_OP_breg30:
return "DW_OP_breg30";
case DW_OP_breg31:
return "DW_OP_breg31";
case DW_OP_regx:
return "DW_OP_regx";
case DW_OP_fbreg:
return "DW_OP_fbreg";
case DW_OP_bregx:
return "DW_OP_bregx";
case DW_OP_piece:
return "DW_OP_piece";
case DW_OP_bit_piece:
return "DW_OP_bit_piece";
case DW_OP_deref_size:
return "DW_OP_deref_size";
case DW_OP_xderef_size:
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";
case DW_OP_APPLE_uninit:
return "DW_OP_APPLE_uninit";
default:
return "OP_<unknown>";
}
}
static inline dw_loc_descr_ref
new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
unsigned HOST_WIDE_INT oprnd2)
{
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;
descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
return descr;
}
static inline void
add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
{
dw_loc_descr_ref *d;
for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
;
*d = descr;
}
static unsigned long
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_const1s:
size += 1;
break;
case DW_OP_const2u:
case DW_OP_const2s:
size += 2;
break;
case DW_OP_const4u:
case DW_OP_const4s:
size += 4;
break;
case DW_OP_const8u:
case DW_OP_const8s:
size += 8;
break;
case DW_OP_constu:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_consts:
size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
break;
case DW_OP_pick:
size += 1;
break;
case DW_OP_plus_uconst:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_skip:
case DW_OP_bra:
size += 2;
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
break;
case DW_OP_regx:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_fbreg:
size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
break;
case DW_OP_bregx:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
break;
case DW_OP_piece:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_bit_piece:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
size += size_of_uleb128 (loc->dw_loc_oprnd2.v.val_unsigned);
break;
case DW_OP_deref_size:
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 size;
}
static unsigned long
size_of_locs (dw_loc_descr_ref loc)
{
dw_loc_descr_ref l;
unsigned long size;
for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
{
if (l->dw_loc_opc == DW_OP_skip || l->dw_loc_opc == DW_OP_bra)
break;
size += size_of_loc_descr (l);
}
if (! l)
return size;
for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
{
l->dw_loc_addr = size;
size += size_of_loc_descr (l);
}
return size;
}
static void
output_loc_operands (dw_loc_descr_ref loc)
{
dw_val_ref val1 = &loc->dw_loc_oprnd1;
dw_val_ref val2 = &loc->dw_loc_oprnd2;
switch (loc->dw_loc_opc)
{
#ifdef DWARF2_DEBUGGING_INFO
case DW_OP_addr:
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
break;
case DW_OP_const2u:
case DW_OP_const2s:
dw2_asm_output_data (2, val1->v.val_int, NULL);
break;
case DW_OP_const4u:
case DW_OP_const4s:
dw2_asm_output_data (4, val1->v.val_int, NULL);
break;
case DW_OP_const8u:
case DW_OP_const8s:
gcc_assert (HOST_BITS_PER_LONG >= 64);
dw2_asm_output_data (8, val1->v.val_int, NULL);
break;
case DW_OP_skip:
case DW_OP_bra:
{
int offset;
gcc_assert (val1->val_class == dw_val_class_loc);
offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
dw2_asm_output_data (2, offset, NULL);
}
break;
#else
case DW_OP_addr:
case DW_OP_const2u:
case DW_OP_const2s:
case DW_OP_const4u:
case DW_OP_const4s:
case DW_OP_const8u:
case DW_OP_const8s:
case DW_OP_skip:
case DW_OP_bra:
gcc_unreachable ();
#endif
case DW_OP_const1u:
case DW_OP_const1s:
dw2_asm_output_data (1, val1->v.val_int, NULL);
break;
case DW_OP_constu:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
break;
case DW_OP_consts:
dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
break;
case DW_OP_pick:
dw2_asm_output_data (1, val1->v.val_int, NULL);
break;
case DW_OP_plus_uconst:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
break;
case DW_OP_regx:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
break;
case DW_OP_fbreg:
dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
break;
case DW_OP_bregx:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
break;
case DW_OP_piece:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
break;
case DW_OP_bit_piece:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
dw2_asm_output_data_uleb128 (val2->v.val_unsigned, NULL);
break;
case DW_OP_deref_size:
case DW_OP_xderef_size:
dw2_asm_output_data (1, val1->v.val_int, NULL);
break;
case INTERNAL_DW_OP_tls_addr:
if (targetm.asm_out.output_dwarf_dtprel)
{
targetm.asm_out.output_dwarf_dtprel (asm_out_file,
DWARF2_ADDR_SIZE,
val1->v.val_addr);
fputc ('\n', asm_out_file);
}
else
gcc_unreachable ();
break;
default:
break;
}
}
static void
output_loc_sequence (dw_loc_descr_ref loc)
{
for (; loc != NULL; loc = loc->dw_loc_next)
{
dw2_asm_output_data (1, loc->dw_loc_opc,
"%s", dwarf_stack_op_name (loc->dw_loc_opc));
output_loc_operands (loc);
}
}
static void
output_cfa_loc (dw_cfi_ref cfi)
{
dw_loc_descr_ref loc;
unsigned long size;
loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
size = size_of_locs (loc);
dw2_asm_output_data_uleb128 (size, NULL);
output_loc_sequence (loc);
}
static struct dw_loc_descr_struct *
build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
{
struct dw_loc_descr_struct *head, *tmp;
offset += cfa->offset;
if (cfa->indirect)
{
if (cfa->base_offset)
{
if (cfa->reg <= 31)
head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
else
head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
}
else if (cfa->reg <= 31)
head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
else
head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
head->dw_loc_oprnd1.val_class = dw_val_class_const;
tmp = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (&head, tmp);
if (offset != 0)
{
tmp = new_loc_descr (DW_OP_plus_uconst, offset, 0);
add_loc_descr (&head, tmp);
}
}
else
{
if (offset == 0)
if (cfa->reg <= 31)
head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
else
head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
else if (cfa->reg <= 31)
head = new_loc_descr (DW_OP_breg0 + cfa->reg, offset, 0);
else
head = new_loc_descr (DW_OP_bregx, cfa->reg, offset);
}
return head;
}
static void
get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_struct *loc)
{
struct dw_loc_descr_struct *ptr;
cfa->offset = 0;
cfa->base_offset = 0;
cfa->indirect = 0;
cfa->reg = -1;
for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next)
{
enum dwarf_location_atom op = ptr->dw_loc_opc;
switch (op)
{
case DW_OP_reg0:
case DW_OP_reg1:
case DW_OP_reg2:
case DW_OP_reg3:
case DW_OP_reg4:
case DW_OP_reg5:
case DW_OP_reg6:
case DW_OP_reg7:
case DW_OP_reg8:
case DW_OP_reg9:
case DW_OP_reg10:
case DW_OP_reg11:
case DW_OP_reg12:
case DW_OP_reg13:
case DW_OP_reg14:
case DW_OP_reg15:
case DW_OP_reg16:
case DW_OP_reg17:
case DW_OP_reg18:
case DW_OP_reg19:
case DW_OP_reg20:
case DW_OP_reg21:
case DW_OP_reg22:
case DW_OP_reg23:
case DW_OP_reg24:
case DW_OP_reg25:
case DW_OP_reg26:
case DW_OP_reg27:
case DW_OP_reg28:
case DW_OP_reg29:
case DW_OP_reg30:
case DW_OP_reg31:
cfa->reg = op - DW_OP_reg0;
break;
case DW_OP_regx:
cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
cfa->reg = op - DW_OP_breg0;
cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
break;
case DW_OP_bregx:
cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int;
break;
case DW_OP_deref:
cfa->indirect = 1;
break;
case DW_OP_plus_uconst:
cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
break;
default:
internal_error ("DW_LOC_OP %s not implemented",
dwarf_stack_op_name (ptr->dw_loc_opc));
}
}
}
#endif
#ifdef DWARF2_DEBUGGING_INFO
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_type_decl (tree, int);
static void dwarf2out_imported_module_or_decl (tree, tree);
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx);
static void dwarf2out_begin_function (tree);
static void dwarf2out_od_entry (enum debug_od_msg, expanded_location);
static void dwarf2out_switch_text_section (void);
const struct gcc_debug_hooks dwarf2_debug_hooks =
{
dwarf2out_init,
dwarf2out_finish,
dwarf2out_define,
dwarf2out_undef,
dwarf2out_start_source_file,
dwarf2out_end_source_file,
dwarf2out_begin_block,
dwarf2out_end_block,
dwarf2out_ignore_block,
dwarf2out_source_line,
dwarf2out_begin_prologue,
debug_nothing_int_charstar,
dwarf2out_end_epilogue,
dwarf2out_begin_function,
debug_nothing_int,
dwarf2out_decl,
dwarf2out_global_decl,
dwarf2out_type_decl,
dwarf2out_imported_module_or_decl,
debug_nothing_tree,
dwarf2out_abstract_function,
debug_nothing_rtx,
debug_nothing_int,
dwarf2out_var_location,
dwarf2out_od_entry,
dwarf2out_switch_text_section,
1
};
#endif
typedef long int dw_offset;
typedef struct dw_attr_struct *dw_attr_ref;
typedef struct dw_line_info_struct *dw_line_info_ref;
typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
typedef struct pubname_struct *pubname_ref;
typedef struct dw_ranges_struct *dw_ranges_ref;
typedef struct inlined_entry_struct *inlined_ref;
typedef struct dw_line_info_struct GTY(())
{
unsigned long dw_file_num;
unsigned long dw_line_num;
}
dw_line_info_entry;
typedef struct dw_separate_line_info_struct GTY(())
{
unsigned long dw_file_num;
unsigned long dw_line_num;
unsigned long function;
}
dw_separate_line_info_entry;
typedef struct dw_attr_struct GTY(())
{
enum dwarf_attribute dw_attr;
dw_val_node dw_attr_val;
}
dw_attr_node;
DEF_VEC_O(dw_attr_node);
DEF_VEC_ALLOC_O(dw_attr_node,gc);
typedef struct die_struct GTY(())
{
enum dwarf_tag die_tag;
char *die_symbol;
VEC(dw_attr_node,gc) * die_attr;
dw_die_ref die_parent;
dw_die_ref die_child;
dw_die_ref die_sib;
dw_die_ref die_definition;
dw_offset die_offset;
unsigned long die_abbrev;
int die_mark;
int die_perennial_p;
unsigned int decl_id;
bool dead;
}
die_node;
#define FOR_EACH_CHILD(die, c, expr) do { \
c = die->die_child; \
if (c) do { \
c = c->die_sib; \
expr; \
} while (c != die->die_child); \
} while (0)
typedef struct pubname_struct GTY(())
{
dw_die_ref die;
char *name;
}
pubname_entry;
DEF_VEC_O(pubname_entry);
DEF_VEC_ALLOC_O(pubname_entry, gc);
DEF_VEC_O(dw_die_ref);
DEF_VEC_ALLOC_O(dw_die_ref, gc);
typedef struct inlined_entry_struct GTY (())
{
dw_die_ref origin_die;
VEC(dw_die_ref,gc) *inlined_instances;
}
inlined_entry;
DEF_VEC_O(inlined_entry);
DEF_VEC_ALLOC_O(inlined_entry, gc);
struct dw_ranges_struct GTY(())
{
int block_num;
};
typedef struct limbo_die_struct GTY(())
{
dw_die_ref die;
tree created_for;
struct limbo_die_struct *next;
}
limbo_die_node;
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
#endif
#define TYPE_DECL_IS_STUB(decl) \
(DECL_NAME (decl) == NULL_TREE \
|| (DECL_ARTIFICIAL (decl) \
&& is_tagged_type (TREE_TYPE (decl)) \
&& ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \
\
|| (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \
&& (decl_ultimate_origin (decl) \
== TYPE_STUB_DECL (TREE_TYPE (decl)))))))
#define DWARF_COMPILE_UNIT_HEADER_SIZE \
(DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
#define DWARF_INLINED_HEADER_SIZE (3)
#define DWARF_ARANGES_HEADER_SIZE \
(DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
DWARF2_ADDR_SIZE * 2) \
- DWARF_INITIAL_LENGTH_SIZE)
#define DWARF_ARANGES_PAD_SIZE \
(DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
DWARF2_ADDR_SIZE * 2) \
- (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4))
#ifndef DWARF2_ASM_LINE_DEBUG_INFO
#ifdef HAVE_AS_DWARF2_DEBUG_LINE
#define DWARF2_ASM_LINE_DEBUG_INFO 1
#else
#define DWARF2_ASM_LINE_DEBUG_INFO 0
#endif
#endif
#define DWARF_LINE_BASE -10
#define DWARF_LINE_OPCODE_BASE 10
#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1)
#define DWARF_LINE_DEFAULT_IS_STMT_START 1
#ifdef DWARF2_DEBUGGING_INFO
static unsigned long next_die_offset;
#endif
static GTY(()) dw_die_ref comp_unit_die;
static GTY(()) limbo_die_node *limbo_die_list;
static GTY((param_is (struct dwarf_file_data))) htab_t file_table;
static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
struct var_loc_node GTY ((chain_next ("%h.next")))
{
rtx GTY (()) var_loc_note;
const char * GTY (()) label;
const char * GTY (()) section_label;
struct var_loc_node * GTY (()) next;
};
struct var_loc_list_def GTY (())
{
struct var_loc_node * GTY (()) first;
struct var_loc_node * GTY ((skip ("%h"))) last;
unsigned int decl_id;
};
typedef struct var_loc_list_def var_loc_list;
static GTY ((param_is (var_loc_list))) htab_t decl_loc_table;
static GTY((length ("abbrev_die_table_allocated")))
dw_die_ref *abbrev_die_table;
static GTY(()) unsigned abbrev_die_table_allocated;
static GTY(()) unsigned abbrev_die_table_in_use;
#define ABBREV_DIE_TABLE_INCREMENT 256
static GTY((length ("line_info_table_allocated")))
dw_line_info_ref line_info_table;
static GTY(()) unsigned line_info_table_allocated;
static GTY(()) unsigned line_info_table_in_use;
static GTY(()) bool have_multiple_function_sections = false;
static GTY ((length ("separate_line_info_table_allocated")))
dw_separate_line_info_ref separate_line_info_table;
static GTY(()) unsigned separate_line_info_table_allocated;
static GTY(()) unsigned separate_line_info_table_in_use;
#define LINE_INFO_TABLE_INCREMENT 1024
static GTY (()) VEC (pubname_entry, gc) * pubname_table;
static GTY (()) VEC (pubname_entry, gc) * pubtype_table;
static GTY (()) VEC (inlined_entry, gc) * debug_inlined_table;
static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table;
static GTY(()) unsigned arange_table_allocated;
static GTY(()) unsigned arange_table_in_use;
#define ARANGE_TABLE_INCREMENT 64
static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table;
static GTY(()) unsigned ranges_table_allocated;
static GTY(()) unsigned ranges_table_in_use;
#define RANGES_TABLE_INCREMENT 64
static GTY(()) bool have_location_lists;
static GTY(()) unsigned int loclabel_num;
#ifdef DWARF2_DEBUGGING_INFO
static int current_function_has_inlines;
#endif
#if 0 && defined (MIPS_DEBUGGING_INFO)
static int comp_unit_has_inlines;
#endif
static GTY(()) struct dwarf_file_data * last_emitted_file;
static GTY(()) int label_num;
static GTY(()) struct dwarf_file_data * file_table_last_lookup;
#ifdef DWARF2_DEBUGGING_INFO
static HOST_WIDE_INT frame_pointer_fb_offset;
static rtx frame_pointer_fb_offset_from;
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);
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 inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
unsigned int, unsigned char *);
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 void add_AT_specification (dw_die_ref, 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_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_macptr (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_objc (void);
static bool is_objcxx (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 void remove_child_TAG (dw_die_ref, enum dwarf_tag);
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 hashval_t decl_die_table_hash (const void *);
static int decl_die_table_eq (const void *, const void *);
static dw_die_ref lookup_decl_die (tree);
static hashval_t decl_loc_table_hash (const void *);
static int decl_loc_table_eq (const void *, const void *);
static var_loc_list *lookup_decl_loc (tree);
static void equate_decl_number_to_die (tree, dw_die_ref);
static void add_var_loc_to_decl (tree, struct var_loc_node *);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, FILE *);
static void print_dwarf_line_table (FILE *);
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 (VEC (pubname_entry,gc) *);
static unsigned long size_of_inlined (VEC (inlined_entry,gc) *);
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 add_pubtype (tree, dw_die_ref);
static void output_pubnames (VEC (pubname_entry,gc) *);
static void add_inlined_section_entry (dw_die_ref);
static void output_debug_inlined_section (VEC (inlined_entry,gc) *);
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_subrange_type (tree);
static dw_die_ref subrange_type_die (tree, dw_die_ref);
static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
static int type_is_enum (tree);
static unsigned int dbx_reg_number (rtx);
static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
static dw_loc_descr_ref reg_loc_descriptor (rtx, enum var_init_status);
static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int,
enum var_init_status);
static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
enum var_init_status);
static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
enum var_init_status);
static int is_based_loc (rtx);
static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
enum var_init_status);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
enum var_init_status);
static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status);
static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
static dw_loc_descr_ref loc_descriptor_from_tree (tree);
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 void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
static void insert_float (rtx, unsigned char *);
static rtx rtl_for_decl_location (tree);
static void add_location_or_const_value_attribute (dw_die_ref, tree,
enum dwarf_attribute);
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_or_namespace_scope_p (dw_die_ref);
static void add_type_attribute (dw_die_ref, tree, int, int, dw_die_ref);
static void add_calling_convention_attribute (dw_die_ref, tree);
static const char *type_tag (tree);
static tree member_declared_type (tree);
#if 0
static const char *decl_start_label (tree);
#endif
static void gen_array_type_die (tree, dw_die_ref);
#if 0
static void gen_entry_point_die (tree, dw_die_ref);
#endif
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 dw_die_ref 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_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_namespace_die (tree);
static void gen_decl_die (tree, dw_die_ref);
static dw_die_ref force_decl_die (tree);
static dw_die_ref force_type_die (tree);
static dw_die_ref setup_namespace_context (tree, dw_die_ref);
static void declare_in_namespace (tree, dw_die_ref);
static struct dwarf_file_data * lookup_filename (const char *);
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 (struct dwarf_file_data *fd);
#ifndef DEBUG_INFO_SECTION
#define DEBUG_INFO_SECTION ".debug_info"
#endif
#ifndef DEBUG_ABBREV_SECTION
#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
#ifndef DEBUG_ARANGES_SECTION
#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
#ifndef DEBUG_MACINFO_SECTION
#define DEBUG_MACINFO_SECTION ".debug_macinfo"
#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
#ifndef DEBUG_LOC_SECTION
#define DEBUG_LOC_SECTION ".debug_loc"
#endif
#ifndef DEBUG_PUBNAMES_SECTION
#define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
#endif
#ifndef DEBUG_STR_SECTION
#define DEBUG_STR_SECTION ".debug_str"
#endif
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
#endif
#ifndef TEXT_SECTION_NAME
#define TEXT_SECTION_NAME ".text"
#endif
#define DEBUG_STR_SECTION_FLAGS \
(HAVE_GAS_SHF_MERGE && flag_merge_constants \
? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \
: SECTION_DEBUG)
#ifndef TEXT_SECTION_LABEL
#define TEXT_SECTION_LABEL "Ltext"
#endif
#ifndef COLD_TEXT_SECTION_LABEL
#define COLD_TEXT_SECTION_LABEL "Ltext_cold"
#endif
#ifndef DEBUG_LINE_SECTION_LABEL
#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
#endif
#ifndef DEBUG_INFO_SECTION_LABEL
#define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
#endif
#ifndef DEBUG_ABBREV_SECTION_LABEL
#define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev"
#endif
#ifndef DEBUG_LOC_SECTION_LABEL
#define DEBUG_LOC_SECTION_LABEL "Ldebug_loc"
#endif
#ifndef DEBUG_RANGES_SECTION_LABEL
#define DEBUG_RANGES_SECTION_LABEL "Ldebug_ranges"
#endif
#ifndef DEBUG_MACINFO_SECTION_LABEL
#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
#endif
static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
#ifndef TEXT_END_LABEL
#define TEXT_END_LABEL "Letext"
#endif
#ifndef COLD_END_LABEL
#define COLD_END_LABEL "Letext_cold"
#endif
#ifndef BLOCK_BEGIN_LABEL
#define BLOCK_BEGIN_LABEL "LBB"
#endif
#ifndef BLOCK_END_LABEL
#define BLOCK_END_LABEL "LBE"
#endif
#ifndef LINE_CODE_LABEL
#define LINE_CODE_LABEL "LM"
#endif
#ifndef SEPARATE_LINE_CODE_LABEL
#define SEPARATE_LINE_CODE_LABEL "LSM"
#endif
static const char *(*demangle_name_func) (const char *);
void
dwarf2out_set_demangle_name_func (const char *(*func) (const char *))
{
demangle_name_func = func;
}
static inline int
is_pseudo_reg (rtx rtl)
{
return ((REG_P (rtl) && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
|| (GET_CODE (rtl) == SUBREG
&& REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
}
static inline tree
type_main_variant (tree type)
{
type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE)
while (type != TYPE_MAIN_VARIANT (type))
type = TYPE_MAIN_VARIANT (type);
return type;
}
static inline int
is_tagged_type (tree type)
{
enum tree_code code = TREE_CODE (type);
return (code == RECORD_TYPE || code == UNION_TYPE
|| code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
}
static const char *
dwarf_tag_name (unsigned int tag)
{
switch (tag)
{
case DW_TAG_padding:
return "DW_TAG_padding";
case DW_TAG_array_type:
return "DW_TAG_array_type";
case DW_TAG_class_type:
return "DW_TAG_class_type";
case DW_TAG_entry_point:
return "DW_TAG_entry_point";
case DW_TAG_enumeration_type:
return "DW_TAG_enumeration_type";
case DW_TAG_formal_parameter:
return "DW_TAG_formal_parameter";
case DW_TAG_imported_declaration:
return "DW_TAG_imported_declaration";
case DW_TAG_label:
return "DW_TAG_label";
case DW_TAG_lexical_block:
return "DW_TAG_lexical_block";
case DW_TAG_member:
return "DW_TAG_member";
case DW_TAG_pointer_type:
return "DW_TAG_pointer_type";
case DW_TAG_reference_type:
return "DW_TAG_reference_type";
case DW_TAG_compile_unit:
return "DW_TAG_compile_unit";
case DW_TAG_string_type:
return "DW_TAG_string_type";
case DW_TAG_structure_type:
return "DW_TAG_structure_type";
case DW_TAG_subroutine_type:
return "DW_TAG_subroutine_type";
case DW_TAG_typedef:
return "DW_TAG_typedef";
case DW_TAG_union_type:
return "DW_TAG_union_type";
case DW_TAG_unspecified_parameters:
return "DW_TAG_unspecified_parameters";
case DW_TAG_variant:
return "DW_TAG_variant";
case DW_TAG_common_block:
return "DW_TAG_common_block";
case DW_TAG_common_inclusion:
return "DW_TAG_common_inclusion";
case DW_TAG_inheritance:
return "DW_TAG_inheritance";
case DW_TAG_inlined_subroutine:
return "DW_TAG_inlined_subroutine";
case DW_TAG_module:
return "DW_TAG_module";
case DW_TAG_ptr_to_member_type:
return "DW_TAG_ptr_to_member_type";
case DW_TAG_set_type:
return "DW_TAG_set_type";
case DW_TAG_subrange_type:
return "DW_TAG_subrange_type";
case DW_TAG_with_stmt:
return "DW_TAG_with_stmt";
case DW_TAG_access_declaration:
return "DW_TAG_access_declaration";
case DW_TAG_base_type:
return "DW_TAG_base_type";
case DW_TAG_catch_block:
return "DW_TAG_catch_block";
case DW_TAG_const_type:
return "DW_TAG_const_type";
case DW_TAG_constant:
return "DW_TAG_constant";
case DW_TAG_enumerator:
return "DW_TAG_enumerator";
case DW_TAG_file_type:
return "DW_TAG_file_type";
case DW_TAG_friend:
return "DW_TAG_friend";
case DW_TAG_namelist:
return "DW_TAG_namelist";
case DW_TAG_namelist_item:
return "DW_TAG_namelist_item";
case DW_TAG_namespace:
return "DW_TAG_namespace";
case DW_TAG_packed_type:
return "DW_TAG_packed_type";
case DW_TAG_subprogram:
return "DW_TAG_subprogram";
case DW_TAG_template_type_param:
return "DW_TAG_template_type_param";
case DW_TAG_template_value_param:
return "DW_TAG_template_value_param";
case DW_TAG_thrown_type:
return "DW_TAG_thrown_type";
case DW_TAG_try_block:
return "DW_TAG_try_block";
case DW_TAG_variant_part:
return "DW_TAG_variant_part";
case DW_TAG_variable:
return "DW_TAG_variable";
case DW_TAG_volatile_type:
return "DW_TAG_volatile_type";
case DW_TAG_imported_module:
return "DW_TAG_imported_module";
case DW_TAG_MIPS_loop:
return "DW_TAG_MIPS_loop";
case DW_TAG_format_label:
return "DW_TAG_format_label";
case DW_TAG_function_template:
return "DW_TAG_function_template";
case DW_TAG_class_template:
return "DW_TAG_class_template";
case DW_TAG_GNU_BINCL:
return "DW_TAG_GNU_BINCL";
case DW_TAG_GNU_EINCL:
return "DW_TAG_GNU_EINCL";
case DW_TAG_GNU_OD_entry:
return "DW_TAG_GNU_OD_entry";
default:
return "DW_TAG_<unknown>";
}
}
static const char *
dwarf_attr_name (unsigned int attr)
{
switch (attr)
{
case DW_AT_sibling:
return "DW_AT_sibling";
case DW_AT_location:
return "DW_AT_location";
case DW_AT_name:
return "DW_AT_name";
case DW_AT_ordering:
return "DW_AT_ordering";
case DW_AT_subscr_data:
return "DW_AT_subscr_data";
case DW_AT_byte_size:
return "DW_AT_byte_size";
case DW_AT_bit_offset:
return "DW_AT_bit_offset";
case DW_AT_bit_size:
return "DW_AT_bit_size";
case DW_AT_element_list:
return "DW_AT_element_list";
case DW_AT_stmt_list:
return "DW_AT_stmt_list";
case DW_AT_low_pc:
return "DW_AT_low_pc";
case DW_AT_high_pc:
return "DW_AT_high_pc";
case DW_AT_language:
return "DW_AT_language";
case DW_AT_member:
return "DW_AT_member";
case DW_AT_discr:
return "DW_AT_discr";
case DW_AT_discr_value:
return "DW_AT_discr_value";
case DW_AT_visibility:
return "DW_AT_visibility";
case DW_AT_import:
return "DW_AT_import";
case DW_AT_string_length:
return "DW_AT_string_length";
case DW_AT_common_reference:
return "DW_AT_common_reference";
case DW_AT_comp_dir:
return "DW_AT_comp_dir";
case DW_AT_const_value:
return "DW_AT_const_value";
case DW_AT_containing_type:
return "DW_AT_containing_type";
case DW_AT_default_value:
return "DW_AT_default_value";
case DW_AT_inline:
return "DW_AT_inline";
case DW_AT_is_optional:
return "DW_AT_is_optional";
case DW_AT_lower_bound:
return "DW_AT_lower_bound";
case DW_AT_producer:
return "DW_AT_producer";
case DW_AT_prototyped:
return "DW_AT_prototyped";
case DW_AT_return_addr:
return "DW_AT_return_addr";
case DW_AT_start_scope:
return "DW_AT_start_scope";
case DW_AT_stride_size:
return "DW_AT_stride_size";
case DW_AT_upper_bound:
return "DW_AT_upper_bound";
case DW_AT_abstract_origin:
return "DW_AT_abstract_origin";
case DW_AT_accessibility:
return "DW_AT_accessibility";
case DW_AT_address_class:
return "DW_AT_address_class";
case DW_AT_artificial:
return "DW_AT_artificial";
case DW_AT_base_types:
return "DW_AT_base_types";
case DW_AT_calling_convention:
return "DW_AT_calling_convention";
case DW_AT_count:
return "DW_AT_count";
case DW_AT_data_member_location:
return "DW_AT_data_member_location";
case DW_AT_decl_column:
return "DW_AT_decl_column";
case DW_AT_decl_file:
return "DW_AT_decl_file";
case DW_AT_decl_line:
return "DW_AT_decl_line";
case DW_AT_declaration:
return "DW_AT_declaration";
case DW_AT_discr_list:
return "DW_AT_discr_list";
case DW_AT_encoding:
return "DW_AT_encoding";
case DW_AT_external:
return "DW_AT_external";
case DW_AT_frame_base:
return "DW_AT_frame_base";
case DW_AT_friend:
return "DW_AT_friend";
case DW_AT_identifier_case:
return "DW_AT_identifier_case";
case DW_AT_macro_info:
return "DW_AT_macro_info";
case DW_AT_namelist_items:
return "DW_AT_namelist_items";
case DW_AT_priority:
return "DW_AT_priority";
case DW_AT_segment:
return "DW_AT_segment";
case DW_AT_specification:
return "DW_AT_specification";
case DW_AT_static_link:
return "DW_AT_static_link";
case DW_AT_type:
return "DW_AT_type";
case DW_AT_use_location:
return "DW_AT_use_location";
case DW_AT_variable_parameter:
return "DW_AT_variable_parameter";
case DW_AT_virtuality:
return "DW_AT_virtuality";
case DW_AT_vtable_elem_location:
return "DW_AT_vtable_elem_location";
case DW_AT_allocated:
return "DW_AT_allocated";
case DW_AT_associated:
return "DW_AT_associated";
case DW_AT_data_location:
return "DW_AT_data_location";
case DW_AT_stride:
return "DW_AT_stride";
case DW_AT_entry_pc:
return "DW_AT_entry_pc";
case DW_AT_use_UTF8:
return "DW_AT_use_UTF8";
case DW_AT_extension:
return "DW_AT_extension";
case DW_AT_ranges:
return "DW_AT_ranges";
case DW_AT_trampoline:
return "DW_AT_trampoline";
case DW_AT_call_column:
return "DW_AT_call_column";
case DW_AT_call_file:
return "DW_AT_call_file";
case DW_AT_call_line:
return "DW_AT_call_line";
case DW_AT_MIPS_fde:
return "DW_AT_MIPS_fde";
case DW_AT_MIPS_loop_begin:
return "DW_AT_MIPS_loop_begin";
case DW_AT_MIPS_tail_loop_begin:
return "DW_AT_MIPS_tail_loop_begin";
case DW_AT_MIPS_epilog_begin:
return "DW_AT_MIPS_epilog_begin";
case DW_AT_MIPS_loop_unroll_factor:
return "DW_AT_MIPS_loop_unroll_factor";
case DW_AT_MIPS_software_pipeline_depth:
return "DW_AT_MIPS_software_pipeline_depth";
case DW_AT_MIPS_linkage_name:
return "DW_AT_MIPS_linkage_name";
case DW_AT_MIPS_stride:
return "DW_AT_MIPS_stride";
case DW_AT_MIPS_abstract_name:
return "DW_AT_MIPS_abstract_name";
case DW_AT_MIPS_clone_origin:
return "DW_AT_MIPS_clone_origin";
case DW_AT_MIPS_has_inlines:
return "DW_AT_MIPS_has_inlines";
case DW_AT_sf_names:
return "DW_AT_sf_names";
case DW_AT_src_info:
return "DW_AT_src_info";
case DW_AT_mac_info:
return "DW_AT_mac_info";
case DW_AT_src_coords:
return "DW_AT_src_coords";
case DW_AT_body_begin:
return "DW_AT_body_begin";
case DW_AT_body_end:
return "DW_AT_body_end";
case DW_AT_GNU_vector:
return "DW_AT_GNU_vector";
case DW_AT_GNU_OD_msg:
return "DW_AT_GNU_OD_msg";
case DW_AT_GNU_OD_category:
return "DW_AT_GNU_OD_category";
case DW_AT_GNU_OD_version:
return "DW_AT_GNU_OD_version";
case DW_AT_VMS_rtnbeg_pd_address:
return "DW_AT_VMS_rtnbeg_pd_address";
case DW_AT_APPLE_flags:
return "DW_AT_APPLE_flags";
case DW_AT_APPLE_optimized:
return "DW_AT_APPLE_optimized";
case DW_AT_APPLE_isa:
return "DW_AT_APPLE_isa";
case DW_AT_APPLE_block:
return "DW_AT_APPLE_block";
case DW_AT_APPLE_major_runtime_vers:
return "DW_AT_APPLE_major_runtime_vers";
case DW_AT_APPLE_runtime_class:
return "DW_AT_APPLE_runtime_class";
default:
return "DW_AT_<unknown>";
}
}
static const char *
dwarf_form_name (unsigned int form)
{
switch (form)
{
case DW_FORM_addr:
return "DW_FORM_addr";
case DW_FORM_block2:
return "DW_FORM_block2";
case DW_FORM_block4:
return "DW_FORM_block4";
case DW_FORM_data2:
return "DW_FORM_data2";
case DW_FORM_data4:
return "DW_FORM_data4";
case DW_FORM_data8:
return "DW_FORM_data8";
case DW_FORM_string:
return "DW_FORM_string";
case DW_FORM_block:
return "DW_FORM_block";
case DW_FORM_block1:
return "DW_FORM_block1";
case DW_FORM_data1:
return "DW_FORM_data1";
case DW_FORM_flag:
return "DW_FORM_flag";
case DW_FORM_sdata:
return "DW_FORM_sdata";
case DW_FORM_strp:
return "DW_FORM_strp";
case DW_FORM_udata:
return "DW_FORM_udata";
case DW_FORM_ref_addr:
return "DW_FORM_ref_addr";
case DW_FORM_ref1:
return "DW_FORM_ref1";
case DW_FORM_ref2:
return "DW_FORM_ref2";
case DW_FORM_ref4:
return "DW_FORM_ref4";
case DW_FORM_ref8:
return "DW_FORM_ref8";
case DW_FORM_ref_udata:
return "DW_FORM_ref_udata";
case DW_FORM_indirect:
return "DW_FORM_indirect";
default:
return "DW_FORM_<unknown>";
}
}
static tree
decl_ultimate_origin (tree decl)
{
if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
return NULL_TREE;
if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
return NULL_TREE;
gcc_assert (!DECL_FROM_INLINE (DECL_ORIGIN (decl)));
return DECL_ABSTRACT_ORIGIN (decl);
}
static tree
block_ultimate_origin (tree block)
{
tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
if (BLOCK_ABSTRACT (block) && immediate_origin == block)
return NULL_TREE;
if (immediate_origin == NULL_TREE)
return NULL_TREE;
else
{
tree ret_val;
tree lookahead = immediate_origin;
do
{
ret_val = lookahead;
lookahead = (TREE_CODE (ret_val) == BLOCK
? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
}
while (lookahead != NULL && lookahead != ret_val);
if (DECL_P (ret_val))
return DECL_ORIGIN (ret_val);
return ret_val;
}
}
static tree
decl_class_context (tree decl)
{
tree context = NULL_TREE;
if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
context = DECL_CONTEXT (decl);
else
context = TYPE_MAIN_VARIANT
(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
if (context && !TYPE_P (context))
context = NULL_TREE;
return context;
}
static inline void
add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
{
if (die == NULL)
return;
if (die->die_attr == NULL)
die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
}
static inline enum dw_val_class
AT_class (dw_attr_ref a)
{
return a->dw_attr_val.val_class;
}
static inline void
add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_flag;
attr.dw_attr_val.v.val_flag = flag;
add_dwarf_attr (die, &attr);
}
static inline unsigned
AT_flag (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_flag);
return a->dw_attr_val.v.val_flag;
}
static inline void
add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_const;
attr.dw_attr_val.v.val_int = int_val;
add_dwarf_attr (die, &attr);
}
static inline HOST_WIDE_INT
AT_int (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_const);
return a->dw_attr_val.v.val_int;
}
static inline void
add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned HOST_WIDE_INT unsigned_val)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
attr.dw_attr_val.v.val_unsigned = unsigned_val;
add_dwarf_attr (die, &attr);
}
static inline unsigned HOST_WIDE_INT
AT_unsigned (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
return a->dw_attr_val.v.val_unsigned;
}
static inline void
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_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_long_long;
attr.dw_attr_val.v.val_long_long.hi = val_hi;
attr.dw_attr_val.v.val_long_long.low = val_low;
add_dwarf_attr (die, &attr);
}
static inline void
add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned int length, unsigned int elt_size, unsigned char *array)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_vec;
attr.dw_attr_val.v.val_vec.length = length;
attr.dw_attr_val.v.val_vec.elt_size = elt_size;
attr.dw_attr_val.v.val_vec.array = array;
add_dwarf_attr (die, &attr);
}
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;
}
static inline void
add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
{
dw_attr_node attr;
struct indirect_string_node *node;
void **slot;
if (! debug_str_hash)
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++;
#ifdef DEBUG_INLINED_SECTION
if (die
&& die->die_tag == DW_TAG_subprogram
&& ((attr_kind == DW_AT_name)
|| (attr_kind == DW_AT_MIPS_linkage_name)))
node->is_fn_name = true;
#endif
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_str;
attr.dw_attr_val.v.val_str = node;
add_dwarf_attr (die, &attr);
}
static inline const char *
AT_string (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_str);
return a->dw_attr_val.v.val_str->str;
}
static int
AT_string_form (dw_attr_ref a)
{
struct indirect_string_node *node;
unsigned int len;
char label[32];
gcc_assert (a && AT_class (a) == dw_val_class_str);
node = a->dw_attr_val.v.val_str;
if (node->form)
return node->form;
len = strlen (node->str) + 1;
if ((len <= DWARF_OFFSET_SIZE || node->refcount == 0)
&& !node->is_fn_name)
return node->form = DW_FORM_string;
if ((debug_str_section->common.flags & SECTION_MERGE) == 0
&& (len - DWARF_OFFSET_SIZE) * node->refcount <= len
&& !node->is_fn_name)
return node->form = DW_FORM_string;
ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
++dw2_string_counter;
node->label = xstrdup (label);
return node->form = DW_FORM_strp;
}
static inline void
add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_die_ref;
attr.dw_attr_val.v.val_die_ref.die = targ_die;
attr.dw_attr_val.v.val_die_ref.external = 0;
add_dwarf_attr (die, &attr);
}
static inline void
add_AT_specification (dw_die_ref die, dw_die_ref targ_die)
{
add_AT_die_ref (die, DW_AT_specification, targ_die);
gcc_assert (!targ_die->die_definition);
targ_die->die_definition = die;
}
static inline dw_die_ref
AT_ref (dw_attr_ref a)
{
gcc_assert (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 (dw_attr_ref a)
{
if (a && AT_class (a) == dw_val_class_die_ref)
return a->dw_attr_val.v.val_die_ref.external;
return 0;
}
static inline void
set_AT_ref_external (dw_attr_ref a, int i)
{
gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
a->dw_attr_val.v.val_die_ref.external = i;
}
static inline void
add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_fde_ref;
attr.dw_attr_val.v.val_fde_index = targ_fde;
add_dwarf_attr (die, &attr);
}
static inline void
add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_loc;
attr.dw_attr_val.v.val_loc = loc;
add_dwarf_attr (die, &attr);
}
static inline dw_loc_descr_ref
AT_loc (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_loc);
return a->dw_attr_val.v.val_loc;
}
static inline void
add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_loc_list;
attr.dw_attr_val.v.val_loc_list = loc_list;
add_dwarf_attr (die, &attr);
have_location_lists = true;
}
static inline dw_loc_list_ref
AT_loc_list (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
return a->dw_attr_val.v.val_loc_list;
}
static inline void
add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_addr;
attr.dw_attr_val.v.val_addr = addr;
add_dwarf_attr (die, &attr);
}
static inline rtx
AT_addr (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_addr);
return a->dw_attr_val.v.val_addr;
}
static inline void
add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
struct dwarf_file_data *fd)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_file;
attr.dw_attr_val.v.val_file = fd;
add_dwarf_attr (die, &attr);
}
static inline struct dwarf_file_data *
AT_file (dw_attr_ref a)
{
gcc_assert (a && AT_class (a) == dw_val_class_file);
return a->dw_attr_val.v.val_file;
}
static inline void
add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_lbl_id;
attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
add_dwarf_attr (die, &attr);
}
static inline void
add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
const char *label)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_lineptr;
attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
add_dwarf_attr (die, &attr);
}
static inline void
add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
const char *label)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_macptr;
attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
add_dwarf_attr (die, &attr);
}
static inline void
add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned HOST_WIDE_INT offset)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_offset;
attr.dw_attr_val.v.val_offset = offset;
add_dwarf_attr (die, &attr);
}
static void
add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
long unsigned int offset)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_range_list;
attr.dw_attr_val.v.val_offset = offset;
add_dwarf_attr (die, &attr);
}
static inline const char *
AT_lbl (dw_attr_ref a)
{
gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
|| AT_class (a) == dw_val_class_lineptr
|| AT_class (a) == dw_val_class_macptr));
return a->dw_attr_val.v.val_lbl_id;
}
static dw_attr_ref
has_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
unsigned ix;
if (! die)
return NULL;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (a->dw_attr == attr_kind)
return a;
return NULL;
}
static dw_attr_ref
get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
unsigned ix;
dw_die_ref spec = NULL;
if (! die)
return NULL;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (a->dw_attr == attr_kind)
return a;
else if (a->dw_attr == DW_AT_specification
|| a->dw_attr == DW_AT_abstract_origin)
spec = AT_ref (a);
if (spec)
return get_AT (spec, attr_kind);
return NULL;
}
static inline const char *
get_AT_low_pc (dw_die_ref die)
{
dw_attr_ref a = get_AT (die, DW_AT_low_pc);
return a ? AT_lbl (a) : NULL;
}
static inline const char *
get_AT_hi_pc (dw_die_ref die)
{
dw_attr_ref a = get_AT (die, DW_AT_high_pc);
return a ? AT_lbl (a) : NULL;
}
static inline const char *
get_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
return a ? AT_string (a) : NULL;
}
static inline int
get_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
return a ? AT_flag (a) : 0;
}
static inline unsigned
get_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
return a ? AT_unsigned (a) : 0;
}
static inline dw_die_ref
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 struct dwarf_file_data *
get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a = get_AT (die, attr_kind);
return a ? AT_file (a) : NULL;
}
static inline bool
is_c_family (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_C || lang == DW_LANG_C89 || lang == DW_LANG_ObjC
|| lang == DW_LANG_C99
|| lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus);
}
static inline bool
is_cxx (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
}
static inline bool
is_objc (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return lang == DW_LANG_ObjC;
}
static inline bool
is_objcxx (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return lang == DW_LANG_ObjC_plus_plus;
}
static inline bool
is_fortran (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_Fortran77
|| lang == DW_LANG_Fortran90
|| lang == DW_LANG_Fortran95);
}
static inline bool
is_java (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return lang == DW_LANG_Java;
}
static inline bool
is_ada (void)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
}
static void
remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
unsigned ix;
if (! die)
return;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (a->dw_attr == attr_kind)
{
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--;
VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
return;
}
}
static void
remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
{
gcc_assert (child->die_parent == prev->die_parent);
gcc_assert (prev->die_sib == child);
if (prev == child)
{
gcc_assert (child->die_parent->die_child == child);
prev = NULL;
}
else
prev->die_sib = child->die_sib;
if (child->die_parent->die_child == child)
child->die_parent->die_child = prev;
}
static void
remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
{
dw_die_ref c;
c = die->die_child;
if (c) do {
dw_die_ref prev = c;
c = c->die_sib;
while (c->die_tag == tag)
{
remove_child_with_prev (c, prev);
if (c == c->die_sib)
return;
c = c->die_sib;
}
} while (c != die->die_child);
}
static void
add_child_die (dw_die_ref die, dw_die_ref child_die)
{
if (! die || ! child_die)
return;
gcc_assert (die != child_die);
child_die->die_parent = die;
if (die->die_child)
{
child_die->die_sib = die->die_child->die_sib;
die->die_child->die_sib = child_die;
}
else
child_die->die_sib = child_die;
die->die_child = child_die;
}
static void
splice_child_die (dw_die_ref parent, dw_die_ref child)
{
dw_die_ref p;
if (child->die_parent != parent)
{
dw_die_ref tmp = get_AT_ref (child, DW_AT_specification);
if (tmp)
child = tmp;
}
gcc_assert (child->die_parent == parent
|| (child->die_parent
== get_AT_ref (parent, DW_AT_specification)));
for (p = child->die_parent->die_child; ; p = p->die_sib)
if (p->die_sib == child)
{
remove_child_with_prev (child, p);
break;
}
add_child_die (parent, child);
}
static inline dw_die_ref
new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
{
dw_die_ref die = ggc_alloc_cleared (sizeof (die_node));
die->die_tag = tag_value;
if (parent_die != NULL)
add_child_die (parent_die, die);
else
{
limbo_die_node *limbo_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;
limbo_die_list = limbo_node;
}
return die;
}
static inline dw_die_ref
lookup_type_die (tree type)
{
return TYPE_SYMTAB_DIE (type);
}
static inline void
equate_type_number_to_die (tree type, dw_die_ref type_die)
{
TYPE_SYMTAB_DIE (type) = type_die;
}
static hashval_t
decl_die_table_hash (const void *x)
{
return (hashval_t) ((const dw_die_ref) x)->decl_id;
}
static int
decl_die_table_eq (const void *x, const void *y)
{
return (((const dw_die_ref) x)->decl_id == DECL_UID ((const tree) y));
}
static inline dw_die_ref
lookup_decl_die (tree decl)
{
return htab_find_with_hash (decl_die_table, decl, DECL_UID (decl));
}
static hashval_t
decl_loc_table_hash (const void *x)
{
return (hashval_t) ((const var_loc_list *) x)->decl_id;
}
static int
decl_loc_table_eq (const void *x, const void *y)
{
return (((const var_loc_list *) x)->decl_id == DECL_UID ((const tree) y));
}
static inline var_loc_list *
lookup_decl_loc (tree decl)
{
return htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
}
static void
equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
{
unsigned int decl_id = DECL_UID (decl);
void **slot;
slot = htab_find_slot_with_hash (decl_die_table, decl, decl_id, INSERT);
*slot = decl_die;
decl_die->decl_id = decl_id;
}
static void
add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
{
unsigned int decl_id = DECL_UID (decl);
var_loc_list *temp;
void **slot;
slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
if (*slot == NULL)
{
temp = ggc_alloc_cleared (sizeof (var_loc_list));
temp->decl_id = decl_id;
*slot = temp;
}
else
temp = *slot;
if (temp->last)
{
if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
|| ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
!= NOTE_VAR_LOCATION_STATUS (loc->var_loc_note))
&& ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
== STATUS_UNINITIALIZED)
|| (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)
== STATUS_UNINITIALIZED))))
{
temp->last->next = loc;
temp->last = loc;
}
}
else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
{
temp->first = loc;
temp->last = loc;
}
}
static int print_indent;
static inline void
print_spaces (FILE *outfile)
{
fprintf (outfile, "%*s", print_indent, "");
}
static void
print_die (dw_die_ref die, FILE *outfile)
{
dw_attr_ref a;
dw_die_ref c;
unsigned ix;
print_spaces (outfile);
fprintf (outfile, "DIE %4lu: %s\n",
die->die_offset, dwarf_tag_name (die->die_tag));
print_spaces (outfile);
fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
fprintf (outfile, " offset: %lu\n", die->die_offset);
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
print_spaces (outfile);
fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
switch (AT_class (a))
{
case dw_val_class_addr:
fprintf (outfile, "address");
break;
case dw_val_class_offset:
fprintf (outfile, "offset");
break;
case dw_val_class_loc:
fprintf (outfile, "location descriptor");
break;
case dw_val_class_loc_list:
fprintf (outfile, "location list -> label:%s",
AT_loc_list (a)->ll_symbol);
break;
case dw_val_class_range_list:
fprintf (outfile, "range list");
break;
case dw_val_class_const:
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
break;
case dw_val_class_unsigned_const:
fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
break;
case dw_val_class_long_long:
fprintf (outfile, "constant (%lu,%lu)",
a->dw_attr_val.v.val_long_long.hi,
a->dw_attr_val.v.val_long_long.low);
break;
case dw_val_class_vec:
fprintf (outfile, "floating-point or vector constant");
break;
case dw_val_class_flag:
fprintf (outfile, "%u", AT_flag (a));
break;
case dw_val_class_die_ref:
if (AT_ref (a) != NULL)
{
if (AT_ref (a)->die_symbol)
fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol);
else
fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset);
}
else
fprintf (outfile, "die -> <null>");
break;
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
fprintf (outfile, "label: %s", AT_lbl (a));
break;
case dw_val_class_str:
if (AT_string (a) != NULL)
fprintf (outfile, "\"%s\"", AT_string (a));
else
fprintf (outfile, "<null>");
break;
case dw_val_class_file:
fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
AT_file (a)->emitted_number);
break;
default:
break;
}
fprintf (outfile, "\n");
}
if (die->die_child != NULL)
{
print_indent += 4;
FOR_EACH_CHILD (die, c, print_die (c, outfile));
print_indent -= 4;
}
if (print_indent == 0)
fprintf (outfile, "\n");
}
static void
print_dwarf_line_table (FILE *outfile)
{
unsigned i;
dw_line_info_ref line_info;
fprintf (outfile, "\n\nDWARF source line information\n");
for (i = 1; i < line_info_table_in_use; i++)
{
line_info = &line_info_table[i];
fprintf (outfile, "%5d: %4ld %6ld\n", i,
line_info->dw_file_num,
line_info->dw_line_num);
}
fprintf (outfile, "\n\n");
}
void
debug_dwarf_die (dw_die_ref die)
{
print_die (die, stderr);
}
void
debug_dwarf (void)
{
print_indent = 0;
print_die (comp_unit_die, stderr);
if (! DWARF2_ASM_LINE_DEBUG_INFO)
print_dwarf_line_table (stderr);
}
static dw_die_ref
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);
new_unit->die_sib = old_unit;
return new_unit;
}
static dw_die_ref
pop_compile_unit (dw_die_ref old_unit)
{
dw_die_ref new_unit = old_unit->die_sib;
old_unit->die_sib = NULL;
return new_unit;
}
#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx)
static inline void
loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
{
CHECKSUM (loc->dw_loc_opc);
CHECKSUM (loc->dw_loc_oprnd1);
CHECKSUM (loc->dw_loc_oprnd2);
}
static void
attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
{
dw_loc_descr_ref loc;
rtx r;
CHECKSUM (at->dw_attr);
if (at->dw_attr == DW_AT_producer)
return;
switch (AT_class (at))
{
case dw_val_class_const:
CHECKSUM (at->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
CHECKSUM (at->dw_attr_val.v.val_unsigned);
break;
case dw_val_class_long_long:
CHECKSUM (at->dw_attr_val.v.val_long_long);
break;
case dw_val_class_vec:
CHECKSUM (at->dw_attr_val.v.val_vec);
break;
case dw_val_class_flag:
CHECKSUM (at->dw_attr_val.v.val_flag);
break;
case dw_val_class_str:
CHECKSUM_STRING (AT_string (at));
break;
case dw_val_class_addr:
r = AT_addr (at);
gcc_assert (GET_CODE (r) == SYMBOL_REF);
CHECKSUM_STRING (XSTR (r, 0));
break;
case dw_val_class_offset:
CHECKSUM (at->dw_attr_val.v.val_offset);
break;
case dw_val_class_loc:
for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
loc_checksum (loc, ctx);
break;
case dw_val_class_die_ref:
die_checksum (AT_ref (at), ctx, mark);
break;
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
break;
case dw_val_class_file:
CHECKSUM_STRING (AT_file (at)->filename);
break;
default:
break;
}
}
static void
die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
{
dw_die_ref c;
dw_attr_ref a;
unsigned ix;
if (die->die_mark)
{
CHECKSUM (die->die_mark);
return;
}
die->die_mark = ++(*mark);
CHECKSUM (die->die_tag);
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
attr_checksum (a, ctx, mark);
FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
}
#undef CHECKSUM
#undef CHECKSUM_STRING
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);
}
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;
if (v1->val_class != v2->val_class)
return 0;
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_vec:
if (v1->v.val_vec.length != v2->v.val_vec.length
|| v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
return 0;
if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
v1->v.val_vec.length * v1->v.val_vec.elt_size))
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);
case dw_val_class_addr:
r1 = v1->v.val_addr;
r2 = v2->v.val_addr;
if (GET_CODE (r1) != GET_CODE (r2))
return 0;
gcc_assert (GET_CODE (r1) == SYMBOL_REF);
return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
case dw_val_class_offset:
return v1->v.val_offset == v2->v.val_offset;
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;
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_lineptr:
case dw_val_class_macptr:
return 1;
case dw_val_class_file:
return v1->v.val_file == v2->v.val_file;
default:
return 1;
}
}
static int
same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
{
if (at1->dw_attr != at2->dw_attr)
return 0;
if (at1->dw_attr == DW_AT_producer)
return 1;
return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
}
static int
same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
{
dw_die_ref c1, c2;
dw_attr_ref a1;
unsigned ix;
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;
if (VEC_length (dw_attr_node, die1->die_attr)
!= VEC_length (dw_attr_node, die2->die_attr))
return 0;
for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
return 0;
c1 = die1->die_child;
c2 = die2->die_child;
if (! c1)
{
if (c2)
return 0;
}
else
for (;;)
{
if (!same_die_p (c1, c2, mark))
return 0;
c1 = c1->die_sib;
c2 = c2->die_sib;
if (c1 == die1->die_child)
{
if (c2 == die2->die_child)
break;
else
return 0;
}
}
return 1;
}
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;
}
static char *comdat_symbol_id;
static unsigned int comdat_symbol_number;
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;
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;
}
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_string_type:
case DW_TAG_structure_type:
case DW_TAG_subroutine_type:
case DW_TAG_union_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_set_type:
case DW_TAG_subrange_type:
case DW_TAG_base_type:
case DW_TAG_const_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;
}
}
static int
is_comdat_die (dw_die_ref c)
{
if (c->die_tag == DW_TAG_base_type)
return 0;
if (c->die_tag == DW_TAG_pointer_type
|| c->die_tag == DW_TAG_reference_type
|| c->die_tag == DW_TAG_const_type
|| c->die_tag == DW_TAG_volatile_type)
{
dw_die_ref t = get_AT_ref (c, DW_AT_type);
return t ? is_comdat_die (t) : 0;
}
return is_type_die (c);
}
static int
is_symbol_die (dw_die_ref c)
{
return (is_type_die (c)
|| (get_AT (c, DW_AT_declaration)
&& !get_AT (c, DW_AT_specification))
|| c->die_tag == DW_TAG_namespace);
}
static char *
gen_internal_sym (const char *prefix)
{
char buf[256];
ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
return xstrdup (buf);
}
static void
assign_symbol_names (dw_die_ref die)
{
dw_die_ref c;
if (is_symbol_die (die))
{
if (comdat_symbol_id)
{
char *p = alloca (strlen (comdat_symbol_id) + 64);
sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
comdat_symbol_id, comdat_symbol_number++);
die->die_symbol = xstrdup (p);
}
else
die->die_symbol = gen_internal_sym ("LDIE");
}
FOR_EACH_CHILD (die, 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;
};
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;
}
}
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 = XCNEW (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;
}
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;
}
static void
break_out_includes (dw_die_ref die)
{
dw_die_ref c;
dw_die_ref unit = NULL;
limbo_die_node *node, **pnode;
htab_t cu_hash_table;
c = die->die_child;
if (c) do {
dw_die_ref prev = c;
c = c->die_sib;
while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
|| (unit && is_comdat_die (c)))
{
dw_die_ref next = c->die_sib;
remove_child_with_prev (c, prev);
if (c->die_tag == DW_TAG_GNU_BINCL)
unit = push_new_compile_unit (unit, c);
else if (c->die_tag == DW_TAG_GNU_EINCL)
unit = pop_compile_unit (unit);
else
add_child_die (unit, c);
c = next;
if (c == die->die_child)
break;
}
} while (c != die->die_child);
#if 0
gcc_assert (!unit);
#endif
assign_symbol_names (die);
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);
}
static bool
contained_in_subroutine (dw_die_ref die)
{
dw_die_ref ancestor_die;
bool ret_val = false;
ancestor_die = die->die_parent;
while (ancestor_die
&& ancestor_die->die_tag != DW_TAG_compile_unit
&& ancestor_die->die_tag != DW_TAG_subprogram)
ancestor_die = ancestor_die->die_parent;
if (ancestor_die && ancestor_die->die_tag == DW_TAG_subprogram)
ret_val = true;
return ret_val;
}
static void
add_sibling_attributes (dw_die_ref die)
{
dw_die_ref c;
if (get_AT (die, DW_AT_MIPS_linkage_name)
&& contained_in_subroutine (die))
remove_AT (die, DW_AT_MIPS_linkage_name);
if (! die->die_child)
return;
if (die->die_parent && die != die->die_parent->die_child)
add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
}
static void
output_location_lists (dw_die_ref die)
{
dw_die_ref c;
dw_attr_ref a;
unsigned ix;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (AT_class (a) == dw_val_class_loc_list)
output_loc_list (AT_loc_list (a));
FOR_EACH_CHILD (die, c, output_location_lists (c));
}
static void
build_abbrev_table (dw_die_ref die)
{
unsigned long abbrev_id;
unsigned int n_alloc;
dw_die_ref c;
dw_attr_ref a;
unsigned ix;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (AT_class (a) == dw_val_class_die_ref
&& AT_ref (a)->die_mark == 0)
{
gcc_assert (AT_ref (a)->die_symbol);
set_AT_ref_external (a, 1);
}
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
dw_attr_ref die_a, abbrev_a;
unsigned ix;
bool ok = true;
if (abbrev->die_tag != die->die_tag)
continue;
if ((abbrev->die_child != NULL) != (die->die_child != NULL))
continue;
if (VEC_length (dw_attr_node, abbrev->die_attr)
!= VEC_length (dw_attr_node, die->die_attr))
continue;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
{
abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
if ((abbrev_a->dw_attr != die_a->dw_attr)
|| (value_format (abbrev_a) != value_format (die_a)))
{
ok = false;
break;
}
}
if (ok)
break;
}
if (abbrev_id >= abbrev_die_table_in_use)
{
if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
{
n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
abbrev_die_table = ggc_realloc (abbrev_die_table,
sizeof (dw_die_ref) * n_alloc);
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;
}
++abbrev_die_table_in_use;
abbrev_die_table[abbrev_id] = die;
}
die->die_abbrev = abbrev_id;
FOR_EACH_CHILD (die, c, build_abbrev_table (c));
}
static int
constant_size (long unsigned int value)
{
int log;
if (value == 0)
log = 0;
else
log = floor_log2 (value);
log = log / 8;
log = 1 << (floor_log2 (log) + 1);
return log;
}
static unsigned long
size_of_die (dw_die_ref die)
{
unsigned long size = 0;
dw_attr_ref a;
unsigned ix;
size += size_of_uleb128 (die->die_abbrev);
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
switch (AT_class (a))
{
case dw_val_class_addr:
size += DWARF2_ADDR_SIZE;
break;
case dw_val_class_offset:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_loc:
{
unsigned long lsize = size_of_locs (AT_loc (a));
size += constant_size (lsize);
size += lsize;
}
break;
case dw_val_class_loc_list:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_range_list:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_const:
size += size_of_sleb128 (AT_int (a));
break;
case dw_val_class_unsigned_const:
size += constant_size (AT_unsigned (a));
break;
case dw_val_class_long_long:
size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR;
break;
case dw_val_class_vec:
size += 1 + (a->dw_attr_val.v.val_vec.length
* a->dw_attr_val.v.val_vec.elt_size);
break;
case dw_val_class_flag:
size += 1;
break;
case dw_val_class_die_ref:
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;
break;
case dw_val_class_lbl_id:
size += DWARF2_ADDR_SIZE;
break;
case dw_val_class_lineptr:
case dw_val_class_macptr:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
if (AT_string_form (a) == DW_FORM_strp)
size += DWARF_OFFSET_SIZE;
else
size += strlen (a->dw_attr_val.v.val_str->str) + 1;
break;
case dw_val_class_file:
size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
break;
default:
gcc_unreachable ();
}
}
return size;
}
static void
calc_die_sizes (dw_die_ref die)
{
dw_die_ref c;
die->die_offset = next_die_offset;
next_die_offset += size_of_die (die);
FOR_EACH_CHILD (die, c, calc_die_sizes (c));
if (die->die_child != NULL)
next_die_offset += 1;
}
static void
mark_dies (dw_die_ref die)
{
dw_die_ref c;
gcc_assert (!die->die_mark);
die->die_mark = 1;
FOR_EACH_CHILD (die, c, mark_dies (c));
}
static void
unmark_dies (dw_die_ref die)
{
dw_die_ref c;
gcc_assert (die->die_mark);
die->die_mark = 0;
FOR_EACH_CHILD (die, c, unmark_dies (c));
}
static void
unmark_all_dies (dw_die_ref die)
{
dw_die_ref c;
dw_attr_ref a;
unsigned ix;
if (!die->die_mark)
return;
die->die_mark = 0;
FOR_EACH_CHILD (die, c, unmark_all_dies (c));
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (AT_class (a) == dw_val_class_die_ref)
unmark_all_dies (AT_ref (a));
}
static unsigned long
size_of_inlined (VEC (inlined_entry, gc) * inlined_dies)
{
unsigned long size;
unsigned i;
unsigned j;
dw_die_ref *diep;
unsigned num_entries;
inlined_ref iptr;
size = DWARF_INLINED_HEADER_SIZE;
for (i = 0; VEC_iterate (inlined_entry, inlined_dies, i, iptr); i++)
{
num_entries = 0;
for (j = 0; VEC_iterate (dw_die_ref, iptr->inlined_instances, j, diep);
j++)
if (! (*diep)->dead)
num_entries++;
size += (2 * DWARF_OFFSET_SIZE) + (num_entries * DWARF2_ADDR_SIZE)
+ (num_entries * DWARF_OFFSET_SIZE) + size_of_uleb128 (num_entries);
}
return size;
}
static unsigned long
size_of_pubnames (VEC (pubname_entry, gc) * names)
{
unsigned long size;
unsigned i;
pubname_ref p;
size = DWARF_PUBNAMES_HEADER_SIZE;
for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
if (names != pubtype_table
|| p->die->die_offset != 0
|| !flag_eliminate_unused_debug_types)
size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
size += DWARF_OFFSET_SIZE;
return size;
}
static unsigned long
size_of_aranges (void)
{
unsigned long size;
size = DWARF_ARANGES_HEADER_SIZE;
size += 2 * DWARF2_ADDR_SIZE;
size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use;
size += 2 * DWARF2_ADDR_SIZE;
return size;
}
static enum dwarf_form
value_format (dw_attr_ref a)
{
switch (a->dw_attr_val.val_class)
{
case dw_val_class_addr:
return DW_FORM_addr;
case dw_val_class_range_list:
case dw_val_class_offset:
case dw_val_class_loc_list:
switch (DWARF_OFFSET_SIZE)
{
case 4:
return DW_FORM_data4;
case 8:
return DW_FORM_data8;
default:
gcc_unreachable ();
}
case dw_val_class_loc:
switch (constant_size (size_of_locs (AT_loc (a))))
{
case 1:
return DW_FORM_block1;
case 2:
return DW_FORM_block2;
default:
gcc_unreachable ();
}
case dw_val_class_const:
return DW_FORM_sdata;
case dw_val_class_unsigned_const:
switch (constant_size (AT_unsigned (a)))
{
case 1:
return DW_FORM_data1;
case 2:
return DW_FORM_data2;
case 4:
return DW_FORM_data4;
case 8:
return DW_FORM_data8;
default:
gcc_unreachable ();
}
case dw_val_class_long_long:
return DW_FORM_block1;
case dw_val_class_vec:
return DW_FORM_block1;
case dw_val_class_flag:
return DW_FORM_flag;
case dw_val_class_die_ref:
if (AT_ref_external (a))
return DW_FORM_ref_addr;
else
return DW_FORM_ref;
case dw_val_class_fde_ref:
return DW_FORM_data;
case dw_val_class_lbl_id:
return DW_FORM_addr;
case dw_val_class_lineptr:
case dw_val_class_macptr:
return DW_FORM_data;
case dw_val_class_str:
return AT_string_form (a);
case dw_val_class_file:
switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
{
case 1:
return DW_FORM_data1;
case 2:
return DW_FORM_data2;
case 4:
return DW_FORM_data4;
default:
gcc_unreachable ();
}
default:
gcc_unreachable ();
}
}
static void
output_value_format (dw_attr_ref a)
{
enum dwarf_form form = value_format (a);
dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
}
static void
output_abbrev_section (void)
{
unsigned long abbrev_id;
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
unsigned ix;
dw_attr_ref a_attr;
dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
dwarf_tag_name (abbrev->die_tag));
if (abbrev->die_child != NULL)
dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
else
dw2_asm_output_data (1, DW_children_no, "DW_children_no");
for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
ix++)
{
dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
dwarf_attr_name (a_attr->dw_attr));
output_value_format (a_attr);
}
dw2_asm_output_data (1, 0, NULL);
dw2_asm_output_data (1, 0, NULL);
}
dw2_asm_output_data (1, 0, NULL);
}
static inline void
output_die_symbol (dw_die_ref die)
{
char *sym = die->die_symbol;
if (sym == 0)
return;
if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
targetm.asm_out.globalize_label (asm_out_file, sym);
ASM_OUTPUT_LABEL (asm_out_file, sym);
}
static inline dw_loc_list_ref
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 = ggc_alloc_cleared (sizeof (dw_loc_list_node));
retlist->begin = begin;
retlist->end = end;
retlist->expr = expr;
retlist->section = section;
if (gensym)
retlist->ll_symbol = gen_internal_sym ("LLST");
return retlist;
}
static inline void
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)
;
*d = new_loc_list (descr, begin, end, section, 0);
}
static void
dwarf2out_switch_text_section (void)
{
dw_fde_ref fde;
gcc_assert (cfun);
fde = &fde_table[fde_table_in_use - 1];
fde->dw_fde_switched_sections = true;
fde->dw_fde_hot_section_label = cfun->hot_section_label;
fde->dw_fde_hot_section_end_label = cfun->hot_section_end_label;
fde->dw_fde_unlikely_section_label = cfun->cold_section_label;
fde->dw_fde_unlikely_section_end_label = cfun->cold_section_end_label;
have_multiple_function_sections = true;
fde->dw_fde_current_label = NULL;
}
static void
output_loc_list (dw_loc_list_ref list_head)
{
dw_loc_list_ref curr = list_head;
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
{
unsigned long size;
if (strcmp (curr->begin, curr->end) == 0)
continue;
if (!have_multiple_function_sections)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
"Location list begin address (%s)",
list_head->ll_symbol);
dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
"Location list end address (%s)",
list_head->ll_symbol);
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
"Location list begin address (%s)",
list_head->ll_symbol);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
"Location list end address (%s)",
list_head->ll_symbol);
}
size = size_of_locs (curr->expr);
gcc_assert (size <= 0xffff);
dw2_asm_output_data (2, size, "%s", "Location expression size");
output_loc_sequence (curr->expr);
}
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
"Location list terminator begin (%s)",
list_head->ll_symbol);
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
"Location list terminator end (%s)",
list_head->ll_symbol);
}
static void
output_die (dw_die_ref die)
{
dw_attr_ref a;
dw_die_ref c;
unsigned long size;
unsigned ix;
if (die->die_symbol)
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
die->die_offset, dwarf_tag_name (die->die_tag));
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
const char *name = dwarf_attr_name (a->dw_attr);
switch (AT_class (a))
{
case dw_val_class_addr:
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
break;
case dw_val_class_offset:
dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
"%s", name);
break;
case dw_val_class_range_list:
{
char *p = strchr (ranges_section_label, '\0');
sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
a->dw_attr_val.v.val_offset);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
debug_ranges_section, "%s", name);
*p = '\0';
}
break;
case dw_val_class_loc:
size = size_of_locs (AT_loc (a));
dw2_asm_output_data (constant_size (size), size, "%s", name);
output_loc_sequence (AT_loc (a));
break;
case dw_val_class_const:
dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
break;
case dw_val_class_unsigned_const:
dw2_asm_output_data (constant_size (AT_unsigned (a)),
AT_unsigned (a), "%s", name);
break;
case dw_val_class_long_long:
{
unsigned HOST_WIDE_INT first, second;
dw2_asm_output_data (1,
2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
"%s", name);
if (WORDS_BIG_ENDIAN)
{
first = a->dw_attr_val.v.val_long_long.hi;
second = a->dw_attr_val.v.val_long_long.low;
}
else
{
first = a->dw_attr_val.v.val_long_long.low;
second = a->dw_attr_val.v.val_long_long.hi;
}
dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
first, "long long constant");
dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
second, NULL);
}
break;
case dw_val_class_vec:
{
unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
unsigned int len = a->dw_attr_val.v.val_vec.length;
unsigned int i;
unsigned char *p;
dw2_asm_output_data (1, len * elt_size, "%s", name);
if (elt_size > sizeof (HOST_WIDE_INT))
{
elt_size /= 2;
len *= 2;
}
for (i = 0, p = a->dw_attr_val.v.val_vec.array;
i < len;
i++, p += elt_size)
dw2_asm_output_data (elt_size, extract_int (p, elt_size),
"fp or vector constant word %u", i);
break;
}
case dw_val_class_flag:
dw2_asm_output_data (1, AT_flag (a), "%s", name);
break;
case dw_val_class_loc_list:
{
char *sym = AT_loc_list (a)->ll_symbol;
gcc_assert (sym);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
"%s", name);
}
break;
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
char *sym = AT_ref (a)->die_symbol;
gcc_assert (sym);
dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, debug_info_section,
"%s", name);
}
else
{
gcc_assert (AT_ref (a)->die_offset);
dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
"%s", name);
}
break;
case dw_val_class_fde_ref:
{
char l1[20];
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
a->dw_attr_val.v.val_fde_index * 2);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
"%s", name);
}
break;
case dw_val_class_lbl_id:
dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
break;
case dw_val_class_lineptr:
dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
debug_line_section, "%s", name);
break;
case dw_val_class_macptr:
dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
debug_macinfo_section, "%s", name);
break;
case dw_val_class_str:
if (AT_string_form (a) == DW_FORM_strp)
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
a->dw_attr_val.v.val_str->label,
debug_str_section,
"%s: \"%s\"", name, AT_string (a));
else
dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
break;
case dw_val_class_file:
{
int f = maybe_emit_file (a->dw_attr_val.v.val_file);
dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
a->dw_attr_val.v.val_file->filename);
break;
}
default:
gcc_unreachable ();
}
}
FOR_EACH_CHILD (die, c, output_die (c));
if (die->die_child != NULL)
dw2_asm_output_data (1, 0, "end of children of DIE 0x%lx",
die->die_offset);
}
static void
output_compilation_unit_header (void)
{
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,
debug_abbrev_section,
"Offset Into Abbrev. Section");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
}
static void
output_comp_unit (dw_die_ref die, int output_if_empty)
{
const char *secname;
char *oldsym, *tmp;
if (!output_if_empty && die->die_child == NULL)
return;
mark_dies (die);
build_abbrev_table (die);
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
calc_die_sizes (die);
oldsym = die->die_symbol;
if (oldsym)
{
tmp = alloca (strlen (oldsym) + 24);
sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
secname = tmp;
die->die_symbol = NULL;
switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
}
else
switch_to_section (debug_info_section);
output_compilation_unit_header ();
output_die (die);
if (oldsym)
{
unmark_dies (die);
die->die_symbol = oldsym;
}
}
static const char *
dwarf2_name (tree decl, int scope)
{
return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
}
static void
add_pubname (tree decl, dw_die_ref die)
{
pubname_entry e;
if (! TREE_PUBLIC (decl))
return;
e.die = die;
e.name = xstrdup (dwarf2_name (decl, 1));
VEC_safe_push (pubname_entry, gc, pubname_table, &e);
}
static void
add_pubtype (tree decl, dw_die_ref die)
{
pubname_entry e;
e.name = NULL;
if ((TREE_PUBLIC (decl)
|| die->die_parent == comp_unit_die)
&& (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
{
e.die = die;
if (TYPE_P (decl))
{
if (TYPE_NAME (decl))
{
if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
e.name =
xstrdup ((const char *) IDENTIFIER_POINTER (TYPE_NAME (decl)));
else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (decl)))
e.name =
xstrdup ((const char *) IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl))));
else
e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
}
}
else
e.name = xstrdup (dwarf2_name (decl, 1));
if (e.name && e.name[0] != '\0')
VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
}
}
static void
add_inlined_section_entry (dw_die_ref die)
{
unsigned i;
bool found = false;
inlined_ref iptr;
dw_die_ref current_origin_die = get_AT_ref (die, DW_AT_abstract_origin);
if (!current_origin_die)
return;
if (!has_AT (die, DW_AT_low_pc))
return;
for (i = 0; VEC_iterate (inlined_entry, debug_inlined_table, i, iptr); i++)
{
if (iptr->origin_die == current_origin_die)
{
VEC_safe_push (dw_die_ref, gc, iptr->inlined_instances, &die);
found = true;
}
}
if (!found)
{
inlined_entry *new_entry = (inlined_entry *) xmalloc (sizeof (inlined_entry));
new_entry->origin_die = current_origin_die;
new_entry->inlined_instances = VEC_alloc (dw_die_ref, gc, 32);
VEC_safe_push (dw_die_ref, gc, new_entry->inlined_instances, &die);
VEC_safe_push (inlined_entry, gc, debug_inlined_table, new_entry);
}
}
static void
output_debug_inlined_section (VEC (inlined_entry, gc) * inlined_dies)
{
unsigned i;
unsigned long inlined_length = size_of_inlined (inlined_dies);
inlined_entry *iptr;
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, inlined_length,
"Length of Inlined Subroutines Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
for (i = 0; VEC_iterate (inlined_entry, inlined_dies, i, iptr); i++)
{
dw_attr_ref name_attr;
dw_attr_ref mips_name_attr;
dw_die_ref *diep;
unsigned j;
unsigned num_entries = 0;
dw_die_ref origin_die = iptr->origin_die;
for (j = 0; VEC_iterate (dw_die_ref, iptr->inlined_instances, j, diep);
j++)
if (! (*diep)->dead)
num_entries++;
if (num_entries == 0)
continue;
mips_name_attr = get_AT (origin_die, DW_AT_MIPS_linkage_name);
name_attr = get_AT (origin_die, DW_AT_name);
if (!mips_name_attr)
mips_name_attr = name_attr;
gcc_assert (origin_die != NULL);
gcc_assert (name_attr != NULL);
gcc_assert (mips_name_attr != NULL);
gcc_assert (num_entries > 0);
gcc_assert (AT_string_form (name_attr) == DW_FORM_strp);
gcc_assert (AT_string_form (mips_name_attr) == DW_FORM_strp);
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
mips_name_attr->dw_attr_val.v.val_str->label,
debug_str_section,
"MIPS linkage name: \"%s\"",
AT_string (mips_name_attr));
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
name_attr->dw_attr_val.v.val_str->label,
debug_str_section,
"Function name: \"%s\"", AT_string (name_attr));
dw2_asm_output_data_uleb128 (num_entries, NULL);
for (j = 0; VEC_iterate (dw_die_ref, iptr->inlined_instances, j, diep);
j++)
{
const char *low_pc = get_AT_low_pc (*diep);
gcc_assert (low_pc != NULL);
if (! (*diep)->dead)
{
dw2_asm_output_data (DWARF_OFFSET_SIZE, (*diep)->die_offset,
"inlined subroutine die offset");
dw2_asm_output_addr (DWARF2_ADDR_SIZE, low_pc, "%s",
"Low PC address");
}
}
}
}
static void
output_pubnames (VEC (pubname_entry, gc) * names)
{
unsigned i;
unsigned long pubnames_length = size_of_pubnames (names);
pubname_ref pub;
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
dw2_asm_output_data (4, 0xffffffff,
"Initial length escape value indicating 64-bit DWARF extension");
if (names == pubname_table)
dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
"Length of Public Names Info");
else
dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
"Length of Public Type Names Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
debug_info_section,
"Offset of Compilation Unit Info");
dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
"Compilation Unit Length");
for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
{
if (names == pubname_table)
gcc_assert (pub->die->die_mark);
if (names != pubtype_table
|| pub->die->die_offset != 0
|| !flag_eliminate_unused_debug_types)
{
dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
"DIE offset");
dw2_asm_output_nstring (pub->name, -1, "external name");
}
}
dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
}
static void
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 = 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;
}
static void
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");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
debug_info_section,
"Offset of Compilation Unit Info");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
if (DWARF_ARANGES_PAD_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)
dw2_asm_output_data (2, 0, NULL);
}
dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
text_section_label, "Length");
if (flag_reorder_blocks_and_partition)
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
"Address");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
cold_text_section_label, "Length");
}
for (i = 0; i < arange_table_in_use; i++)
{
dw_die_ref die = arange_table[i];
gcc_assert (die->die_mark);
if (die->die_tag == DW_TAG_subprogram)
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die),
"Address");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die),
get_AT_low_pc (die), "Length");
}
else
{
dw_attr_ref a = get_AT (die, DW_AT_location);
dw_loc_descr_ref loc;
gcc_assert (a && AT_class (a) == dw_val_class_loc);
loc = AT_loc (a);
gcc_assert (loc->dw_loc_opc == DW_OP_addr);
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
loc->dw_loc_oprnd1.v.val_addr, "Address");
dw2_asm_output_data (DWARF2_ADDR_SIZE,
get_AT_unsigned (die, DW_AT_byte_size),
"Length");
}
}
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
}
static unsigned int
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
= 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);
ranges_table_in_use = in_use + 1;
return in_use * 2 * DWARF2_ADDR_SIZE;
}
static void
output_ranges (void)
{
unsigned i;
static const char *const start_fmt = "Offset 0x%x";
const char *fmt = start_fmt;
for (i = 0; i < ranges_table_in_use; i++)
{
int block_num = ranges_table[i].block_num;
if (block_num)
{
char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
if (!have_multiple_function_sections)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
text_section_label,
fmt, i * 2 * DWARF2_ADDR_SIZE);
dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
text_section_label, NULL);
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
fmt, i * 2 * DWARF2_ADDR_SIZE);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
}
fmt = NULL;
}
else
{
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
fmt = start_fmt;
}
}
}
struct file_info
{
const char *path;
const char *fname;
int length;
struct dwarf_file_data * file_idx;
int dir_idx;
};
struct dir_info
{
const char *path;
int length;
int prefix;
int count;
int dir_idx;
};
static int
file_info_cmp (const void *p1, const void *p2)
{
const struct file_info *s1 = p1;
const struct file_info *s2 = p2;
unsigned char *cp1;
unsigned char *cp2;
if ((s1->path == s1->fname || s2->path == s2->fname))
return (s2->path == s2->fname) - (s1->path == s1->fname);
cp1 = (unsigned char *) s1->path;
cp2 = (unsigned char *) s2->path;
while (1)
{
++cp1;
++cp2;
if ((cp1 == (unsigned char *) s1->fname)
|| (cp2 == (unsigned char *) s2->fname))
return ((cp2 == (unsigned char *) s2->fname)
- (cp1 == (unsigned char *) s1->fname));
else if (*cp1 != *cp2)
return *cp1 - *cp2;
}
}
struct file_name_acquire_data
{
struct file_info *files;
int used_files;
int max_files;
};
static int
file_name_acquire (void ** slot, void *data)
{
struct file_name_acquire_data *fnad = data;
struct dwarf_file_data *d = *slot;
struct file_info *fi;
const char *f;
gcc_assert (fnad->max_files >= d->emitted_number);
if (! d->emitted_number)
return 1;
gcc_assert (fnad->max_files != fnad->used_files);
fi = fnad->files + fnad->used_files++;
f = d->filename;
while (f[0] == '.' && f[1] == '/')
f += 2;
fi->path = f;
fi->length = strlen (f);
fi->file_idx = d;
f = strrchr (f, '/');
fi->fname = f == NULL ? fi->path : f + 1;
return 1;
}
static void
output_file_names (void)
{
struct file_name_acquire_data fnad;
int numfiles;
struct file_info *files;
struct dir_info *dirs;
int *saved;
int *savehere;
int *backmap;
int ndirs;
int idx_offset;
int i;
int idx;
if (!last_emitted_file)
{
dw2_asm_output_data (1, 0, "End directory table");
dw2_asm_output_data (1, 0, "End file name table");
return;
}
numfiles = last_emitted_file->emitted_number;
files = alloca (numfiles * sizeof (struct file_info));
dirs = alloca (numfiles * sizeof (struct dir_info));
fnad.files = files;
fnad.used_files = 0;
fnad.max_files = numfiles;
htab_traverse (file_table, file_name_acquire, &fnad);
gcc_assert (fnad.used_files == fnad.max_files);
qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
dirs[0].path = files[0].path;
dirs[0].length = files[0].fname - files[0].path;
dirs[0].prefix = -1;
dirs[0].count = 1;
dirs[0].dir_idx = 0;
files[0].dir_idx = 0;
ndirs = 1;
for (i = 1; i < numfiles; 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)
{
files[i].dir_idx = ndirs - 1;
++dirs[ndirs - 1].count;
}
else
{
int j;
dirs[ndirs].path = files[i].path;
dirs[ndirs].length = files[i].fname - files[i].path;
dirs[ndirs].count = 1;
dirs[ndirs].dir_idx = ndirs;
files[i].dir_idx = ndirs;
dirs[ndirs].prefix = -1;
for (j = 0; j < ndirs; j++)
if (dirs[j].length < dirs[ndirs].length
&& dirs[j].length > 1
&& (dirs[ndirs].prefix == -1
|| dirs[j].length > dirs[dirs[ndirs].prefix].length)
&& memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
dirs[ndirs].prefix = j;
++ndirs;
}
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;
int total;
savehere[i] = dirs[i].length;
total = (savehere[i] - saved[i]) * dirs[i].count;
for (j = i + 1; j < ndirs; j++)
{
savehere[j] = 0;
if (saved[j] < dirs[i].length)
{
int k;
k = dirs[j].prefix;
while (k != -1 && k != (int) i)
k = dirs[k].prefix;
if (k == (int) i)
{
savehere[j] = dirs[i].length;
total += (savehere[j] - saved[j]) * dirs[j].count;
}
}
}
if (total > dirs[i].length + 1)
{
for (j = i; j < ndirs; j++)
if (savehere[j] > 0)
{
saved[j] = savehere[j];
dirs[j].dir_idx = i;
}
}
}
idx = 1;
idx_offset = dirs[0].length > 0 ? 1 : 0;
for (i = 1 - idx_offset; i < ndirs; i++)
dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
"Directory Entry: 0x%x", i + idx_offset);
dw2_asm_output_data (1, 0, "End directory table");
backmap = alloca (numfiles * sizeof (int));
for (i = 0; i < numfiles; i++)
backmap[files[i].file_idx->emitted_number - 1] = i;
for (i = 0; i < numfiles; 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", (unsigned) i + 1);
dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
dw2_asm_output_data_uleb128 (0, NULL);
dw2_asm_output_data_uleb128 (0, NULL);
}
dw2_asm_output_data (1, 0, "End file name table");
}
static void
output_line_info (void)
{
char l1[20], l2[20], p1[20], p2[20];
char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
unsigned opc;
unsigned n_op_args;
unsigned long lt_index;
unsigned long current_line;
long line_offset;
long line_delta;
unsigned long current_file;
unsigned long function;
ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
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);
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
ASM_OUTPUT_LABEL (asm_out_file, p1);
dw2_asm_output_data (1, 1,
"Minimum Instruction Length");
dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
"Default is_stmt_start flag");
dw2_asm_output_data (1, DWARF_LINE_BASE,
"Line Base Value (Special Opcodes)");
dw2_asm_output_data (1, DWARF_LINE_RANGE,
"Line Range Value (Special Opcodes)");
dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
"Special Opcode Base");
for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
{
switch (opc)
{
case DW_LNS_advance_pc:
case DW_LNS_advance_line:
case DW_LNS_set_file:
case DW_LNS_set_column:
case DW_LNS_fixed_advance_pc:
n_op_args = 1;
break;
default:
n_op_args = 0;
break;
}
dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
opc, n_op_args);
}
output_file_names ();
ASM_OUTPUT_LABEL (asm_out_file, p2);
current_file = 1;
current_line = 1;
if (cfun && in_cold_section_p)
strcpy (prev_line_label, cfun->cold_section_label);
else
strcpy (prev_line_label, text_section_label);
for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
{
dw_line_info_ref line_info = &line_info_table[lt_index];
#if 0
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file)
continue;
#endif
ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
if (0)
{
dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
"DW_LNS_fixed_advance_pc");
dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
}
else
{
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);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
}
strcpy (prev_line_label, line_label);
if (line_info->dw_file_num != current_file)
{
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, "%lu", current_file);
}
if (line_info->dw_line_num != current_line)
{
line_offset = line_info->dw_line_num - current_line;
line_delta = line_offset - DWARF_LINE_BASE;
current_line = line_info->dw_line_num;
if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
"line %lu", current_line);
else
{
dw2_asm_output_data (1, DW_LNS_advance_line,
"advance to line %lu", current_line);
dw2_asm_output_data_sleb128 (line_offset, NULL);
dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
}
}
else
dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
}
if (0)
{
dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
"DW_LNS_fixed_advance_pc");
dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
}
else
{
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);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
}
dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
dw2_asm_output_data_uleb128 (1, NULL);
dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
function = 0;
current_file = 1;
current_line = 1;
for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
{
dw_separate_line_info_ref line_info
= &separate_line_info_table[lt_index];
#if 0
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file
&& line_info->function == function)
goto cont;
#endif
ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
lt_index);
if (function != line_info->function)
{
function = line_info->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);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
}
else
{
if (0)
{
dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
"DW_LNS_fixed_advance_pc");
dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
}
else
{
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);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
}
}
strcpy (prev_line_label, line_label);
if (line_info->dw_file_num != current_file)
{
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, "%lu", current_file);
}
if (line_info->dw_line_num != current_line)
{
line_offset = line_info->dw_line_num - current_line;
line_delta = line_offset - DWARF_LINE_BASE;
current_line = line_info->dw_line_num;
if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
"line %lu", current_line);
else
{
dw2_asm_output_data (1, DW_LNS_advance_line,
"advance to line %lu", current_line);
dw2_asm_output_data_sleb128 (line_offset, NULL);
dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
}
}
else
dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
#if 0
cont:
#endif
lt_index++;
if (lt_index == separate_line_info_table_in_use
|| separate_line_info_table[lt_index].function != function)
{
current_file = 1;
current_line = 1;
ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
if (0)
{
dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
"DW_LNS_fixed_advance_pc");
dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
}
else
{
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);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
}
dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
dw2_asm_output_data_uleb128 (1, NULL);
dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
}
}
ASM_OUTPUT_LABEL (asm_out_file, l2);
}
static dw_die_ref
base_type_die (tree type)
{
dw_die_ref base_type_result;
enum dwarf_type encoding;
if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
return 0;
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
if (TYPE_STRING_FLAG (type))
{
if (TYPE_UNSIGNED (type))
encoding = DW_ATE_unsigned_char;
else
encoding = DW_ATE_signed_char;
}
else if (TYPE_UNSIGNED (type))
encoding = DW_ATE_unsigned;
else
encoding = DW_ATE_signed;
break;
case REAL_TYPE:
if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
encoding = DW_ATE_decimal_float;
else
encoding = DW_ATE_float;
break;
case COMPLEX_TYPE:
if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
encoding = DW_ATE_complex_float;
else
encoding = DW_ATE_lo_user;
break;
case BOOLEAN_TYPE:
encoding = DW_ATE_boolean;
break;
default:
gcc_unreachable ();
}
base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
if (! TYPE_NAME (type))
add_name_attribute (base_type_result, "__unknown__");
add_AT_unsigned (base_type_result, DW_AT_byte_size,
int_size_in_bytes (type));
add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
return base_type_result;
}
static tree
root_type (tree type)
{
if (TREE_CODE (type) == ERROR_MARK)
return error_mark_node;
switch (TREE_CODE (type))
{
case ERROR_MARK:
return error_mark_node;
case BLOCK_POINTER_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
return type_main_variant (root_type (TREE_TYPE (type)));
default:
return type_main_variant (type);
}
}
static inline int
is_base_type (tree type)
{
switch (TREE_CODE (type))
{
case ERROR_MARK:
case VOID_TYPE:
case INTEGER_TYPE:
case REAL_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
return 1;
case ARRAY_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
case ENUMERAL_TYPE:
case FUNCTION_TYPE:
case METHOD_TYPE:
case BLOCK_POINTER_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
case OFFSET_TYPE:
case LANG_TYPE:
case VECTOR_TYPE:
return 0;
default:
gcc_unreachable ();
}
return 0;
}
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);
}
static inline bool
is_subrange_type (tree type)
{
tree subtype = TREE_TYPE (type);
if (TREE_CODE (type) != INTEGER_TYPE
|| subtype == NULL_TREE)
return false;
if (TREE_CODE (subtype) != INTEGER_TYPE
&& TREE_CODE (subtype) != ENUMERAL_TYPE)
return false;
if (TREE_CODE (type) == TREE_CODE (subtype)
&& int_size_in_bytes (type) == int_size_in_bytes (subtype)
&& TYPE_MIN_VALUE (type) != NULL
&& TYPE_MIN_VALUE (subtype) != NULL
&& tree_int_cst_equal (TYPE_MIN_VALUE (type), TYPE_MIN_VALUE (subtype))
&& TYPE_MAX_VALUE (type) != NULL
&& TYPE_MAX_VALUE (subtype) != NULL
&& tree_int_cst_equal (TYPE_MAX_VALUE (type), TYPE_MAX_VALUE (subtype)))
{
tree type_name = TYPE_NAME (type);
tree subtype_name = TYPE_NAME (subtype);
if (type_name != NULL && TREE_CODE (type_name) == TYPE_DECL)
type_name = DECL_NAME (type_name);
if (subtype_name != NULL && TREE_CODE (subtype_name) == TYPE_DECL)
subtype_name = DECL_NAME (subtype_name);
if (type_name == subtype_name)
return false;
}
return true;
}
static dw_die_ref
subrange_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref subrange_die;
const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
if (context_die == NULL)
context_die = comp_unit_die;
subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
{
add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
}
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));
return subrange_die;
}
static dw_die_ref
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;
dw_die_ref sub_die = NULL;
tree item_type = NULL;
tree qualified_type;
tree name;
if (code == ERROR_MARK)
return NULL;
if (is_volatile_type
&& (is_objc () || is_objcxx ())
&& lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (type)))
{
is_volatile_type = 0;
if (TYPE_NAME (type) && TREE_TYPE (TYPE_NAME (type)))
type = TREE_TYPE (TYPE_NAME (type));
}
qualified_type
= get_qualified_type (type,
((is_const_type ? TYPE_QUAL_CONST : 0)
| (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
if (qualified_type)
{
mod_type_die = lookup_type_die (qualified_type);
if (mod_type_die)
return mod_type_die;
}
name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
{
tree dtype = TREE_TYPE (name);
if (qualified_type == dtype)
{
gen_type_die (qualified_type, context_die);
return lookup_type_die (qualified_type);
}
else if (is_const_type < TYPE_READONLY (dtype)
|| is_volatile_type < TYPE_VOLATILE (dtype)
|| (is_const_type <= TYPE_READONLY (dtype)
&& is_volatile_type <= TYPE_VOLATILE (dtype)
&& DECL_ORIGINAL_TYPE (name) != type))
return modified_type_die (DECL_ORIGINAL_TYPE (name),
is_const_type, is_volatile_type,
context_die);
}
if (is_const_type)
{
mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
}
else if (is_volatile_type)
{
mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
sub_die = modified_type_die (type, 0, 0, context_die);
}
else if (code == POINTER_TYPE || code == BLOCK_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,
simple_type_size_in_bits (type) / BITS_PER_UNIT);
item_type = TREE_TYPE (type);
}
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,
simple_type_size_in_bits (type) / BITS_PER_UNIT);
item_type = TREE_TYPE (type);
}
else if (is_subrange_type (type))
{
mod_type_die = subrange_type_die (type, context_die);
item_type = TREE_TYPE (type);
}
else if (is_base_type (type))
mod_type_die = base_type_die (type);
else
{
gen_type_die (type, context_die);
if (TREE_CODE (type) != VECTOR_TYPE)
return lookup_type_die (type_main_variant (type));
else
return lookup_type_die (type);
}
if (name
&& (TREE_CODE (name) != TYPE_DECL || TREE_TYPE (name) == qualified_type))
{
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
}
if (qualified_type)
equate_type_number_to_die (qualified_type, mod_type_die);
if (item_type)
sub_die = modified_type_die (item_type,
TYPE_READONLY (item_type),
TYPE_VOLATILE (item_type),
context_die);
if (sub_die != NULL)
add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
if (mod_type_die
&& mod_type_die->die_tag == DW_TAG_pointer_type
&& get_AT (mod_type_die, DW_AT_name))
add_pubtype (type, mod_type_die);
return mod_type_die;
}
static inline int
type_is_enum (tree type)
{
return TREE_CODE (type) == ENUMERAL_TYPE;
}
static unsigned int
dbx_reg_number (rtx rtl)
{
unsigned regno = REGNO (rtl);
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
{
int leaf_reg = LEAF_REG_REMAP (regno);
if (leaf_reg != -1)
regno = (unsigned) leaf_reg;
}
#endif
return DBX_REGISTER_NUMBER (regno);
}
static void
add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
{
dw_loc_descr_ref loc;
if (*list_head != NULL)
{
for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
;
if (loc->dw_loc_opc != DW_OP_piece)
loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
}
}
static dw_loc_descr_ref
reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
{
rtx regs;
if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
return 0;
regs = targetm.dwarf_register_span (rtl);
#ifdef TARGET_DWARF2_REG_HANDLER
TARGET_DWARF2_REG_HANDLER (rtl);
#endif
if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
return multiple_reg_loc_descriptor (rtl, regs, initialized);
else
return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
}
static dw_loc_descr_ref
one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
{
dw_loc_descr_ref reg_loc_descr;
if (regno <= 31)
reg_loc_descr = new_loc_descr (DW_OP_reg0 + regno, 0, 0);
else
reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
if (initialized == STATUS_UNINITIALIZED)
add_loc_descr (®_loc_descr, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
return reg_loc_descr;
}
static dw_loc_descr_ref
multiple_reg_loc_descriptor (rtx rtl, rtx regs,
enum var_init_status initialized)
{
int nregs, size, i;
unsigned reg;
dw_loc_descr_ref loc_result = NULL;
reg = REGNO (rtl);
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
{
int leaf_reg = LEAF_REG_REMAP (reg);
if (leaf_reg != -1)
reg = (unsigned) leaf_reg;
}
#endif
gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
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 (DBX_REGISTER_NUMBER (reg),
STATUS_INITIALIZED);
add_loc_descr (&loc_result, t);
add_loc_descr_op_piece (&loc_result, size);
++reg;
}
return loc_result;
}
gcc_assert (GET_CODE (regs) == PARALLEL);
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)),
STATUS_INITIALIZED);
add_loc_descr (&loc_result, t);
size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
add_loc_descr_op_piece (&loc_result, size);
}
if (loc_result && initialized == STATUS_UNINITIALIZED)
add_loc_descr (&loc_result, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
return loc_result;
}
static dw_loc_descr_ref
int_loc_descriptor (HOST_WIDE_INT i)
{
enum dwarf_location_atom op;
if (i >= 0)
{
if (i <= 31)
op = DW_OP_lit0 + i;
else if (i <= 0xff)
op = DW_OP_const1u;
else if (i <= 0xffff)
op = DW_OP_const2u;
else if (HOST_BITS_PER_WIDE_INT == 32
|| i <= 0xffffffff)
op = DW_OP_const4u;
else
op = DW_OP_constu;
}
else
{
if (i >= -0x80)
op = DW_OP_const1s;
else if (i >= -0x8000)
op = DW_OP_const2s;
else if (HOST_BITS_PER_WIDE_INT == 32
|| i >= -0x80000000)
op = DW_OP_const4s;
else
op = DW_OP_consts;
}
return new_loc_descr (op, i, 0);
}
static dw_loc_descr_ref
based_loc_descr (rtx reg, HOST_WIDE_INT offset,
enum var_init_status initialized)
{
unsigned int regno;
dw_loc_descr_ref result;
if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
{
rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
if (elim != reg)
{
if (GET_CODE (elim) == PLUS)
{
offset += INTVAL (XEXP (elim, 1));
elim = XEXP (elim, 0);
}
gcc_assert (elim == frame_pointer_fb_offset_from);
offset += frame_pointer_fb_offset;
return new_loc_descr (DW_OP_fbreg, offset, 0);
}
}
regno = dbx_reg_number (reg);
if (regno <= 31)
result = new_loc_descr (DW_OP_breg0 + regno, offset, 0);
else
result = new_loc_descr (DW_OP_bregx, regno, offset);
if (initialized == STATUS_UNINITIALIZED)
add_loc_descr (&result, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
return result;
}
static inline int
is_based_loc (rtx rtl)
{
return (GET_CODE (rtl) == PLUS
&& ((REG_P (XEXP (rtl, 0))
&& REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
&& GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
}
static dw_loc_descr_ref
mem_loc_descriptor (rtx rtl, enum machine_mode mode,
enum var_init_status initialized)
{
dw_loc_descr_ref mem_loc_result = NULL;
enum dwarf_location_atom op;
rtl = targetm.delegitimize_address (rtl);
switch (GET_CODE (rtl))
{
case POST_INC:
case POST_DEC:
case POST_MODIFY:
case SUBREG:
rtl = XEXP (rtl, 0);
case REG:
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
mem_loc_result = based_loc_descr (rtl, 0, STATUS_INITIALIZED);
break;
case MEM:
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
STATUS_INITIALIZED);
if (mem_loc_result != 0)
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
case LO_SUM:
rtl = XEXP (rtl, 1);
case LABEL_REF:
case CONST:
case SYMBOL_REF:
if (GET_CODE (rtl) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (rtl))
{
bool marked;
rtx tmp = get_pool_constant_mark (rtl, &marked);
if (GET_CODE (tmp) == SYMBOL_REF)
{
rtl = tmp;
if (CONSTANT_POOL_ADDRESS_P (tmp))
get_pool_constant_mark (tmp, &marked);
else
marked = true;
}
if (!marked)
return 0;
}
mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
case PRE_MODIFY:
rtl = XEXP (rtl, 1);
goto plus;
case PRE_INC:
case PRE_DEC:
rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
GEN_INT (GET_CODE (rtl) == PRE_INC
? GET_MODE_UNIT_SIZE (mode)
: -GET_MODE_UNIT_SIZE (mode)));
case PLUS:
plus:
if (is_based_loc (rtl))
mem_loc_result = based_loc_descr (XEXP (rtl, 0),
INTVAL (XEXP (rtl, 1)),
STATUS_INITIALIZED);
else
{
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
STATUS_INITIALIZED);
if (mem_loc_result == 0)
break;
if (GET_CODE (XEXP (rtl, 1)) == CONST_INT
&& INTVAL (XEXP (rtl, 1)) >= 0)
add_loc_descr (&mem_loc_result,
new_loc_descr (DW_OP_plus_uconst,
INTVAL (XEXP (rtl, 1)), 0));
else
{
add_loc_descr (&mem_loc_result,
mem_loc_descriptor (XEXP (rtl, 1), mode,
STATUS_INITIALIZED));
add_loc_descr (&mem_loc_result,
new_loc_descr (DW_OP_plus, 0, 0));
}
}
break;
case MULT:
op = DW_OP_mul;
goto do_binop;
case ASHIFT:
op = DW_OP_shl;
goto do_binop;
case ASHIFTRT:
op = DW_OP_shra;
goto do_binop;
case LSHIFTRT:
op = DW_OP_shr;
goto do_binop;
do_binop:
{
dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
STATUS_INITIALIZED);
dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
STATUS_INITIALIZED);
if (op0 == 0 || op1 == 0)
break;
mem_loc_result = op0;
add_loc_descr (&mem_loc_result, op1);
add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
break;
}
case CONST_INT:
mem_loc_result = int_loc_descriptor (INTVAL (rtl));
break;
default:
gcc_unreachable ();
}
if (mem_loc_result && initialized == STATUS_UNINITIALIZED)
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_APPLE_uninit, 0,
0));
return mem_loc_result;
}
static dw_loc_descr_ref
concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
{
dw_loc_descr_ref cc_loc_result = NULL;
dw_loc_descr_ref x0_ref = loc_descriptor (x0, STATUS_INITIALIZED);
dw_loc_descr_ref x1_ref = loc_descriptor (x1, STATUS_INITIALIZED);
if (x0_ref == 0 || x1_ref == 0)
return 0;
cc_loc_result = x0_ref;
add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
add_loc_descr (&cc_loc_result, x1_ref);
add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
if (initialized == STATUS_UNINITIALIZED)
add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
return cc_loc_result;
}
static dw_loc_descr_ref
loc_descriptor (rtx rtl, enum var_init_status initialized)
{
dw_loc_descr_ref loc_result = NULL;
switch (GET_CODE (rtl))
{
case SUBREG:
rtl = SUBREG_REG (rtl);
case REG:
loc_result = reg_loc_descriptor (rtl, initialized);
break;
case MEM:
loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
initialized);
break;
case CONCAT:
loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
initialized);
break;
case VAR_LOCATION:
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
break;
}
rtl = XEXP (rtl, 1);
case PARALLEL:
{
rtvec par_elems = XVEC (rtl, 0);
int num_elem = GET_NUM_ELEM (par_elems);
enum machine_mode mode;
int i;
loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
initialized);
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
for (i = 1; i < num_elem; i++)
{
dw_loc_descr_ref temp;
temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
initialized);
add_loc_descr (&loc_result, temp);
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
}
}
break;
default:
gcc_unreachable ();
}
return loc_result;
}
static dw_loc_descr_ref
loc_descriptor_from_tree_1 (tree loc, int want_address)
{
dw_loc_descr_ref ret, ret1;
int have_address = 0;
enum dwarf_location_atom op;
switch (TREE_CODE (loc))
{
case ERROR_MARK:
return 0;
case PLACEHOLDER_EXPR:
return 0;
case CALL_EXPR:
return 0;
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
return 0;
case ADDR_EXPR:
if (want_address)
return 0;
return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
case VAR_DECL:
if (DECL_THREAD_LOCAL_P (loc))
{
rtx rtl;
if (!targetm.asm_out.output_dwarf_dtprel)
return 0;
if (DECL_EXTERNAL (loc))
return 0;
rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
return 0;
if (!MEM_P (rtl))
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);
have_address = 1;
break;
}
case PARM_DECL:
if (DECL_HAS_VALUE_EXPR_P (loc))
return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc),
want_address);
case RESULT_DECL:
case FUNCTION_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
return 0;
else if (GET_CODE (rtl) == CONST_INT)
{
HOST_WIDE_INT val = INTVAL (rtl);
if (TYPE_UNSIGNED (TREE_TYPE (loc)))
val &= GET_MODE_MASK (DECL_MODE (loc));
ret = int_loc_descriptor (val);
}
else if (GET_CODE (rtl) == CONST_STRING)
return 0;
else if (CONSTANT_P (rtl))
{
ret = new_loc_descr (DW_OP_addr, 0, 0);
ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
ret->dw_loc_oprnd1.v.val_addr = rtl;
}
else
{
enum machine_mode mode;
if (want_address == 2)
return loc_descriptor (rtl, STATUS_INITIALIZED);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
{
rtl = XEXP (rtl, 0);
have_address = 1;
}
ret = mem_loc_descriptor (rtl, mode, STATUS_INITIALIZED);
}
}
break;
case INDIRECT_REF:
ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
have_address = 1;
break;
case COMPOUND_EXPR:
return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address);
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
case MODIFY_EXPR:
return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
case COMPONENT_REF:
case BIT_FIELD_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
enum machine_mode mode;
int volatilep;
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep, false);
if (obj == loc)
return 0;
ret = loc_descriptor_from_tree_1 (obj, 1);
if (ret == 0
|| bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
return 0;
if (offset != NULL_TREE)
{
add_loc_descr (&ret, loc_descriptor_from_tree_1 (offset, 0));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
bytepos = bitpos / BITS_PER_UNIT;
if (bytepos > 0)
add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
else if (bytepos < 0)
{
add_loc_descr (&ret, int_loc_descriptor (bytepos));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
have_address = 1;
break;
}
case INTEGER_CST:
if (host_integerp (loc, 0))
ret = int_loc_descriptor (tree_low_cst (loc, 0));
else
return 0;
break;
case CONSTRUCTOR:
{
rtx rtl = lookup_constant_def (loc);
enum machine_mode mode;
if (!rtl || !MEM_P (rtl))
return 0;
mode = GET_MODE (rtl);
rtl = XEXP (rtl, 0);
ret = mem_loc_descriptor (rtl, mode, STATUS_INITIALIZED);
have_address = 1;
break;
}
case TRUTH_AND_EXPR:
case TRUTH_ANDIF_EXPR:
case BIT_AND_EXPR:
op = DW_OP_and;
goto do_binop;
case TRUTH_XOR_EXPR:
case BIT_XOR_EXPR:
op = DW_OP_xor;
goto do_binop;
case TRUTH_OR_EXPR:
case TRUTH_ORIF_EXPR:
case BIT_IOR_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;
case MINUS_EXPR:
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;
case MULT_EXPR:
op = DW_OP_mul;
goto do_binop;
case LSHIFT_EXPR:
op = DW_OP_shl;
goto do_binop;
case RSHIFT_EXPR:
op = (TYPE_UNSIGNED (TREE_TYPE (loc)) ? DW_OP_shr : DW_OP_shra);
goto do_binop;
case PLUS_EXPR:
if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
&& host_integerp (TREE_OPERAND (loc, 1), 0))
{
ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
add_loc_descr (&ret,
new_loc_descr (DW_OP_plus_uconst,
tree_low_cst (TREE_OPERAND (loc, 1),
0),
0));
break;
}
op = DW_OP_plus;
goto do_binop;
case LE_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_le;
goto do_binop;
case GE_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_ge;
goto do_binop;
case LT_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_lt;
goto do_binop;
case GT_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_gt;
goto do_binop;
case EQ_EXPR:
op = DW_OP_eq;
goto do_binop;
case NE_EXPR:
op = DW_OP_ne;
goto do_binop;
do_binop:
ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
if (ret == 0 || ret1 == 0)
return 0;
add_loc_descr (&ret, ret1);
add_loc_descr (&ret, new_loc_descr (op, 0, 0));
break;
case TRUTH_NOT_EXPR:
case BIT_NOT_EXPR:
op = DW_OP_not;
goto do_unop;
case ABS_EXPR:
op = DW_OP_abs;
goto do_unop;
case NEGATE_EXPR:
op = DW_OP_neg;
goto do_unop;
do_unop:
ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
add_loc_descr (&ret, new_loc_descr (op, 0, 0));
break;
case MIN_EXPR:
case MAX_EXPR:
{
const enum tree_code code =
TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
loc = build3 (COND_EXPR, TREE_TYPE (loc),
build2 (code, integer_type_node,
TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
}
case COND_EXPR:
{
dw_loc_descr_ref lhs
= loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
dw_loc_descr_ref rhs
= loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0);
dw_loc_descr_ref bra_node, jump_node, tmp;
ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0 || lhs == 0 || rhs == 0)
return 0;
bra_node = new_loc_descr (DW_OP_bra, 0, 0);
add_loc_descr (&ret, bra_node);
add_loc_descr (&ret, rhs);
jump_node = new_loc_descr (DW_OP_skip, 0, 0);
add_loc_descr (&ret, jump_node);
add_loc_descr (&ret, lhs);
bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
bra_node->dw_loc_oprnd1.v.val_loc = lhs;
tmp = new_loc_descr (DW_OP_nop, 0, 0);
add_loc_descr (&ret, tmp);
jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
jump_node->dw_loc_oprnd1.v.val_loc = tmp;
}
break;
case FIX_TRUNC_EXPR:
case FIX_CEIL_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
return 0;
default:
if ((unsigned int) TREE_CODE (loc)
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
return 0;
#ifdef ENABLE_CHECKING
gcc_unreachable ();
#else
return NULL;
#endif
}
if (want_address && !have_address)
return 0;
if (!want_address && have_address && ret)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
if (size > DWARF2_ADDR_SIZE || size == -1)
return 0;
else if (size == DWARF2_ADDR_SIZE)
op = DW_OP_deref;
else
op = DW_OP_deref_size;
add_loc_descr (&ret, new_loc_descr (op, size, 0));
}
return ret;
}
static inline dw_loc_descr_ref
loc_descriptor_from_tree (tree loc)
{
return loc_descriptor_from_tree_1 (loc, 2);
}
static inline HOST_WIDE_INT
ceiling (HOST_WIDE_INT value, unsigned int boundary)
{
return (((value + boundary - 1) / boundary) * boundary);
}
static inline tree
field_type (tree decl)
{
tree type;
if (TREE_CODE (decl) == ERROR_MARK)
return integer_type_node;
type = DECL_BIT_FIELD_TYPE (decl);
if (type == NULL_TREE)
type = TREE_TYPE (decl);
return type;
}
static inline unsigned
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 (tree decl)
{
return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
}
static HOST_WIDE_INT
field_byte_offset (tree decl)
{
unsigned int type_align_in_bits;
unsigned int decl_align_in_bits;
unsigned HOST_WIDE_INT type_size_in_bits;
HOST_WIDE_INT object_offset_in_bits;
tree type;
tree field_size_tree;
HOST_WIDE_INT bitpos_int;
HOST_WIDE_INT deepest_bitpos;
unsigned HOST_WIDE_INT field_size_in_bits;
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
gcc_assert (TREE_CODE (decl) == FIELD_DECL);
type = field_type (decl);
field_size_tree = DECL_SIZE (decl);
if (! field_size_tree)
field_size_tree = bitsize_zero_node;
if (! host_integerp (bit_position (decl), 0))
return 0;
bitpos_int = int_bit_position (decl);
if (host_integerp (field_size_tree, 1))
field_size_in_bits = tree_low_cst (field_size_tree, 1);
else
field_size_in_bits = BITS_PER_WORD;
type_size_in_bits = simple_type_size_in_bits (type);
type_align_in_bits = simple_type_align_in_bits (type);
decl_align_in_bits = simple_decl_align_in_bits (decl);
deepest_bitpos = bitpos_int + field_size_in_bits;
object_offset_in_bits = deepest_bitpos - type_size_in_bits;
object_offset_in_bits += type_align_in_bits - 1;
object_offset_in_bits /= type_align_in_bits;
object_offset_in_bits *= type_align_in_bits;
if (object_offset_in_bits > bitpos_int)
{
object_offset_in_bits = deepest_bitpos - type_size_in_bits;
object_offset_in_bits += decl_align_in_bits - 1;
object_offset_in_bits /= decl_align_in_bits;
object_offset_in_bits *= decl_align_in_bits;
}
return object_offset_in_bits / BITS_PER_UNIT;
}
static inline void
add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
dw_loc_descr_ref descr)
{
if (descr != 0)
add_AT_loc (die, attr_kind, descr);
}
static void
add_data_member_location_attribute (dw_die_ref die, tree decl)
{
HOST_WIDE_INT offset;
dw_loc_descr_ref loc_descr = 0;
if (TREE_CODE (decl) == TREE_BINFO)
{
if (BINFO_VIRTUAL_P (decl) && is_cxx ())
{
dw_loc_descr_ref tmp;
tmp = new_loc_descr (DW_OP_dup, 0, 0);
add_loc_descr (&loc_descr, tmp);
tmp = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (&loc_descr, tmp);
offset = tree_low_cst (BINFO_VPTR_FIELD (decl), 0);
gcc_assert (offset < 0);
tmp = int_loc_descriptor (-offset);
add_loc_descr (&loc_descr, tmp);
tmp = new_loc_descr (DW_OP_minus, 0, 0);
add_loc_descr (&loc_descr, tmp);
tmp = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (&loc_descr, tmp);
tmp = new_loc_descr (DW_OP_plus, 0, 0);
add_loc_descr (&loc_descr, tmp);
}
else
offset = tree_low_cst (BINFO_OFFSET (decl), 0);
}
else
offset = field_byte_offset (decl);
if (! loc_descr)
{
enum dwarf_location_atom op;
#ifdef MIPS_DEBUGGING_INFO
op = DW_OP_constu;
#else
op = DW_OP_plus_uconst;
#endif
loc_descr = new_loc_descr (op, offset, 0);
}
add_AT_loc (die, DW_AT_data_member_location, loc_descr);
}
static void
insert_int (HOST_WIDE_INT val, unsigned int size, unsigned char *dest)
{
while (size != 0)
{
*dest++ = val & 0xff;
val >>= 8;
--size;
}
}
static HOST_WIDE_INT
extract_int (const unsigned char *src, unsigned int size)
{
HOST_WIDE_INT val = 0;
src += size;
while (size != 0)
{
val <<= 8;
val |= *--src & 0xff;
--size;
}
return val;
}
static void
insert_float (rtx rtl, unsigned char *array)
{
REAL_VALUE_TYPE rv;
long val[4];
int i;
REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
real_to_target (val, &rv, GET_MODE (rtl));
for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
{
insert_int (val[i], 4, array);
array += 4;
}
}
static void
add_const_value_attribute (dw_die_ref die, rtx rtl)
{
switch (GET_CODE (rtl))
{
case CONST_INT:
{
HOST_WIDE_INT val = INTVAL (rtl);
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:
{
enum machine_mode mode = GET_MODE (rtl);
if (SCALAR_FLOAT_MODE_P (mode))
{
unsigned int length = GET_MODE_SIZE (mode);
unsigned char *array = ggc_alloc (length);
insert_float (rtl, array);
add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
}
else
{
gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
add_AT_long_long (die, DW_AT_const_value,
CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
}
}
break;
case CONST_VECTOR:
{
enum machine_mode mode = GET_MODE (rtl);
unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
unsigned int length = CONST_VECTOR_NUNITS (rtl);
unsigned char *array = ggc_alloc (length * elt_size);
unsigned int i;
unsigned char *p;
switch (GET_MODE_CLASS (mode))
{
case MODE_VECTOR_INT:
for (i = 0, p = array; i < length; i++, p += elt_size)
{
rtx elt = CONST_VECTOR_ELT (rtl, i);
HOST_WIDE_INT lo, hi;
switch (GET_CODE (elt))
{
case CONST_INT:
lo = INTVAL (elt);
hi = -(lo < 0);
break;
case CONST_DOUBLE:
lo = CONST_DOUBLE_LOW (elt);
hi = CONST_DOUBLE_HIGH (elt);
break;
default:
gcc_unreachable ();
}
if (elt_size <= sizeof (HOST_WIDE_INT))
insert_int (lo, elt_size, p);
else
{
unsigned char *p0 = p;
unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
if (WORDS_BIG_ENDIAN)
{
p0 = p1;
p1 = p;
}
insert_int (lo, sizeof (HOST_WIDE_INT), p0);
insert_int (hi, sizeof (HOST_WIDE_INT), p1);
}
}
break;
case MODE_VECTOR_FLOAT:
for (i = 0, p = array; i < length; i++, p += elt_size)
{
rtx elt = CONST_VECTOR_ELT (rtl, i);
insert_float (elt, p);
}
break;
default:
gcc_unreachable ();
}
add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
}
break;
case CONST_STRING:
add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
break;
case SYMBOL_REF:
case LABEL_REF:
case CONST:
add_AT_addr (die, DW_AT_const_value, rtl);
VEC_safe_push (rtx, gc, used_rtx_array, rtl);
break;
case PLUS:
break;
default:
gcc_unreachable ();
}
}
static tree
reference_to_unused (tree * tp, int * walk_subtrees,
void * data ATTRIBUTE_UNUSED)
{
if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
*walk_subtrees = 0;
if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
&& ! TREE_ASM_WRITTEN (*tp))
return *tp;
else if (!flag_unit_at_a_time)
return NULL_TREE;
else if (!cgraph_global_info_ready
&& (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
gcc_unreachable ();
else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
{
struct cgraph_varpool_node *node = cgraph_varpool_node (*tp);
if (!node->needed)
return *tp;
}
else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
&& (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
{
struct cgraph_node *node = cgraph_node (*tp);
if (!node->output)
return *tp;
}
return NULL_TREE;
}
static rtx
rtl_for_decl_init (tree init, tree type)
{
rtx rtl = NULL_RTX;
if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE)
{
tree enttype = TREE_TYPE (type);
tree domain = TYPE_DOMAIN (type);
enum machine_mode mode = TYPE_MODE (enttype);
if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
&& domain
&& integer_zerop (TYPE_MIN_VALUE (domain))
&& compare_tree_int (TYPE_MAX_VALUE (domain),
TREE_STRING_LENGTH (init) - 1) == 0
&& ((size_t) TREE_STRING_LENGTH (init)
== strlen (TREE_STRING_POINTER (init)) + 1))
rtl = gen_rtx_CONST_STRING (VOIDmode,
ggc_strdup (TREE_STRING_POINTER (init)));
}
else if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
;
else if (TREE_CODE (type) == VECTOR_TYPE && TYPE_MODE (type) == BLKmode)
;
else if (initializer_constant_valid_p (init, type)
&& ! walk_tree (&init, reference_to_unused, NULL, NULL))
{
rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
gcc_assert (!rtl || !MEM_P (rtl));
}
return rtl;
}
static rtx
rtl_for_decl_location (tree decl)
{
rtx rtl;
rtl = DECL_RTL_IF_SET (decl);
if (! reload_completed)
{
if (rtl
&& (CONSTANT_P (rtl)
|| (MEM_P (rtl)
&& CONSTANT_P (XEXP (rtl, 0)))
|| (REG_P (rtl)
&& TREE_CODE (decl) == VAR_DECL
&& TREE_STATIC (decl))))
{
rtl = targetm.delegitimize_address (rtl);
return rtl;
}
rtl = NULL_RTX;
}
else if (TREE_CODE (decl) == PARM_DECL)
{
if (rtl == NULL_RTX || is_pseudo_reg (rtl))
{
tree declared_type = TREE_TYPE (decl);
tree passed_type = DECL_ARG_TYPE (decl);
enum machine_mode dmode = TYPE_MODE (declared_type);
enum machine_mode pmode = TYPE_MODE (passed_type);
if (dmode == pmode)
rtl = DECL_INCOMING_RTL (decl);
else if (SCALAR_INT_MODE_P (dmode)
&& GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode)
&& DECL_INCOMING_RTL (decl))
{
rtx inc = DECL_INCOMING_RTL (decl);
if (REG_P (inc))
rtl = inc;
else if (MEM_P (inc))
{
if (BYTES_BIG_ENDIAN)
rtl = adjust_address_nv (inc, dmode,
GET_MODE_SIZE (pmode)
- GET_MODE_SIZE (dmode));
else
rtl = inc;
}
}
}
else if (MEM_P (rtl)
&& XEXP (rtl, 0) != const0_rtx
&& ! CONSTANT_P (XEXP (rtl, 0))
&& !MEM_P (DECL_INCOMING_RTL (decl))
&& (!REG_P (XEXP (rtl, 0))
|| REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM
|| REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|| REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM
#endif
)
&& BYTES_BIG_ENDIAN
&& TYPE_MODE (TREE_TYPE (decl)) != GET_MODE (rtl)
&& (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))
< UNITS_PER_WORD))
{
int offset = (UNITS_PER_WORD
- GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))));
rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
plus_constant (XEXP (rtl, 0), offset));
}
}
else if (TREE_CODE (decl) == VAR_DECL
&& rtl
&& MEM_P (rtl)
&& GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
&& BYTES_BIG_ENDIAN)
{
int rsize = GET_MODE_SIZE (GET_MODE (rtl));
int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
if (rsize > dsize)
rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
plus_constant (XEXP (rtl, 0), rsize-dsize));
}
if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
if (rtl)
rtl = targetm.delegitimize_address (rtl);
if (rtl)
rtl = avoid_constant_pool_reference (rtl);
return rtl;
}
static const char *
secname_for_decl (tree decl)
{
const char *secname;
if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
{
tree sectree = DECL_SECTION_NAME (decl);
secname = TREE_STRING_POINTER (sectree);
}
else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
{
tree sectree = DECL_SECTION_NAME (current_function_decl);
secname = TREE_STRING_POINTER (sectree);
}
else if (cfun && in_cold_section_p)
secname = cfun->cold_section_label;
else
secname = text_section_label;
return secname;
}
static void
add_location_or_const_value_attribute (dw_die_ref die, tree decl,
enum dwarf_attribute attr)
{
rtx rtl;
dw_loc_descr_ref descr;
var_loc_list *loc_list;
struct var_loc_node *node;
if (TREE_CODE (decl) == ERROR_MARK)
return;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
loc_list = lookup_decl_loc (decl);
if (loc_list && loc_list->first != loc_list->last)
{
const char *endname, *secname;
dw_loc_list_ref list;
rtx varloc;
enum var_init_status initialized;
node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
secname = secname_for_decl (decl);
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
else
initialized = STATUS_INITIALIZED;
list = new_loc_list (loc_descriptor (varloc, initialized),
node->label, node->next->label, secname, 1);
node = node->next;
for (; node->next; node = node->next)
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
{
enum var_init_status initialized =
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
add_loc_descr_to_loc_list (&list,
loc_descriptor (varloc, initialized),
node->label, node->next->label, secname);
}
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
{
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
enum var_init_status initialized =
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
if (!current_function_decl)
endname = text_end_label;
else
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
add_loc_descr_to_loc_list (&list,
loc_descriptor (varloc, initialized),
node->label, endname, secname);
}
add_AT_loc_list (die, attr, list);
return;
}
rtl = rtl_for_decl_location (decl);
if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
{
add_const_value_attribute (die, rtl);
return;
}
if (loc_list && loc_list->first)
{
enum var_init_status status;
node = loc_list->first;
status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
if (descr)
{
add_AT_location_description (die, attr, descr);
return;
}
}
descr = loc_descriptor_from_tree (decl);
if (descr)
{
add_AT_location_description (die, attr, descr);
return;
}
tree_add_const_value_attribute (die, decl);
}
static void
tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
{
tree init = DECL_INITIAL (decl);
tree type = TREE_TYPE (decl);
rtx rtl;
if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
;
else
return;
rtl = rtl_for_decl_init (init, type);
if (rtl)
add_const_value_attribute (var_die, rtl);
}
static dw_loc_list_ref
convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
{
dw_fde_ref fde;
dw_loc_list_ref list, *list_tail;
dw_cfi_ref cfi;
dw_cfa_location last_cfa, next_cfa;
const char *start_label, *last_label, *section;
fde = &fde_table[fde_table_in_use - 1];
section = secname_for_decl (current_function_decl);
list_tail = &list;
list = NULL;
next_cfa.reg = INVALID_REGNUM;
next_cfa.offset = 0;
next_cfa.indirect = 0;
next_cfa.base_offset = 0;
start_label = fde->dw_fde_begin;
for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
lookup_cfa_1 (cfi, &next_cfa);
last_cfa = next_cfa;
last_label = start_label;
for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
switch (cfi->dw_cfi_opc)
{
case DW_CFA_set_loc:
case DW_CFA_advance_loc1:
case DW_CFA_advance_loc2:
case DW_CFA_advance_loc4:
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
start_label, last_label, section,
list == NULL);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
start_label = last_label;
}
last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc:
case DW_CFA_remember_state:
case DW_CFA_restore_state:
gcc_unreachable ();
default:
lookup_cfa_1 (cfi, &next_cfa);
break;
}
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
start_label, last_label, section,
list == NULL);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
start_label, fde->dw_fde_end, section,
list == NULL);
return list;
}
static void
compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
{
rtx reg, elim;
#ifdef FRAME_POINTER_CFA_OFFSET
reg = frame_pointer_rtx;
offset += FRAME_POINTER_CFA_OFFSET (current_function_decl);
#else
reg = arg_pointer_rtx;
offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
#endif
elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
if (GET_CODE (elim) == PLUS)
{
offset += INTVAL (XEXP (elim, 1));
elim = XEXP (elim, 0);
}
frame_pointer_fb_offset_from = elim;
frame_pointer_fb_offset = -offset;
}
static void
add_name_attribute (dw_die_ref die, const char *name_string)
{
if (name_string != NULL && *name_string != 0)
{
if (demangle_name_func)
name_string = (*demangle_name_func) (name_string);
add_AT_string (die, DW_AT_name, name_string);
}
}
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);
}
static void
add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
{
switch (TREE_CODE (bound))
{
case ERROR_MARK:
return;
case INTEGER_CST:
if (! host_integerp (bound, 0)
|| (bound_attr == DW_AT_lower_bound
&& (((is_c_family () || is_java ()) && integer_zerop (bound))
|| (is_fortran () && integer_onep (bound)))))
;
else
add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
break;
case CONVERT_EXPR:
case NOP_EXPR:
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
break;
case SAVE_EXPR:
break;
case VAR_DECL:
case PARM_DECL:
case RESULT_DECL:
{
dw_die_ref decl_die = lookup_decl_die (bound);
if (decl_die != NULL)
add_AT_die_ref (subrange_die, bound_attr, decl_die);
break;
}
default:
{
dw_die_ref ctx, decl_die;
dw_loc_descr_ref loc;
loc = loc_descriptor_from_tree (bound);
if (loc == NULL)
break;
if (current_function_decl == 0)
ctx = comp_unit_die;
else
ctx = lookup_decl_die (current_function_decl);
decl_die = new_die (DW_TAG_variable, ctx, bound);
add_AT_flag (decl_die, DW_AT_artificial, 1);
add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
add_AT_loc (decl_die, DW_AT_location, loc);
add_AT_die_ref (subrange_die, bound_attr, decl_die);
break;
}
}
}
static void
add_subscript_info (dw_die_ref type_die, tree type)
{
#ifndef MIPS_DEBUGGING_INFO
unsigned dimension_number;
#endif
tree lower, upper;
dw_die_ref subrange_die;
#ifndef MIPS_DEBUGGING_INFO
for (dimension_number = 0;
TREE_CODE (type) == ARRAY_TYPE;
type = TREE_TYPE (type), dimension_number++)
#endif
{
tree domain = TYPE_DOMAIN (type);
subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
if (domain)
{
lower = TYPE_MIN_VALUE (domain);
upper = TYPE_MAX_VALUE (domain);
if (TREE_TYPE (domain))
{
if (TREE_CODE (domain) == INTEGER_TYPE
&& TYPE_NAME (domain) == NULL_TREE
&& TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE
&& TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE)
;
else
add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0,
type_die);
}
add_bound_info (subrange_die, DW_AT_lower_bound, lower);
if (upper)
add_bound_info (subrange_die, DW_AT_upper_bound, upper);
}
}
}
static void
add_byte_size_attribute (dw_die_ref die, tree tree_node)
{
unsigned size;
switch (TREE_CODE (tree_node))
{
case ERROR_MARK:
size = 0;
break;
case ENUMERAL_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
size = int_size_in_bytes (tree_node);
break;
case FIELD_DECL:
size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
break;
default:
gcc_unreachable ();
}
add_AT_unsigned (die, DW_AT_byte_size, size);
}
static inline void
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);
HOST_WIDE_INT bitpos_int;
HOST_WIDE_INT highest_order_object_bit_offset;
HOST_WIDE_INT highest_order_field_bit_offset;
HOST_WIDE_INT unsigned bit_offset;
gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
if (! host_integerp (bit_position (decl), 0)
|| ! host_integerp (DECL_SIZE (decl), 1))
return;
bitpos_int = int_bit_position (decl);
highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
highest_order_field_bit_offset = bitpos_int;
if (! BYTES_BIG_ENDIAN)
{
highest_order_field_bit_offset += tree_low_cst (DECL_SIZE (decl), 0);
highest_order_object_bit_offset += simple_type_size_in_bits (type);
}
bit_offset
= (! BYTES_BIG_ENDIAN
? highest_order_object_bit_offset - highest_order_field_bit_offset
: highest_order_field_bit_offset - highest_order_object_bit_offset);
add_AT_unsigned (die, DW_AT_bit_offset, bit_offset);
}
static inline void
add_bit_size_attribute (dw_die_ref die, tree decl)
{
gcc_assert (TREE_CODE (decl) == FIELD_DECL
&& DECL_BIT_FIELD_TYPE (decl));
if (host_integerp (DECL_SIZE (decl), 1))
add_AT_unsigned (die, DW_AT_bit_size, tree_low_cst (DECL_SIZE (decl), 1));
}
static inline void
add_prototyped_attribute (dw_die_ref die, tree func_type)
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
if ((lang == DW_LANG_C89 || lang == DW_LANG_ObjC)
&& TYPE_ARG_TYPES (func_type) != NULL)
add_AT_flag (die, DW_AT_prototyped, 1);
}
static inline void
add_abstract_origin_attribute (dw_die_ref die, tree origin)
{
dw_die_ref origin_die = NULL;
if (TREE_CODE (origin) != FUNCTION_DECL)
{
tree fn = origin;
if (TYPE_P (fn))
fn = TYPE_STUB_DECL (fn);
fn = decl_function_context (fn);
if (fn)
dwarf2out_abstract_function (fn);
}
if (DECL_P (origin))
origin_die = lookup_decl_die (origin);
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
if (origin_die)
{
add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
if (die->die_tag == DW_TAG_inlined_subroutine)
{
dw_attr_ref inline_attr = get_AT (origin_die, DW_AT_inline);
if (!inline_attr)
{
if (DECL_P (origin) && DECL_DECLARED_INLINE_P (origin))
add_AT_unsigned (origin_die, DW_AT_inline, DW_INL_declared_inlined);
else
add_AT_unsigned (origin_die, DW_AT_inline, DW_INL_inlined);
}
}
}
}
static inline void
add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
{
if (DECL_VINDEX (func_decl))
{
add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
if (host_integerp (DECL_VINDEX (func_decl), 0))
add_AT_loc (die, DW_AT_vtable_elem_location,
new_loc_descr (DW_OP_constu,
tree_low_cst (DECL_VINDEX (func_decl), 0),
0));
if (debug_info_level > DINFO_LEVEL_TERSE)
add_AT_die_ref (die, DW_AT_containing_type,
lookup_type_die (DECL_CONTEXT (func_decl)));
}
}
static void
add_src_coords_attributes_locus (dw_die_ref die, expanded_location s)
{
add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
add_AT_unsigned (die, DW_AT_decl_line, s.line);
}
static void
add_src_coords_attributes (dw_die_ref die, tree decl)
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
add_AT_unsigned (die, DW_AT_decl_line, s.line);
}
static bool
assembler_name_exists_and_is_different (tree decl)
{
bool ret_val = true;
const char *assem_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
unsigned int len = strlen (name);
if (!assem_name)
ret_val = false;
else
{
if (strlen (assem_name) < len)
len = strlen (assem_name);
if (strncmp (name, assem_name, len) == 0)
ret_val = false;
}
return ret_val;
}
static void
add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
{
tree decl_name;
decl_name = DECL_NAME (decl);
if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
{
add_name_attribute (die, dwarf2_name (decl, 0));
if (! DECL_ARTIFICIAL (decl))
add_src_coords_attributes (die, decl);
if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
&& (TREE_PUBLIC (decl) || TREE_STATIC (decl) || DECL_EXTERNAL (decl))
&& assembler_name_exists_and_is_different (decl)
&& !DECL_ABSTRACT (decl)
&& !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)))
add_AT_string (die, DW_AT_MIPS_linkage_name,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
#ifdef VMS_DEBUGGING_INFO
if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
{
add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
XEXP (DECL_RTL (decl), 0));
VEC_safe_push (tree, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
}
#endif
}
static void
push_decl_scope (tree scope)
{
VEC_safe_push (tree, gc, decl_scope_table, scope);
}
static inline void
pop_decl_scope (void)
{
VEC_pop (tree, decl_scope_table);
}
static dw_die_ref
scope_die_for (tree t, dw_die_ref context_die)
{
dw_die_ref scope_die = NULL;
tree containing_scope;
int i;
gcc_assert (TYPE_P (t));
containing_scope = TYPE_CONTEXT (t);
if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
{
if (context_die == lookup_decl_die (containing_scope))
;
else
containing_scope = NULL_TREE;
}
if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE)
containing_scope = NULL_TREE;
if (containing_scope == NULL_TREE)
scope_die = comp_unit_die;
else if (TYPE_P (containing_scope))
{
for (i = VEC_length (tree, decl_scope_table) - 1; i >= 0; --i)
if (VEC_index (tree, decl_scope_table, i) == containing_scope)
break;
if (i < 0)
{
gcc_assert (debug_info_level <= DINFO_LEVEL_TERSE
|| TREE_ASM_WRITTEN (containing_scope));
scope_die = comp_unit_die;
}
else
scope_die = lookup_type_die (containing_scope);
}
else
scope_die = context_die;
return scope_die;
}
static inline int
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
|| context_die->die_tag == DW_TAG_subprogram)
return 1;
return 0;
}
static inline int
class_or_namespace_scope_p (dw_die_ref context_die)
{
return (context_die
&& (context_die->die_tag == DW_TAG_structure_type
|| context_die->die_tag == DW_TAG_union_type
|| context_die->die_tag == DW_TAG_namespace));
}
static void
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;
if (code == BLOCK_POINTER_TYPE && generic_block_literal_struct_type)
{
type = build_pointer_type (generic_block_literal_struct_type);
code = TREE_CODE (type);
}
if ((code == INTEGER_TYPE || code == REAL_TYPE)
&& TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
type = TREE_TYPE (type), code = TREE_CODE (type);
if (code == ERROR_MARK
|| code == VOID_TYPE)
return;
type_die = modified_type_die (type,
decl_const || TYPE_READONLY (type),
decl_volatile || TYPE_VOLATILE (type),
context_die);
if (type_die != NULL)
add_AT_die_ref (object_die, DW_AT_type, type_die);
}
static void
add_calling_convention_attribute (dw_die_ref subr_die, tree type)
{
enum dwarf_calling_convention value = DW_CC_normal;
value = targetm.dwarf_calling_convention (type);
if (value && (value != DW_CC_normal))
add_AT_unsigned (subr_die, DW_AT_calling_convention, value);
}
static const char *
type_tag (tree type)
{
const char *name = 0;
if (TYPE_NAME (type) != 0)
{
tree t = 0;
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
t = TYPE_NAME (type);
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ! DECL_IGNORED_P (TYPE_NAME (type)))
t = DECL_NAME (TYPE_NAME (type));
if (t != 0)
name = IDENTIFIER_POINTER (t);
}
return (name == 0 || *name == '\0') ? 0 : name;
}
static inline tree
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 (tree decl)
{
rtx x;
const char *fnname;
x = DECL_RTL (decl);
gcc_assert (MEM_P (x));
x = XEXP (x, 0);
gcc_assert (GET_CODE (x) == SYMBOL_REF);
fnname = XSTR (x, 0);
return fnname;
}
#endif
static void
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;
tree element_type;
#ifdef MIPS_DEBUGGING_INFO
gen_type_die (TREE_TYPE (type), context_die);
#endif
array_die = new_die (DW_TAG_array_type, scope_die, type);
add_name_attribute (array_die, type_tag (type));
equate_type_number_to_die (type, array_die);
if (TREE_CODE (type) == VECTOR_TYPE)
{
type = TREE_TYPE (TYPE_FIELDS (TYPE_DEBUG_REPRESENTATION_TYPE (type)));
add_AT_flag (array_die, DW_AT_GNU_vector, 1);
}
#if 0
add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
#endif
#ifdef MIPS_DEBUGGING_INFO
if (! TYPE_DOMAIN (type))
add_AT_flag (array_die, DW_AT_declaration, 1);
else
#endif
add_subscript_info (array_die, type);
element_type = TREE_TYPE (type);
#ifndef MIPS_DEBUGGING_INFO
while (TREE_CODE (element_type) == ARRAY_TYPE)
element_type = TREE_TYPE (element_type);
gen_type_die (element_type, context_die);
#endif
add_type_attribute (array_die, element_type, 0, 0, context_die);
if (get_AT (array_die, DW_AT_name))
add_pubtype (type, array_die);
}
#if 0
static void
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);
if (origin != NULL)
add_abstract_origin_attribute (decl_die, origin);
else
{
add_name_and_src_coords_attributes (decl_die, decl);
add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
0, 0, context_die);
}
if (DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, decl_die);
else
add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
}
#endif
static void
retry_incomplete_types (void)
{
int i;
for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--)
gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
}
static void
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);
add_abstract_origin_attribute (type_die, type);
}
static void
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);
add_abstract_origin_attribute (type_die, type);
}
static void
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);
add_abstract_origin_attribute (type_die, type);
}
static dw_die_ref
gen_enumeration_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = lookup_type_die (type);
if (type_die == NULL)
{
type_die = new_die (DW_TAG_enumeration_type,
scope_die_for (type, context_die), type);
equate_type_number_to_die (type, type_die);
add_name_attribute (type_die, type_tag (type));
}
else if (! TYPE_SIZE (type))
return type_die;
else
remove_AT (type_die, DW_AT_declaration);
if (TYPE_SIZE (type))
{
tree link;
TREE_ASM_WRITTEN (type) = 1;
add_byte_size_attribute (type_die, type);
if (TYPE_STUB_DECL (type) != NULL_TREE)
add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
if (type_die->die_parent == NULL)
add_child_die (scope_die_for (type, context_die), type_die);
for (link = TYPE_VALUES (type);
link != NULL; link = TREE_CHAIN (link))
{
dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
tree value = TREE_VALUE (link);
add_name_attribute (enum_die,
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
if (host_integerp (value, TYPE_UNSIGNED (TREE_TYPE (value))))
add_AT_int (enum_die, DW_AT_const_value,
tree_low_cst (value, tree_int_cst_sgn (value) > 0));
}
}
else
add_AT_flag (type_die, DW_AT_declaration, 1);
if (get_AT (type_die, DW_AT_name))
add_pubtype (type, type_die);
return type_die;
}
static dw_die_ref
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);
tree origin;
switch (TREE_CODE_CLASS (TREE_CODE (node)))
{
case tcc_declaration:
origin = decl_ultimate_origin (node);
if (origin != NULL)
add_abstract_origin_attribute (parm_die, origin);
else
{
add_name_and_src_coords_attributes (parm_die, node);
add_type_attribute (parm_die, TREE_TYPE (node),
TREE_READONLY (node),
TREE_THIS_VOLATILE (node),
context_die);
if (DECL_ARTIFICIAL (node))
add_AT_flag (parm_die, DW_AT_artificial, 1);
}
equate_decl_number_to_die (node, parm_die);
if (! DECL_ABSTRACT (node))
add_location_or_const_value_attribute (parm_die, node, DW_AT_location);
break;
case tcc_type:
add_type_attribute (parm_die, node, 0, 0, context_die);
break;
default:
gcc_unreachable ();
}
return parm_die;
}
static void
gen_unspecified_parameters_die (tree decl_or_type, dw_die_ref context_die)
{
new_die (DW_TAG_unspecified_parameters, context_die, decl_or_type);
}
static void
gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
{
tree link;
tree formal_type = NULL;
tree first_parm_type;
tree arg;
if (TREE_CODE (function_or_method_type) == FUNCTION_DECL)
{
arg = DECL_ARGUMENTS (function_or_method_type);
function_or_method_type = TREE_TYPE (function_or_method_type);
}
else
arg = NULL_TREE;
first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
for (link = first_parm_type; link; )
{
dw_die_ref parm_die;
formal_type = TREE_VALUE (link);
if (formal_type == void_type_node)
break;
parm_die = gen_formal_parameter_die (formal_type, context_die);
if ((TREE_CODE (function_or_method_type) == METHOD_TYPE
&& link == first_parm_type)
|| (arg && DECL_ARTIFICIAL (arg)))
add_AT_flag (parm_die, DW_AT_artificial, 1);
link = TREE_CHAIN (link);
if (arg)
arg = TREE_CHAIN (arg);
}
if (formal_type != void_type_node)
gen_unspecified_parameters_die (function_or_method_type, context_die);
for (link = TYPE_ARG_TYPES (function_or_method_type);
link && TREE_VALUE (link);
link = TREE_CHAIN (link))
gen_type_die (TREE_VALUE (link), context_die);
}
static void
gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
{
gen_type_die (type, context_die);
if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
&& ! lookup_decl_die (member))
{
dw_die_ref type_die;
gcc_assert (!decl_ultimate_origin (member));
push_decl_scope (type);
type_die = lookup_type_die (type);
if (TREE_CODE (member) == FUNCTION_DECL)
gen_subprogram_die (member, type_die);
else if (TREE_CODE (member) == FIELD_DECL)
{
if (DECL_NAME (member) != NULL_TREE
|| TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
{
gen_type_die (member_declared_type (member), type_die);
gen_field_die (member, type_die);
}
}
else
gen_variable_die (member, type_die);
pop_decl_scope ();
}
}
static void
dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
tree save_fn;
struct function *save_cfun;
tree context;
int was_abstract = DECL_ABSTRACT (decl);
decl = DECL_ORIGIN (decl);
old_die = lookup_decl_die (decl);
if (old_die && get_AT (old_die, DW_AT_inline))
return;
if (debug_info_level > DINFO_LEVEL_TERSE)
{
context = decl_class_context (decl);
if (context)
gen_type_die_for_member
(context, decl, decl_function_context (decl) ? NULL : comp_unit_die);
}
save_fn = current_function_decl;
save_cfun = cfun;
current_function_decl = decl;
cfun = DECL_STRUCT_FUNCTION (decl);
set_decl_abstract_flags (decl, 1);
dwarf2out_decl (decl);
if (! was_abstract)
set_decl_abstract_flags (decl, 0);
current_function_decl = save_fn;
cfun = save_cfun;
}
static int
premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
{
tree type;
dw_die_ref die;
type = *slot;
die = lookup_type_die (type);
if (die != NULL)
die->die_perennial_p = 1;
return 1;
}
static void
premark_used_types (void)
{
if (cfun && cfun->used_types_hash)
htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
}
static void
gen_subprogram_die (tree decl, dw_die_ref context_die)
{
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
tree origin = decl_ultimate_origin (decl);
dw_die_ref subr_die;
tree fn_arg_types;
tree outer_scope;
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (current_function_decl != decl
|| class_or_namespace_scope_p (context_die));
premark_used_types ();
if (origin && declaration && class_or_namespace_scope_p (context_die))
{
origin = NULL;
gcc_assert (!old_die);
}
if (!declaration && !origin && !old_die
&& DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
&& !class_or_namespace_scope_p (context_die)
&& debug_info_level > DINFO_LEVEL_TERSE)
old_die = force_decl_die (decl);
if (origin != NULL)
{
gcc_assert (!declaration || local_scope_p (context_die));
if (old_die && old_die->die_parent == NULL)
add_child_die (context_die, old_die);
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
add_abstract_origin_attribute (subr_die, origin);
}
else if (old_die)
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
struct dwarf_file_data * file_index = lookup_filename (s.file);
if (!get_AT_flag (old_die, DW_AT_declaration)
&& !get_AT (old_die, DW_AT_inline))
{
return;
}
if ((old_die->die_parent == comp_unit_die || context_die == NULL)
&& (DECL_ARTIFICIAL (decl)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) s.line))))
{
subr_die = old_die;
remove_AT (subr_die, DW_AT_declaration);
remove_child_TAG (subr_die, DW_TAG_formal_parameter);
}
else
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
add_AT_specification (subr_die, old_die);
if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
add_AT_file (subr_die, DW_AT_decl_file, file_index);
if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
}
}
else
{
if (BLOCK_SYNTHESIZED_FUNC (decl))
subr_die = new_die (DW_TAG_subprogram, comp_unit_die, decl);
else
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
if (TREE_PUBLIC (decl))
add_AT_flag (subr_die, DW_AT_external, 1);
add_name_and_src_coords_attributes (subr_die, decl);
if (debug_info_level > DINFO_LEVEL_TERSE)
{
add_prototyped_attribute (subr_die, TREE_TYPE (decl));
add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
0, 0, context_die);
}
add_pure_or_virtual_attribute (subr_die, decl);
if (DECL_ARTIFICIAL (decl))
add_AT_flag (subr_die, DW_AT_artificial, 1);
if (TREE_PROTECTED (decl))
add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected);
else if (TREE_PRIVATE (decl))
add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private);
}
if (declaration)
{
if (!old_die || !get_AT (old_die, DW_AT_inline))
{
add_AT_flag (subr_die, DW_AT_declaration, 1);
equate_decl_number_to_die (decl, subr_die);
}
}
else if (DECL_ABSTRACT (decl))
{
if (DECL_DECLARED_INLINE_P (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_declared_not_inlined);
}
else
{
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))
{
HOST_WIDE_INT cfa_fb_offset;
if (TREE_PUBLIC (decl) && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
&& DECL_ABSTRACT_ORIGIN (decl))
add_AT_string (subr_die, DW_AT_MIPS_linkage_name,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
if (!old_die || !get_AT (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
if (!flag_reorder_blocks_and_partition)
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
add_pubname (decl, subr_die);
add_arange (decl, subr_die);
}
else
{
}
#ifdef MIPS_DEBUGGING_INFO
add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
#endif
cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
{
dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
if (list->dw_loc_next)
add_AT_loc_list (subr_die, DW_AT_frame_base, list);
else
add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
}
compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
loc_descriptor_from_tree (cfun->static_chain_decl));
}
if (debug_info_level <= DINFO_LEVEL_TERSE)
;
else if (declaration)
gen_formal_types_die (decl, subr_die);
else
{
tree arg_decls = DECL_ARGUMENTS (decl);
tree parm;
for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
if (TREE_CODE (parm) == PARM_DECL)
{
if (DECL_NAME (parm)
&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
"__builtin_va_alist"))
gen_unspecified_parameters_die (parm, subr_die);
else
gen_decl_die (parm, subr_die);
}
fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
if (fn_arg_types != NULL)
{
if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
gen_unspecified_parameters_die (decl, subr_die);
}
else if (DECL_INITIAL (decl) == NULL_TREE)
gen_unspecified_parameters_die (decl, subr_die);
}
outer_scope = DECL_INITIAL (decl);
if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
{
if (DECL_NAME (DECL_RESULT (decl)))
gen_decl_die (DECL_RESULT (decl), subr_die);
current_function_has_inlines = 0;
decls_for_scope (outer_scope, subr_die, 0);
#if 0 && defined (MIPS_DEBUGGING_INFO)
if (current_function_has_inlines)
{
add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
if (! comp_unit_has_inlines)
{
add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
comp_unit_has_inlines = 1;
}
}
#endif
}
add_calling_convention_attribute (subr_die, TREE_TYPE (decl));
if (optimize > 0)
add_AT_flag (subr_die, DW_AT_APPLE_optimized, 1);
#ifdef TARGET_ARM
if (TARGET_THUMB)
add_AT_int (subr_die, DW_AT_APPLE_isa, DW_ISA_ARM_thumb);
else if (TARGET_ARM)
add_AT_int (subr_die, DW_AT_APPLE_isa, DW_ISA_ARM_arm);
#endif
}
static tree
find_block_byref_var_real_type (tree decl)
{
tree block_struct = TREE_TYPE (decl);
const char *var_name ;
tree var_field;
bool found = false;
tree ret_type = NULL_TREE;
if ((! (DECL_NAME (decl)))
|| (! IDENTIFIER_POINTER (DECL_NAME (decl))))
return ret_type;
if (!block_struct)
return ret_type;
var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
if (TREE_CODE (block_struct) == POINTER_TYPE)
block_struct = TREE_TYPE (block_struct);
if (TREE_CODE (block_struct) != RECORD_TYPE)
return ret_type;
if (! TYPE_NAME (block_struct))
return ret_type;
if (TREE_CODE (TYPE_NAME (block_struct)) != IDENTIFIER_NODE
&& TREE_CODE (TYPE_NAME (block_struct)) != TYPE_DECL)
return ret_type;
if (TREE_CODE (TYPE_NAME (block_struct)) == IDENTIFIER_NODE
&& (strncmp (IDENTIFIER_POINTER (TYPE_NAME (block_struct)),
"__Block_byref_", 14) != 0))
return ret_type;
else if (TREE_CODE (TYPE_NAME (block_struct)) == TYPE_DECL
&& ((! DECL_NAME (TYPE_NAME (block_struct)))
|| (strncmp
(IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (block_struct))),
"__Block_byref_", 14) != 0)))
return ret_type;
var_field = TYPE_FIELDS (block_struct);
while (var_field && !found)
{
if (TREE_CODE (var_field) != FIELD_DECL)
return ret_type;
if (DECL_NAME (var_field)
&& IDENTIFIER_POINTER (DECL_NAME (var_field))
&& strcmp (IDENTIFIER_POINTER (DECL_NAME (var_field)), var_name) == 0)
{
ret_type = TREE_TYPE (var_field);
found = 1;
}
else
var_field = TREE_CHAIN (var_field);
}
return ret_type;
}
static void
blocks_fixup_location_description (dw_loc_descr_ref *main_descr)
{
dw_loc_descr_ref old_descr;
dw_loc_descr_ref new_descr;
enum dwarf_location_atom new_op;
int regno;
unsigned int offset = 0;
old_descr = *main_descr;
if (old_descr->dw_loc_opc >= DW_OP_reg0
&& old_descr->dw_loc_opc <= DW_OP_reg31)
{
regno = old_descr->dw_loc_opc - DW_OP_reg0;
new_op = DW_OP_breg0 + regno;
new_descr = new_loc_descr (new_op, offset, 0);
*main_descr = new_descr;
}
}
static void
build_byref_var_location_expression (dw_loc_descr_ref *main_descr,
bool is_pointer,
int forwarding_field_offset,
int var_field_offset)
{
dw_loc_descr_ref temp_descr;
blocks_fixup_location_description (main_descr);
if (is_pointer)
{
temp_descr = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (main_descr, temp_descr);
}
if (forwarding_field_offset != 0)
{
temp_descr = new_loc_descr (DW_OP_plus_uconst, forwarding_field_offset,
0);
add_loc_descr (main_descr, temp_descr);
}
temp_descr = new_loc_descr (DW_OP_deref, 0, 0);
add_loc_descr (main_descr, temp_descr);
if (var_field_offset != 0)
{
temp_descr = new_loc_descr (DW_OP_plus_uconst, var_field_offset, 0);
add_loc_descr (main_descr, temp_descr);
}
}
static bool
add_block_byref_var_location_attribute (dw_die_ref var_die, tree decl)
{
tree block_struct = TREE_TYPE (decl);
const char *var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
tree var_field = NULL;
tree forwarding_field = NULL;
tree temp_field;
unsigned int forwarding_field_offset = 0;
unsigned int var_field_offset = 0;
bool is_pointer = false;
dw_loc_descr_ref descr;
var_loc_list *loc_list;
if (!block_struct)
return false;
if ((! DECL_NAME (decl))
|| (! IDENTIFIER_POINTER (DECL_NAME (decl))))
return false;
var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
if (TREE_CODE (block_struct) == POINTER_TYPE)
block_struct = TREE_TYPE (block_struct);
if (TREE_CODE (block_struct) != RECORD_TYPE)
return false;
if (! TYPE_NAME (block_struct))
return false;
if (TREE_CODE (TYPE_NAME (block_struct)) != IDENTIFIER_NODE
&& TREE_CODE (TYPE_NAME (block_struct)) != TYPE_DECL)
return false;
if (TREE_CODE (TYPE_NAME (block_struct)) == IDENTIFIER_NODE
&& (strncmp (IDENTIFIER_POINTER (TYPE_NAME (block_struct)),
"__Block_byref_", 14) != 0))
return false;
else if (TREE_CODE (TYPE_NAME (block_struct)) == TYPE_DECL
&& ((! DECL_NAME (TYPE_NAME (block_struct)))
|| (strncmp
(IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (block_struct))),
"__Block_byref_", 14) != 0)))
return false;
temp_field = TYPE_FIELDS (block_struct);
while (temp_field
&& (!var_field || !forwarding_field))
{
if (TREE_CODE (temp_field) != FIELD_DECL)
return false;
if (DECL_NAME (temp_field)
&& IDENTIFIER_POINTER (DECL_NAME (temp_field)))
{
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (temp_field)),
var_name) == 0)
var_field = temp_field;
else if (strcmp (IDENTIFIER_POINTER (DECL_NAME (temp_field)),
"__forwarding") == 0)
forwarding_field = temp_field;
}
temp_field = TREE_CHAIN (temp_field);
}
if (!var_field || !forwarding_field)
return false;
if (var_field)
var_field_offset = field_byte_offset (var_field);
if (forwarding_field)
forwarding_field_offset = field_byte_offset (forwarding_field);
if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
is_pointer = true;
loc_list = lookup_decl_loc (decl);
if (loc_list && loc_list->first != loc_list->last)
{
struct var_loc_node *node;
rtx varloc;
dw_loc_list_ref list;
const char *endname, *secname;
node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
secname = secname_for_decl (decl);
descr = loc_descriptor (varloc, STATUS_INITIALIZED);
build_byref_var_location_expression (&descr, is_pointer,
forwarding_field_offset,
var_field_offset);
list = new_loc_list (descr, node->label, node->next->label, secname, 1);
node = node->next;
for (; node->next; node = node->next)
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
{
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
descr = loc_descriptor (varloc, STATUS_INITIALIZED);
build_byref_var_location_expression (&descr, is_pointer,
forwarding_field_offset,
var_field_offset);
add_loc_descr_to_loc_list (&list, descr, node->label,
node->next->label, secname);
}
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
{
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
if (!current_function_decl)
endname = text_end_label;
else
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
descr = loc_descriptor (varloc, STATUS_INITIALIZED);
build_byref_var_location_expression (&descr, is_pointer,
forwarding_field_offset,
var_field_offset);
add_loc_descr_to_loc_list (&list, descr, node->label, endname,
secname);
}
add_AT_loc_list (var_die, DW_AT_location, list);
}
else
{
descr = loc_descriptor_from_tree (decl);
if (!descr)
return false;
build_byref_var_location_expression (&descr, is_pointer,
forwarding_field_offset,
var_field_offset);
add_AT_location_description (var_die, DW_AT_location, descr);
}
return true;
}
static void
gen_variable_die (tree decl, dw_die_ref context_die)
{
bool is_block_byref_var = false;
tree decl_type = TREE_TYPE (decl);
tree origin = decl_ultimate_origin (decl);
dw_die_ref var_die = new_die (DW_TAG_variable, context_die, decl);
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (DECL_EXTERNAL (decl)
|| (TREE_CODE (decl) == VAR_DECL
&& DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
|| class_or_namespace_scope_p (context_die));
if (decl_type)
{
if (TREE_CODE (decl_type) == POINTER_TYPE)
decl_type = TREE_TYPE (decl_type);
if (decl_type
&& TREE_CODE (decl_type) == RECORD_TYPE
&& TYPE_NAME (decl_type))
{
if (TREE_CODE (TYPE_NAME (decl_type)) == IDENTIFIER_NODE
&& strncmp (IDENTIFIER_POINTER (TYPE_NAME (decl_type)),
"__Block_byref_", 14) == 0)
is_block_byref_var = true;
else if (TREE_CODE (TYPE_NAME (decl_type)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (decl_type))
&& IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl_type)))
&& (strncmp
(IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl_type))),
"__Block_byref_", 14) == 0))
is_block_byref_var = true;
else
is_block_byref_var = false;
}
}
if ((origin != NULL) && lookup_decl_die (origin))
add_abstract_origin_attribute (var_die, origin);
else if (old_die && TREE_STATIC (decl) && ! declaration
&& get_AT_flag (old_die, DW_AT_declaration) == 1)
{
add_AT_specification (var_die, old_die);
if (DECL_NAME (decl))
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
struct dwarf_file_data * file_index = lookup_filename (s.file);
if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
add_AT_file (var_die, DW_AT_decl_file, file_index);
if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
}
}
else
{
add_name_and_src_coords_attributes (var_die, decl);
if (is_block_byref_var)
{
tree real_type = NULL_TREE;
real_type = find_block_byref_var_real_type (decl);
if (real_type)
add_type_attribute (var_die, real_type, TREE_READONLY (decl),
TREE_THIS_VOLATILE (decl), context_die);
else
add_type_attribute (var_die, TREE_TYPE (decl), TREE_READONLY (decl),
TREE_THIS_VOLATILE (decl), context_die);
}
else
add_type_attribute (var_die, TREE_TYPE (decl), TREE_READONLY (decl),
TREE_THIS_VOLATILE (decl), context_die);
if (TREE_PUBLIC (decl))
add_AT_flag (var_die, DW_AT_external, 1);
if (DECL_ARTIFICIAL (decl))
add_AT_flag (var_die, DW_AT_artificial, 1);
if (TREE_PROTECTED (decl))
add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected);
else if (TREE_PRIVATE (decl))
add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private);
}
if (declaration)
add_AT_flag (var_die, DW_AT_declaration, 1);
if (DECL_ABSTRACT (decl) || declaration)
equate_decl_number_to_die (decl, var_die);
if (! declaration && ! DECL_ABSTRACT (decl))
{
bool loc_added = false;
if (is_block_byref_var)
loc_added = add_block_byref_var_location_attribute (var_die, decl);
if (!loc_added)
add_location_or_const_value_attribute (var_die, decl, DW_AT_location);
add_pubname (decl, var_die);
}
else
tree_add_const_value_attribute (var_die, decl);
}
static void
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);
rtx insn;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
if (origin != NULL)
add_abstract_origin_attribute (lbl_die, origin);
else
add_name_and_src_coords_attributes (lbl_die, decl);
if (DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, lbl_die);
else
{
insn = DECL_RTL_IF_SET (decl);
if (insn
&& (LABEL_P (insn)
|| ((NOTE_P (insn)
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))))
{
gcc_assert (!INSN_DELETED_P (insn));
ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
}
}
}
static inline void
add_call_src_coords_attributes (tree stmt, dw_die_ref die)
{
expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
add_AT_unsigned (die, DW_AT_call_line, s.line);
}
static inline void
add_high_low_attributes (tree stmt, dw_die_ref die)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
if (BLOCK_FRAGMENT_CHAIN (stmt))
{
tree chain;
add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
chain = BLOCK_FRAGMENT_CHAIN (stmt);
do
{
add_ranges (chain);
chain = BLOCK_FRAGMENT_CHAIN (chain);
}
while (chain);
add_ranges (NULL);
}
else
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
add_AT_lbl_id (die, DW_AT_low_pc, label);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
BLOCK_NUMBER (stmt));
add_AT_lbl_id (die, DW_AT_high_pc, label);
}
}
static void
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);
if (! BLOCK_ABSTRACT (stmt))
add_high_low_attributes (stmt, stmt_die);
decls_for_scope (stmt, stmt_die, depth);
}
static void
gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
{
tree decl = block_ultimate_origin (stmt);
dwarf2out_abstract_function (decl);
if (! BLOCK_ABSTRACT (stmt))
{
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
add_abstract_origin_attribute (subr_die, decl);
add_high_low_attributes (stmt, subr_die);
add_call_src_coords_attributes (stmt, subr_die);
decls_for_scope (stmt, subr_die, depth);
current_function_has_inlines = 1;
add_inlined_section_entry (subr_die);
}
else
gen_lexical_block_die (stmt, context_die, depth);
}
static void
gen_field_die (tree decl, dw_die_ref context_die)
{
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),
context_die);
if (DECL_BIT_FIELD_TYPE (decl))
{
add_byte_size_attribute (decl_die, decl);
add_bit_size_attribute (decl_die, decl);
add_bit_offset_attribute (decl_die, decl);
}
if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
add_data_member_location_attribute (decl_die, decl);
if (DECL_ARTIFICIAL (decl))
add_AT_flag (decl_die, DW_AT_artificial, 1);
if (TREE_PROTECTED (decl))
add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
else if (TREE_PRIVATE (decl))
add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
equate_decl_number_to_die (decl, decl_die);
}
#if 0
static void
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);
equate_type_number_to_die (type, ptr_die);
add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
}
static void
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);
equate_type_number_to_die (type, ref_die);
add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
}
#endif
static void
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,
scope_die_for (type, context_die), type);
equate_type_number_to_die (type, ptr_die);
add_AT_die_ref (ptr_die, DW_AT_containing_type,
lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
}
static dw_die_ref
gen_compile_unit_die (const char *filename)
{
dw_die_ref die;
char producer[250];
const char *language_string = lang_hooks.name;
int language;
die = new_die (DW_TAG_compile_unit, NULL, NULL);
if (filename)
{
add_name_attribute (die, filename);
if (filename[0] != DIR_SEPARATOR && filename[0] != '<')
add_comp_dir_attribute (die);
}
sprintf (producer, "%s %s", language_string, version_string);
#ifdef MIPS_DEBUGGING_INFO
if (debug_info_level > DINFO_LEVEL_TERSE)
strcat (producer, " -g");
#endif
add_AT_string (die, DW_AT_producer, producer);
if (strcmp (language_string, "GNU C++") == 0)
language = DW_LANG_C_plus_plus;
else if (strcmp (language_string, "GNU Ada") == 0)
language = DW_LANG_Ada95;
else if (strcmp (language_string, "GNU F77") == 0)
language = DW_LANG_Fortran77;
else if (strcmp (language_string, "GNU F95") == 0)
language = DW_LANG_Fortran95;
else if (strcmp (language_string, "GNU Pascal") == 0)
language = DW_LANG_Pascal83;
else if (strcmp (language_string, "GNU Java") == 0)
language = DW_LANG_Java;
else if (strcmp (language_string, "GNU Objective-C") == 0)
language = DW_LANG_ObjC;
else if (strcmp (language_string, "GNU Objective-C++") == 0)
language = DW_LANG_ObjC_plus_plus;
else
language = DW_LANG_C89;
add_AT_unsigned (die, DW_AT_language, language);
return die;
}
static void
gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
{
dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
add_data_member_location_attribute (die, binfo);
if (BINFO_VIRTUAL_P (binfo))
add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
if (access == access_public_node)
add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
else if (access == access_protected_node)
add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
}
static void
gen_member_die (tree type, dw_die_ref context_die)
{
tree member;
tree binfo = TYPE_BINFO (type);
dw_die_ref child;
if (binfo)
{
VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo);
int i;
tree base;
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); i++)
gen_inheritance_die (base,
(accesses ? VEC_index (tree, accesses, i)
: access_public_node), context_die);
}
for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
{
child = lookup_decl_die (member);
if (child)
splice_child_die (context_die, child);
else
gen_decl_die (member, context_die);
}
for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
{
if (DECL_ABSTRACT_ORIGIN (member))
continue;
child = lookup_decl_die (member);
if (child)
splice_child_die (context_die, child);
else
gen_decl_die (member, context_die);
}
}
static void
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;
int nested = 0;
int complete = (TYPE_SIZE (type)
&& (! TYPE_STUB_DECL (type)
|| ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))));
int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace);
if (type_die && ! complete)
return;
if (TYPE_CONTEXT (type) != NULL_TREE
&& (AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
|| TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL))
nested = 1;
scope_die = scope_die_for (type, context_die);
if (! type_die || (nested && scope_die == comp_unit_die))
{
dw_die_ref old_die = type_die;
type_die = new_die (TREE_CODE (type) == RECORD_TYPE
? DW_TAG_structure_type : DW_TAG_union_type,
scope_die, type);
equate_type_number_to_die (type, type_die);
if (old_die)
add_AT_specification (type_die, old_die);
else
add_name_attribute (type_die, type_tag (type));
if (TYPE_BLOCK_IMPL_STRUCT (type))
add_AT_flag (type_die, DW_AT_APPLE_block, 1);
if (TYPE_LANG_SPECIFIC (type)
&& (type_die->die_tag == DW_TAG_structure_type)
&& lang_hooks.types.is_runtime_specific_type (type))
{
if (is_objcxx ())
add_AT_unsigned (type_die, DW_AT_APPLE_runtime_class,
DW_LANG_ObjC_plus_plus);
else if (is_objc ())
add_AT_unsigned (type_die, DW_AT_APPLE_runtime_class,
DW_LANG_ObjC);
else if (is_cxx())
add_AT_unsigned (type_die, DW_AT_APPLE_runtime_class,
DW_LANG_C_plus_plus);
}
}
else
remove_AT (type_die, DW_AT_declaration);
if (complete && !ns_decl)
{
TREE_ASM_WRITTEN (type) = 1;
add_byte_size_attribute (type_die, type);
if (TYPE_STUB_DECL (type) != NULL_TREE)
add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
if (type_die->die_parent == NULL)
add_child_die (scope_die, type_die);
push_decl_scope (type);
gen_member_die (type, type_die);
pop_decl_scope ();
if (TYPE_VFIELD (type))
{
tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
gen_type_die (vtype, context_die);
add_AT_die_ref (type_die, DW_AT_containing_type,
lookup_type_die (vtype));
}
}
else
{
add_AT_flag (type_die, DW_AT_declaration, 1);
if (TYPE_STUB_DECL (type)
&& ! decl_function_context (TYPE_STUB_DECL (type)))
VEC_safe_push (tree, gc, incomplete_types, type);
}
if (get_AT (type_die, DW_AT_name))
add_pubtype (type, type_die);
}
static void
gen_subroutine_type_die (tree type, dw_die_ref context_die)
{
tree return_type = TREE_TYPE (type);
dw_die_ref subr_die
= new_die (DW_TAG_subroutine_type,
scope_die_for (type, context_die), type);
equate_type_number_to_die (type, subr_die);
add_prototyped_attribute (subr_die, type);
add_type_attribute (subr_die, return_type, 0, 0, context_die);
gen_formal_types_die (type, subr_die);
if (get_AT (subr_die, DW_AT_name))
add_pubtype (type, subr_die);
}
static void
gen_typedef_die (tree decl, dw_die_ref context_die)
{
dw_die_ref type_die;
tree origin;
bool type_is_complete_p = true;
if (TREE_ASM_WRITTEN (decl))
return;
TREE_ASM_WRITTEN (decl) = 1;
type_die = new_die (DW_TAG_typedef, context_die, decl);
origin = decl_ultimate_origin (decl);
if (origin != NULL)
add_abstract_origin_attribute (type_die, origin);
else
{
tree type;
add_name_and_src_coords_attributes (type_die, decl);
if (DECL_ORIGINAL_TYPE (decl))
{
type = DECL_ORIGINAL_TYPE (decl);
gcc_assert (type != TREE_TYPE (decl));
equate_type_number_to_die (TREE_TYPE (decl), type_die);
}
else
type = TREE_TYPE (decl);
type_is_complete_p = COMPLETE_TYPE_P (type);
add_type_attribute (type_die, type, TREE_READONLY (decl),
TREE_THIS_VOLATILE (decl), context_die);
}
if (DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, type_die);
if (get_AT (type_die, DW_AT_name)
&& type_is_complete_p)
add_pubtype (decl, type_die);
}
static void
gen_type_die (tree type, dw_die_ref context_die)
{
int need_pop;
if (type == NULL_TREE || type == error_mark_node)
return;
if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
{
if (TREE_ASM_WRITTEN (type))
return;
gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
TREE_ASM_WRITTEN (type) = 1;
gen_decl_die (TYPE_NAME (type), context_die);
return;
}
if (TREE_CODE (type) != VECTOR_TYPE)
type = type_main_variant (type);
if (TREE_ASM_WRITTEN (type))
return;
switch (TREE_CODE (type))
{
case ERROR_MARK:
break;
case BLOCK_POINTER_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
TREE_ASM_WRITTEN (type) = 1;
gen_type_die (TREE_TYPE (type), context_die);
break;
case OFFSET_TYPE:
gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die);
gen_type_die (TREE_TYPE (type), context_die);
gen_ptr_to_mbr_type_die (type, context_die);
break;
case FUNCTION_TYPE:
gen_type_die (TREE_TYPE (type), context_die);
gen_subroutine_type_die (type, context_die);
break;
case METHOD_TYPE:
gen_type_die (TREE_TYPE (type), context_die);
gen_subroutine_type_die (type, context_die);
break;
case ARRAY_TYPE:
gen_array_type_die (type, context_die);
break;
case VECTOR_TYPE:
gen_array_type_die (type, context_die);
break;
case ENUMERAL_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
if (TYPE_CONTEXT (type)
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
{
gen_type_die (TYPE_CONTEXT (type), context_die);
if (TREE_ASM_WRITTEN (type))
return;
push_decl_scope (TYPE_CONTEXT (type));
context_die = lookup_type_die (TYPE_CONTEXT (type));
need_pop = 1;
}
else
{
declare_in_namespace (type, context_die);
need_pop = 0;
}
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
if (!TREE_ASM_WRITTEN (type))
gen_enumeration_type_die (type, context_die);
}
else
gen_struct_or_union_type_die (type, context_die);
if (need_pop)
pop_decl_scope ();
return;
case VOID_TYPE:
case INTEGER_TYPE:
case REAL_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
break;
case LANG_TYPE:
break;
default:
gcc_unreachable ();
}
TREE_ASM_WRITTEN (type) = 1;
}
static void
gen_tagged_type_instantiation_die (tree type, dw_die_ref context_die)
{
if (type == NULL_TREE || type == error_mark_node)
return;
gcc_assert (type == type_main_variant (type));
switch (TREE_CODE (type))
{
case ERROR_MARK:
break;
case ENUMERAL_TYPE:
gen_inlined_enumeration_type_die (type, context_die);
break;
case RECORD_TYPE:
gen_inlined_structure_type_die (type, context_die);
break;
case UNION_TYPE:
case QUAL_UNION_TYPE:
gen_inlined_union_type_die (type, context_die);
break;
default:
gcc_unreachable ();
}
}
static void
gen_block_die (tree stmt, dw_die_ref context_die, int depth)
{
int must_output_die = 0;
tree origin;
tree decl;
enum tree_code origin_code;
if (stmt == NULL_TREE)
return;
if (BLOCK_FRAGMENT_ORIGIN (stmt))
{
tree sub;
for (sub = BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
gen_block_die (sub, context_die, depth + 1);
return;
}
origin = block_ultimate_origin (stmt);
origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK;
if (origin_code == FUNCTION_DECL)
must_output_die = 1;
else
{
if (! is_body_block (origin ? origin : stmt))
{
if (debug_info_level > DINFO_LEVEL_TERSE)
must_output_die = (BLOCK_VARS (stmt) != NULL
&& (TREE_USED (stmt)
|| TREE_ASM_WRITTEN (stmt)
|| BLOCK_ABSTRACT (stmt)));
else
for (decl = BLOCK_VARS (stmt);
decl != NULL; decl = TREE_CHAIN (decl))
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INITIAL (decl))
{
must_output_die = 1;
break;
}
}
}
if (must_output_die)
{
if (origin_code == FUNCTION_DECL)
gen_inlined_subroutine_die (stmt, context_die, depth);
else
gen_lexical_block_die (stmt, context_die, depth);
}
else
decls_for_scope (stmt, context_die, depth);
}
static void
decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
{
tree decl;
tree subblocks;
if (stmt == NULL_TREE)
return;
if (TREE_USED (stmt))
{
for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
{
dw_die_ref die;
if (TREE_CODE (decl) == FUNCTION_DECL)
die = lookup_decl_die (decl);
else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
die = lookup_type_die (TREE_TYPE (decl));
else
die = NULL;
if (die != NULL && die->die_parent == NULL)
add_child_die (context_die, die);
if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
;
else
gen_decl_die (decl, context_die);
}
}
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
for (subblocks = BLOCK_SUBBLOCKS (stmt);
subblocks != NULL;
subblocks = BLOCK_CHAIN (subblocks))
gen_block_die (subblocks, context_die, depth + 1);
}
static inline int
is_redundant_typedef (tree decl)
{
if (TYPE_DECL_IS_STUB (decl))
return 1;
if (DECL_ARTIFICIAL (decl)
&& DECL_CONTEXT (decl)
&& is_tagged_type (DECL_CONTEXT (decl))
&& TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
&& DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
return 1;
return 0;
}
static dw_die_ref
force_decl_die (tree decl)
{
dw_die_ref decl_die;
unsigned saved_external_flag;
tree save_fn = NULL_TREE;
decl_die = lookup_decl_die (decl);
if (!decl_die)
{
dw_die_ref context_die;
tree decl_context = DECL_CONTEXT (decl);
if (decl_context)
{
if (TYPE_P (decl_context))
context_die = force_type_die (decl_context);
else
context_die = force_decl_die (decl_context);
}
else
context_die = comp_unit_die;
decl_die = lookup_decl_die (decl);
if (decl_die)
return decl_die;
switch (TREE_CODE (decl))
{
case FUNCTION_DECL:
save_fn = current_function_decl;
current_function_decl = NULL_TREE;
gen_subprogram_die (decl, context_die);
current_function_decl = save_fn;
break;
case VAR_DECL:
saved_external_flag = DECL_EXTERNAL (decl);
DECL_EXTERNAL (decl) = 1;
gen_decl_die (decl, context_die);
DECL_EXTERNAL (decl) = saved_external_flag;
break;
case NAMESPACE_DECL:
dwarf2out_decl (decl);
break;
default:
gcc_unreachable ();
}
if (!decl_die)
decl_die = lookup_decl_die (decl);
gcc_assert (decl_die);
}
return decl_die;
}
static dw_die_ref
force_type_die (tree type)
{
dw_die_ref type_die;
type_die = lookup_type_die (type);
if (!type_die)
{
dw_die_ref context_die;
if (TYPE_CONTEXT (type))
{
if (TYPE_P (TYPE_CONTEXT (type)))
context_die = force_type_die (TYPE_CONTEXT (type));
else
context_die = force_decl_die (TYPE_CONTEXT (type));
}
else
context_die = comp_unit_die;
type_die = lookup_type_die (type);
if (type_die)
return type_die;
gen_type_die (type, context_die);
type_die = lookup_type_die (type);
gcc_assert (type_die);
}
return type_die;
}
static dw_die_ref
setup_namespace_context (tree thing, dw_die_ref context_die)
{
tree context = (DECL_P (thing)
? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing));
if (context && TREE_CODE (context) == NAMESPACE_DECL)
context_die = force_decl_die (context);
return context_die;
}
static void
declare_in_namespace (tree thing, dw_die_ref context_die)
{
dw_die_ref ns_context;
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
return;
ns_context = setup_namespace_context (thing, context_die);
if (ns_context != context_die)
{
if (DECL_P (thing))
gen_decl_die (thing, ns_context);
else
gen_type_die (thing, ns_context);
}
}
static void
gen_namespace_die (tree decl)
{
dw_die_ref context_die = setup_namespace_context (decl, comp_unit_die);
if (DECL_ABSTRACT_ORIGIN (decl) == NULL)
{
dw_die_ref namespace_die
= new_die (DW_TAG_namespace, context_die, decl);
add_name_and_src_coords_attributes (namespace_die, decl);
equate_decl_number_to_die (decl, namespace_die);
}
else
{
dw_die_ref origin_die
= force_decl_die (DECL_ABSTRACT_ORIGIN (decl));
dw_die_ref namespace_die
= new_die (DW_TAG_imported_declaration, context_die, decl);
add_name_and_src_coords_attributes (namespace_die, decl);
add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
equate_decl_number_to_die (decl, namespace_die);
}
}
static void
gen_decl_die (tree decl, dw_die_ref context_die)
{
tree origin;
if (DECL_P (decl) && DECL_IGNORED_P (decl))
return;
switch (TREE_CODE (decl))
{
case ERROR_MARK:
break;
case CONST_DECL:
break;
case FUNCTION_DECL:
if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE
&& (current_function_decl == NULL_TREE || DECL_ARTIFICIAL (decl)))
break;
#if 0
if (current_function_decl != decl)
;
#endif
if (DECL_ORIGIN (decl) != decl)
dwarf2out_abstract_function (DECL_ABSTRACT_ORIGIN (decl));
else if (cgraph_function_possibly_inlined_p (decl)
&& ! DECL_ABSTRACT (decl)
&& ! class_or_namespace_scope_p (context_die)
&& DECL_INITIAL (decl) != NULL_TREE)
{
dwarf2out_abstract_function (decl);
set_decl_origin_self (decl);
}
else if (debug_info_level > DINFO_LEVEL_TERSE)
{
gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
if (DECL_VINDEX (decl) != NULL_TREE)
gen_type_die (DECL_CONTEXT (decl), context_die);
origin = decl_class_context (decl);
if (origin != NULL_TREE)
gen_type_die_for_member (origin, decl, context_die);
declare_in_namespace (decl, context_die);
}
gen_subprogram_die (decl, context_die);
break;
case TYPE_DECL:
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
{
gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
break;
}
if (is_redundant_typedef (decl))
gen_type_die (TREE_TYPE (decl), context_die);
else
gen_typedef_die (decl, context_die);
break;
case LABEL_DECL:
if (debug_info_level >= DINFO_LEVEL_NORMAL)
gen_label_die (decl, context_die);
break;
case VAR_DECL:
case RESULT_DECL:
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
gen_type_die (TREE_TYPE (decl), context_die);
origin = decl_class_context (decl);
if (origin != NULL_TREE)
gen_type_die_for_member (origin, decl, context_die);
declare_in_namespace (decl, context_die);
origin = decl_ultimate_origin (decl);
if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
gen_formal_parameter_die (decl, context_die);
else
gen_variable_die (decl, context_die);
break;
case FIELD_DECL:
if (DECL_NAME (decl) != NULL_TREE
|| TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
{
gen_type_die (member_declared_type (decl), context_die);
gen_field_die (decl, context_die);
}
break;
case PARM_DECL:
gen_type_die (TREE_TYPE (decl), context_die);
gen_formal_parameter_die (decl, context_die);
break;
case NAMESPACE_DECL:
gen_namespace_die (decl);
break;
default:
gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
break;
}
}
static void
dwarf2out_global_decl (tree decl)
{
if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
dwarf2out_decl (decl);
}
static void
dwarf2out_type_decl (tree decl, int local)
{
if (!local)
dwarf2out_decl (decl);
}
static void
dwarf2out_imported_module_or_decl (tree decl, tree context)
{
dw_die_ref imported_die, at_import_die;
dw_die_ref scope_die;
expanded_location xloc;
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
gcc_assert (decl);
if (!context)
scope_die = comp_unit_die;
else if (TYPE_P (context))
scope_die = force_type_die (context);
else
scope_die = force_decl_die (context);
if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
{
if (is_base_type (TREE_TYPE (decl)))
at_import_die = base_type_die (TREE_TYPE (decl));
else
at_import_die = force_type_die (TREE_TYPE (decl));
}
else
{
at_import_die = lookup_decl_die (decl);
if (!at_import_die)
{
if (TREE_CODE (decl) == FIELD_DECL)
{
tree type = DECL_CONTEXT (decl);
dw_die_ref type_context_die;
if (TYPE_CONTEXT (type))
if (TYPE_P (TYPE_CONTEXT (type)))
type_context_die = force_type_die (TYPE_CONTEXT (type));
else
type_context_die = force_decl_die (TYPE_CONTEXT (type));
else
type_context_die = comp_unit_die;
gen_type_die_for_member (type, decl, type_context_die);
}
at_import_die = force_decl_die (decl);
}
}
if (TREE_CODE (decl) == NAMESPACE_DECL)
imported_die = new_die (DW_TAG_imported_module, scope_die, context);
else
imported_die = new_die (DW_TAG_imported_declaration, scope_die, context);
xloc = expand_location (input_location);
add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
}
void
dwarf2out_decl (tree decl)
{
dw_die_ref context_die = comp_unit_die;
switch (TREE_CODE (decl))
{
case ERROR_MARK:
return;
case FUNCTION_DECL:
if (DECL_INITIAL (decl) == NULL_TREE)
return;
if (decl_function_context (decl)
&& (! BLOCK_SYNTHESIZED_FUNC (decl))
&& debug_info_level > DINFO_LEVEL_TERSE)
context_die = NULL;
break;
case VAR_DECL:
if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
return;
if (TREE_STATIC (decl) && decl_function_context (decl))
context_die = lookup_decl_die (DECL_CONTEXT (decl));
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
break;
case NAMESPACE_DECL:
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
if (lookup_decl_die (decl) != NULL)
return;
break;
case TYPE_DECL:
if (TYPE_DECL_SUPPRESS_DEBUG (decl))
return;
if (DECL_IS_BUILTIN (decl))
{
if (is_cxx ()
&& TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
&& ! DECL_IGNORED_P (decl))
modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
return;
}
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
if (decl_function_context (decl))
context_die = NULL;
break;
default:
return;
}
gen_decl_die (decl, context_die);
}
static void
dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
unsigned int blocknum)
{
switch_to_section (current_function_section ());
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
static void
dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
switch_to_section (current_function_section ());
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
static bool
dwarf2out_ignore_block (tree block)
{
tree decl;
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
if (TREE_CODE (decl) == FUNCTION_DECL
|| (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
return 0;
return 1;
}
static int
file_table_eq (const void *p1_p, const void *p2_p)
{
const struct dwarf_file_data * p1 = p1_p;
const char * p2 = p2_p;
return strcmp (p1->filename, p2) == 0;
}
static hashval_t
file_table_hash (const void *p_p)
{
const struct dwarf_file_data * p = p_p;
return htab_hash_string (p->filename);
}
static struct dwarf_file_data *
lookup_filename (const char *file_name)
{
void ** slot;
struct dwarf_file_data * created;
if (file_table_last_lookup
&& (file_name == file_table_last_lookup->filename
|| strcmp (file_table_last_lookup->filename, file_name) == 0))
return file_table_last_lookup;
slot = htab_find_slot_with_hash (file_table, file_name,
htab_hash_string (file_name), INSERT);
if (*slot)
return *slot;
created = ggc_alloc (sizeof (struct dwarf_file_data));
created->filename = file_name;
created->emitted_number = 0;
*slot = created;
return created;
}
static int
maybe_emit_file (struct dwarf_file_data * fd)
{
if (! fd->emitted_number)
{
if (last_emitted_file)
fd->emitted_number = last_emitted_file->emitted_number + 1;
else
fd->emitted_number = 1;
last_emitted_file = fd;
if (DWARF2_ASM_LINE_DEBUG_INFO)
{
fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
output_quoted_string (asm_out_file, fd->filename);
fputc ('\n', asm_out_file);
}
}
return fd->emitted_number;
}
static void
dwarf2out_var_location (rtx loc_note)
{
char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
struct var_loc_node *newloc;
rtx prev_insn;
static rtx last_insn;
static const char *last_label;
tree decl;
if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
return;
prev_insn = PREV_INSN (loc_note);
newloc = ggc_alloc_cleared (sizeof (struct var_loc_node));
if (last_insn != NULL_RTX
&& last_insn == prev_insn
&& NOTE_P (prev_insn)
&& NOTE_LINE_NUMBER (prev_insn) == NOTE_INSN_VAR_LOCATION)
{
newloc->label = last_label;
}
else
{
ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
loclabel_num++;
newloc->label = ggc_strdup (loclabel);
}
newloc->var_loc_note = loc_note;
newloc->next = NULL;
if (cfun && in_cold_section_p)
newloc->section_label = cfun->cold_section_label;
else
newloc->section_label = text_section_label;
last_insn = loc_note;
last_label = newloc->label;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
add_var_loc_to_decl (decl, newloc);
}
static void
dwarf2out_begin_function (tree fun)
{
htab_empty (decl_loc_table);
if (function_section (fun) != text_section)
have_multiple_function_sections = true;
}
static void
dwarf2out_source_line (unsigned int line, const char *filename)
{
if (debug_info_level >= DINFO_LEVEL_NORMAL
&& line != 0)
{
int file_num = maybe_emit_file (lookup_filename (filename));
switch_to_section (current_function_section ());
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
filename, line);
if (DWARF2_ASM_LINE_DEBUG_INFO)
{
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
line_info_table_in_use++;
}
else if (function_section (current_function_decl) != text_section)
{
dw_separate_line_info_ref line_info;
targetm.asm_out.internal_label (asm_out_file,
SEPARATE_LINE_CODE_LABEL,
separate_line_info_table_in_use);
if (separate_line_info_table_in_use
== separate_line_info_table_allocated)
{
separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
separate_line_info_table
= 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)));
}
line_info
= &separate_line_info_table[separate_line_info_table_in_use++];
line_info->dw_file_num = file_num;
line_info->dw_line_num = line;
line_info->function = current_function_funcdef_no;
}
else
{
dw_line_info_ref line_info;
targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
line_info_table_in_use);
if (line_info_table_in_use == line_info_table_allocated)
{
line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
line_info_table
= 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));
}
line_info = &line_info_table[line_info_table_in_use++];
line_info->dw_file_num = file_num;
line_info->dw_line_num = line;
}
}
}
static void
dwarf2out_od_msg (dw_die_ref die, HOST_WIDE_INT value)
{
add_AT_int (die, DW_AT_GNU_OD_msg, value);
}
static void
dwarf2out_od_category (dw_die_ref die, HOST_WIDE_INT value)
{
add_AT_int (die, DW_AT_GNU_OD_category, value);
}
static void
dwarf2out_od_version (void)
{
if (flag_opt_diary)
add_AT_unsigned (comp_unit_die, DW_AT_GNU_OD_version, 1);
}
static dw_die_ref
gen_new_od_entry_die (dw_die_ref parent)
{
return new_die (DW_TAG_GNU_OD_entry, parent ? parent : comp_unit_die, NULL);
}
static void
dwarf2out_od_entry (enum debug_od_msg msg, expanded_location l)
{
dw_die_ref entry_die = gen_new_od_entry_die (NULL);
dwarf2out_od_msg (entry_die, msg);
add_src_coords_attributes_locus (entry_die, l);
switch (msg)
{
case OD_msg_loop_vectorized:
dwarf2out_od_category (entry_die, OD_report | OD_action);
break;
case OD_msg_loop_not_vectorized:
dwarf2out_od_category (entry_die, OD_report);
break;
case OD_msg_loop_vectorized_using_versioning:
dwarf2out_od_category (entry_die, OD_report | OD_action);
break;
case OD_msg_loop_vectorized_using_peeling:
dwarf2out_od_category (entry_die, OD_report | OD_action);
break;
case OD_msg_loop_not_vectorized_multiple_exits:
dwarf2out_od_category (entry_die, OD_report);
break;
case OD_msg_loop_not_vectorized_bad_data_ref:
dwarf2out_od_category (entry_die, OD_report | OD_hint);
break;
case OD_msg_loop_not_vectorized_unsupported_ops:
dwarf2out_od_category (entry_die, OD_report | OD_limit);
break;
case OD_msg_loop_not_vectorized_data_dep:
dwarf2out_od_category (entry_die, OD_report | OD_hint);
break;
default:
break;
}
}
static void
dwarf2out_start_source_file (unsigned int lineno, const char *filename)
{
if (flag_eliminate_dwarf2_dups)
{
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);
}
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
int file_num = maybe_emit_file (lookup_filename (filename));
switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
lineno);
dw2_asm_output_data_uleb128 (file_num, "file %s", filename);
}
}
static void
dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
{
if (flag_eliminate_dwarf2_dups)
new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
}
}
static void
dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
const char *buffer ATTRIBUTE_UNUSED)
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
dw2_asm_output_nstring (buffer, -1, "The macro");
}
}
static void
dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
const char *buffer ATTRIBUTE_UNUSED)
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
dw2_asm_output_nstring (buffer, -1, "The macro");
}
}
static void
dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
{
file_table = htab_create_ggc (50, file_table_hash,
file_table_eq, NULL);
decl_die_table = htab_create_ggc (10, decl_die_table_hash,
decl_die_table_eq, NULL);
decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
decl_loc_table_eq, NULL);
decl_scope_table = VEC_alloc (tree, gc, 256);
abbrev_die_table = ggc_alloc_cleared (ABBREV_DIE_TABLE_INCREMENT
* sizeof (dw_die_ref));
abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
abbrev_die_table_in_use = 1;
line_info_table = ggc_alloc_cleared (LINE_INFO_TABLE_INCREMENT
* sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
line_info_table_in_use = 1;
pubname_table = VEC_alloc (pubname_entry, gc, 32);
pubtype_table = VEC_alloc (pubname_entry, gc, 32);
debug_inlined_table = VEC_alloc (inlined_entry, gc, 32);
comp_unit_die = gen_compile_unit_die (NULL);
incomplete_types = VEC_alloc (tree, gc, 64);
used_rtx_array = VEC_alloc (rtx, gc, 32);
debug_info_section = get_section (DEBUG_INFO_SECTION,
SECTION_DEBUG, NULL);
debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
SECTION_DEBUG, NULL);
debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
SECTION_DEBUG, NULL);
debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
SECTION_DEBUG, NULL);
debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
debug_loc_section = get_section (DEBUG_LOC_SECTION,
SECTION_DEBUG, NULL);
debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
SECTION_DEBUG, NULL);
#ifdef DEBUG_PUBTYPES_SECTION
debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
SECTION_DEBUG, NULL);
#endif
#ifdef DEBUG_INLINED_SECTION
debug_inlined_section = get_section (DEBUG_INLINED_SECTION,
SECTION_DEBUG, NULL);
#endif
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
SECTION_DEBUG, NULL);
debug_frame_section = get_section (DEBUG_FRAME_SECTION,
SECTION_DEBUG, NULL);
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
DEBUG_ABBREV_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
COLD_TEXT_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
DEBUG_INFO_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
DEBUG_LINE_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
DEBUG_RANGES_SECTION_LABEL, 0);
switch_to_section (debug_abbrev_section);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
switch_to_section (debug_info_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
switch_to_section (debug_line_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
switch_to_section (debug_macinfo_section);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
DEBUG_MACINFO_SECTION_LABEL, 0);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
}
switch_to_section (text_section);
ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
dwarf2out_od_version ();
if (flag_reorder_blocks_and_partition)
{
switch_to_section (unlikely_text_section ());
ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
}
}
static int
output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
{
struct indirect_string_node *node = (struct indirect_string_node *) *h;
if (node->form == DW_FORM_strp)
{
switch_to_section (debug_str_section);
ASM_OUTPUT_LABEL (asm_out_file, node->label);
assemble_string (node->str, strlen (node->str) + 1);
}
return 1;
}
#if ENABLE_ASSERT_CHECKING
static void
verify_marks_clear (dw_die_ref die)
{
dw_die_ref c;
gcc_assert (! die->die_mark);
FOR_EACH_CHILD (die, c, verify_marks_clear (c));
}
#endif
static void
prune_unmark_dies (dw_die_ref die)
{
dw_die_ref c;
if (die->die_mark)
die->die_mark = 0;
FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
}
static void
prune_unused_types_walk_attribs (dw_die_ref die)
{
dw_attr_ref a;
unsigned ix;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
if (a->dw_attr_val.val_class == dw_val_class_die_ref)
{
prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
}
if (AT_class (a) == dw_val_class_str)
a->dw_attr_val.v.val_str->refcount = 0;
}
}
static void
prune_unused_types_mark (dw_die_ref die, int dokids)
{
dw_die_ref c;
if (die->die_mark == 0)
{
die->die_mark = 1;
if (die->die_parent)
prune_unused_types_mark (die->die_parent, 0);
prune_unused_types_walk_attribs (die);
if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
prune_unused_types_mark (die->die_definition, 1);
}
if (dokids && die->die_mark != 2)
{
die->die_mark = 2;
if (die->die_tag == DW_TAG_array_type)
FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
else
FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
}
}
static void
prune_unused_types_walk (dw_die_ref die)
{
dw_die_ref c;
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:
if (die->die_perennial_p)
break;
return;
default:
break;
}
die->die_mark = 1;
prune_unused_types_walk_attribs (die);
FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
}
static void
prune_unused_types_update_strings (dw_die_ref die)
{
dw_attr_ref a;
unsigned ix;
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (AT_class (a) == dw_val_class_str)
{
struct indirect_string_node *s = a->dw_attr_val.v.val_str;
s->refcount++;
if ((s->refcount
== ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
|| s->is_fn_name)
{
void ** slot;
slot = htab_find_slot_with_hash (debug_str_hash, s->str,
htab_hash_string (s->str),
INSERT);
if (*slot == NULL)
*slot = s;
}
}
}
static void
prune_unused_types_prune (dw_die_ref die)
{
dw_die_ref c;
gcc_assert (die->die_mark);
prune_unused_types_update_strings (die);
if (! die->die_child)
return;
c = die->die_child;
do {
dw_die_ref prev = c;
for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
if (c == die->die_child)
{
if (prev == c)
die->die_child = NULL;
else
{
prev->die_sib = c->die_sib;
die->die_child = prev;
}
return;
}
if (c != prev->die_sib)
prev->die_sib = c;
prune_unused_types_prune (c);
} while (c != die->die_child);
}
static void
prune_unused_types_cleanup_inlining (dw_die_ref die, bool should_be_dead)
{
dw_die_ref c;
if (die->die_tag == DW_TAG_inlined_subroutine
&& should_be_dead)
die->dead = 1;
if (die->die_tag == DW_TAG_class_type
|| die->die_tag == DW_TAG_structure_type)
{
if (die->die_mark)
should_be_dead = 0;
else
should_be_dead = 1;
}
FOR_EACH_CHILD (die, c,
prune_unused_types_cleanup_inlining (c, should_be_dead));
}
static void
prune_unused_types (void)
{
unsigned int i;
limbo_die_node *node;
pubname_ref pub;
#if ENABLE_ASSERT_CHECKING
verify_marks_clear (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
verify_marks_clear (node->die);
#endif
prune_unused_types_walk (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unused_types_walk (node->die);
for (i = 0; VEC_iterate (pubname_entry, pubname_table, i, pub); i++)
prune_unused_types_mark (pub->die, 1);
for (i = 0; i < arange_table_in_use; i++)
prune_unused_types_mark (arange_table[i], 1);
if (debug_str_hash)
htab_empty (debug_str_hash);
prune_unused_types_cleanup_inlining (comp_unit_die, false);
prune_unused_types_prune (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
{
prune_unused_types_cleanup_inlining (node->die, false);
prune_unused_types_prune (node->die);
}
prune_unmark_dies (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unmark_dies (node->die);
}
static int
file_table_relative_p (void ** slot, void *param)
{
bool *p = param;
struct dwarf_file_data *d = *slot;
if (d->emitted_number && d->filename[0] != DIR_SEPARATOR)
{
*p = true;
return 0;
}
return 1;
}
static void
dwarf2out_finish (const char *filename)
{
limbo_die_node *node, *next_node;
dw_die_ref die = 0;
add_name_attribute (comp_unit_die, filename);
maybe_emit_file (lookup_filename (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)
{
bool p = false;
htab_traverse (file_table, file_table_relative_p, &p);
if (p)
add_comp_dir_attribute (comp_unit_die);
}
if (flag_objc_abi > 0)
add_AT_unsigned (comp_unit_die, DW_AT_APPLE_major_runtime_vers,
flag_objc_abi);
{
char * debugopt = getenv("RC_DEBUG_OPTIONS");
if (debugopt && debugopt[0])
add_AT_string (comp_unit_die, DW_AT_APPLE_flags, get_arguments());
}
if (optimize > 0)
add_AT_flag (comp_unit_die, DW_AT_APPLE_optimized, 1);
for (node = limbo_die_list; node; node = next_node)
{
next_node = node->next;
die = node->die;
if (die->die_parent == NULL)
{
dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
if (origin)
add_child_die (origin->die_parent, die);
else if (die == comp_unit_die)
;
else if (errorcount > 0 || sorrycount > 0)
add_child_die (comp_unit_die, die);
else
{
tree context = NULL_TREE;
gcc_assert (node->created_for);
if (DECL_P (node->created_for))
context = DECL_CONTEXT (node->created_for);
else if (TYPE_P (node->created_for))
context = TYPE_CONTEXT (node->created_for);
gcc_assert (context
&& (TREE_CODE (context) == FUNCTION_DECL
|| TREE_CODE (context) == NAMESPACE_DECL));
origin = lookup_decl_die (context);
if (origin)
add_child_die (origin, die);
else
add_child_die (comp_unit_die, die);
}
}
}
limbo_die_list = NULL;
retry_incomplete_types ();
if (flag_eliminate_unused_debug_types)
prune_unused_types ();
if (flag_eliminate_dwarf2_dups)
break_out_includes (comp_unit_die);
add_sibling_attributes (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
add_sibling_attributes (node->die);
switch_to_section (text_section);
targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
if (flag_reorder_blocks_and_partition)
{
switch_to_section (unlikely_text_section ());
targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
}
if (!have_multiple_function_sections)
{
add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
}
else if (have_location_lists || ranges_table_in_use)
add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
if (have_location_lists)
{
switch_to_section (debug_loc_section);
ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
DEBUG_LOC_SECTION_LABEL, 0);
ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
output_location_lists (die);
}
if (debug_info_level >= DINFO_LEVEL_NORMAL)
add_AT_lineptr (comp_unit_die, DW_AT_stmt_list,
debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
add_AT_macptr (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
for (node = limbo_die_list; node; node = node->next)
output_comp_unit (node->die, 0);
output_comp_unit (comp_unit_die, 0);
switch_to_section (debug_abbrev_section);
output_abbrev_section ();
if (! VEC_empty (pubname_entry, pubname_table))
{
switch_to_section (debug_pubnames_section);
output_pubnames (pubname_table);
}
#ifdef DEBUG_PUBTYPES_SECTION
if (! VEC_empty (pubname_entry, pubtype_table))
{
switch_to_section (debug_pubtypes_section);
output_pubnames (pubtype_table);
}
#endif
#ifdef DEBUG_INLINED_SECTION
if (! VEC_empty (inlined_entry, debug_inlined_table))
{
switch_to_section (debug_inlined_section);
output_debug_inlined_section (debug_inlined_table);
}
#endif
if (fde_table_in_use)
{
switch_to_section (debug_aranges_section);
output_aranges ();
}
if (ranges_table_in_use)
{
switch_to_section (debug_ranges_section);
ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
output_ranges ();
}
if (! DWARF2_ASM_LINE_DEBUG_INFO)
{
switch_to_section (debug_line_section);
output_line_info ();
}
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, 0, "End compilation unit");
}
if (debug_str_hash)
htab_traverse (debug_str_hash, output_indirect_string, NULL);
}
#else
const struct gcc_debug_hooks dwarf2_debug_hooks;
#endif
#include "gt-dwarf2out.h"