#include "config.h"
#include "system.h"
#include "tree.h"
#include "flags.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 "hashtable.h"
#ifdef DWARF2_DEBUGGING_INFO
static void dwarf2out_source_line PARAMS ((unsigned int, const char *));
#endif
int
dwarf2out_do_frame ()
{
return (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
#ifdef DWARF2_FRAME_INFO
|| DWARF2_FRAME_INFO
#endif
#ifdef DWARF2_UNWIND_INFO
|| flag_unwind_tables
|| (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)
#endif
);
}
unsigned current_funcdef_number = 0;
#ifndef PTR_SIZE
#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
#endif
void
default_eh_frame_section ()
{
#ifdef EH_FRAME_SECTION_NAME
named_section_flags (EH_FRAME_SECTION_NAME, SECTION_WRITE);
#else
tree label = get_file_function_name ('F');
data_section ();
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
#endif
}
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
#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;
typedef union dw_cfi_oprnd_struct
{
unsigned long dw_cfi_reg_num;
long int dw_cfi_offset;
const char *dw_cfi_addr;
struct dw_loc_descr_struct *dw_cfi_loc;
}
dw_cfi_oprnd;
typedef struct dw_cfi_struct
{
dw_cfi_ref dw_cfi_next;
enum dwarf_call_frame_info dw_cfi_opc;
dw_cfi_oprnd dw_cfi_oprnd1;
dw_cfi_oprnd dw_cfi_oprnd2;
}
dw_cfi_node;
typedef struct cfa_loc
{
unsigned long reg;
long offset;
long base_offset;
int indirect;
} dw_cfa_location;
typedef struct dw_fde_struct
{
const char *dw_fde_begin;
const char *dw_fde_current_label;
const char *dw_fde_end;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
#ifdef COALESCED_UNWIND_INFO
const char *dw_real_name;
unsigned coalesced : 1;
unsigned explicit : 1;
unsigned public : 1;
unsigned private_extern : 1;
unsigned all_throwers_are_sibcalls : 1;
#endif
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
#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
static dw_fde_ref fde_table;
static unsigned fde_table_allocated;
static unsigned fde_table_in_use;
#define FDE_TABLE_INCREMENT 256
static dw_cfi_ref cie_cfi_head;
static unsigned current_funcdef_fde;
struct ht *debug_str_hash;
struct indirect_string_node
{
struct ht_identifier id;
unsigned int refcount;
unsigned int form;
char *label;
};
static char *stripattributes PARAMS ((const char *));
static const char *dwarf_cfi_name PARAMS ((unsigned));
static dw_cfi_ref new_cfi PARAMS ((void));
static void add_cfi PARAMS ((dw_cfi_ref *, dw_cfi_ref));
static void add_fde_cfi PARAMS ((const char *, dw_cfi_ref));
static void lookup_cfa_1 PARAMS ((dw_cfi_ref,
dw_cfa_location *));
static void lookup_cfa PARAMS ((dw_cfa_location *));
static void reg_save PARAMS ((const char *, unsigned,
unsigned, long));
static void initial_return_save PARAMS ((rtx));
static long stack_adjust_offset PARAMS ((rtx));
static void output_cfi PARAMS ((dw_cfi_ref, dw_fde_ref, int));
static void output_call_frame_info PARAMS ((int));
static void dwarf2out_stack_adjust PARAMS ((rtx));
static void queue_reg_save PARAMS ((const char *, rtx, long));
static void flush_queued_reg_saves PARAMS ((void));
static bool clobbers_queued_reg_save PARAMS ((rtx));
static void dwarf2out_frame_debug_expr PARAMS ((rtx, const char *));
static void output_cfa_loc PARAMS ((dw_cfi_ref));
static void get_cfa_from_loc_descr PARAMS ((dw_cfa_location *,
struct dw_loc_descr_struct *));
static struct dw_loc_descr_struct *build_cfa_loc
PARAMS ((dw_cfa_location *));
static void def_cfa_1 PARAMS ((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 SECTION_ASM_OP
#define SECTION_ASM_OP "\t.section\t"
#endif
#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
#define FRAME_BEGIN_LABEL "Lframe"
#define CIE_AFTER_SIZE_LABEL "LSCIE"
#define CIE_END_LABEL "LECIE"
#define CIE_LENGTH_LABEL "LLCIE"
#define FDE_LABEL "LSFDE"
#define FDE_AFTER_SIZE_LABEL "LASFDE"
#define FDE_END_LABEL "LEFDE"
#define FDE_LENGTH_LABEL "LLFDE"
#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"
#ifdef SET_ASM_OP
#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \
do { \
fprintf (FILE, "%s", SET_ASM_OP); \
assemble_name (FILE, SY); \
fputc (',', FILE); \
assemble_name (FILE, HI); \
fputc ('-', FILE); \
assemble_name (FILE, LO); \
} while (0)
#endif
#endif
#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
#ifndef INCOMING_FRAME_SP_OFFSET
#define INCOMING_FRAME_SP_OFFSET 0
#endif
rtx
expand_builtin_dwarf_fp_regnum ()
{
return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
}
static inline char *
stripattributes (s)
const char *s;
{
char *stripped = xmalloc (strlen (s) + 2);
char *p = stripped;
*p++ = '*';
while (*s && *s != ',')
*p++ = *s++;
*p = '\0';
return stripped;
}
void
expand_builtin_init_dwarf_reg_sizes (address)
tree address;
{
int i;
enum machine_mode mode = TYPE_MODE (char_type_node);
rtx addr = expand_expr (address, NULL_RTX, VOIDmode, 0);
rtx mem = gen_rtx_MEM (BLKmode, addr);
for (i = 0; i < DWARF_FRAME_REGISTERS; i++)
{
HOST_WIDE_INT offset = DWARF_FRAME_REGNUM (i) * GET_MODE_SIZE (mode);
HOST_WIDE_INT size = GET_MODE_SIZE (reg_raw_mode[i]);
if (offset < 0)
continue;
emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
}
}
static const char *
dwarf_cfi_name (cfi_opc)
unsigned 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 ()
{
dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (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 (list_head, 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 ()
{
static char label[20];
static unsigned long label_num = 0;
ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++);
ASM_OUTPUT_LABEL (asm_out_file, label);
return label;
}
static void
add_fde_cfi (label, 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;
fde->dw_fde_current_label = label = xstrdup (label);
xcfi = new_cfi ();
xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
add_cfi (&fde->dw_fde_cfi, xcfi);
}
add_cfi (&fde->dw_fde_cfi, cfi);
}
else
add_cfi (&cie_cfi_head, cfi);
}
static inline void
lookup_cfa_1 (cfi, loc)
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_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_expression:
get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
break;
default:
break;
}
}
static void
lookup_cfa (loc)
dw_cfa_location *loc;
{
dw_cfi_ref cfi;
loc->reg = (unsigned long) -1;
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 long args_size;
static long old_args_size;
void
dwarf2out_def_cfa (label, reg, offset)
const char *label;
unsigned reg;
long offset;
{
dw_cfa_location loc;
loc.indirect = 0;
loc.base_offset = 0;
loc.reg = reg;
loc.offset = offset;
def_cfa_1 (label, &loc);
}
static void
def_cfa_1 (label, loc_p)
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 (loc.reg == old_cfa.reg && loc.offset == old_cfa.offset
&& loc.indirect == old_cfa.indirect
&& (loc.indirect == 0 || loc.base_offset == old_cfa.base_offset))
return;
cfi = new_cfi ();
if (loc.reg == old_cfa.reg && !loc.indirect)
{
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 != (unsigned long) -1
&& !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)
{
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);
cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
}
add_fde_cfi (label, cfi);
}
void
dwarf2out_undefined_regs (label, beg_reg, end_reg)
char *label;
unsigned int beg_reg;
unsigned int end_reg;
{
register dw_cfi_ref cfi;
do {
cfi = new_cfi ();
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (beg_reg);
cfi->dw_cfi_opc = DW_CFA_undefined;
add_fde_cfi (label, cfi);
} while (beg_reg++ < end_reg);
}
void
dwarf2out_same_value_regs (label, beg_reg, end_reg)
char *label;
unsigned int beg_reg;
unsigned int end_reg;
{
register dw_cfi_ref cfi;
do {
cfi = new_cfi ();
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (beg_reg);
cfi->dw_cfi_opc = DW_CFA_same_value;
add_fde_cfi (label, cfi);
} while (beg_reg++ < end_reg);
}
void
dwarf2out_restore_reg (label, reg)
char *label;
unsigned int reg;
{
register dw_cfi_ref cfi;
cfi = new_cfi ();
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = DWARF_FRAME_REGNUM (reg);
cfi->dw_cfi_opc = (cfi->dw_cfi_oprnd1.dw_cfi_reg_num > 0x3f) ? DW_CFA_restore_extended : DW_CFA_restore;
add_fde_cfi (label, cfi);
}
void
dwarf2out_remember_state (label)
char *label;
{
register dw_cfi_ref cfi;
cfi = new_cfi ();
cfi->dw_cfi_opc = DW_CFA_remember_state;
add_fde_cfi (label, cfi);
}
void
dwarf2out_restore_state (label)
char *label;
{
register dw_cfi_ref cfi;
cfi = new_cfi ();
cfi->dw_cfi_opc = DW_CFA_restore_state;
add_fde_cfi (label, cfi);
}
static void
reg_save (label, reg, sreg, offset)
const char *label;
unsigned reg;
unsigned sreg;
long offset;
{
dw_cfi_ref cfi = new_cfi ();
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
if (sreg == (unsigned int) -1)
{
if (reg & ~0x3f)
cfi->dw_cfi_opc = DW_CFA_offset_extended;
else
cfi->dw_cfi_opc = DW_CFA_offset;
#ifdef ENABLE_CHECKING
{
long check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
if (check_offset * DWARF_CIE_DATA_ALIGNMENT != offset)
abort ();
}
#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)
return;
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 (label)
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 (label, size)
const char *label;
long 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 (label, reg, offset)
const char *label;
unsigned reg;
long offset;
{
reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
}
void
dwarf2out_return_save (label, offset)
const char *label;
long offset;
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset);
}
void
dwarf2out_return_reg (label, sreg)
const char *label;
unsigned sreg;
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0);
}
static void
initial_return_save (rtl)
rtx rtl;
{
unsigned int reg = (unsigned int) -1;
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:
if (REGNO (rtl) != STACK_POINTER_REGNUM)
abort ();
offset = 0;
break;
case PLUS:
if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
abort ();
offset = INTVAL (XEXP (rtl, 1));
break;
case MINUS:
if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
abort ();
offset = -INTVAL (XEXP (rtl, 1));
break;
default:
abort ();
}
break;
case PLUS:
if (GET_CODE (XEXP (rtl, 1)) != CONST_INT)
abort ();
initial_return_save (XEXP (rtl, 0));
return;
default:
abort ();
}
reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
}
static long
stack_adjust_offset (pattern)
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));
}
else if (GET_CODE (dest) == MEM)
{
src = XEXP (dest, 0);
code = GET_CODE (src);
if ((code != PRE_DEC && code != PRE_INC && code != PRE_MODIFY)
|| XEXP (src, 0) != stack_pointer_rtx)
return 0;
if (code == PRE_MODIFY)
{
rtx val = XEXP (XEXP (src, 1), 1);
if (GET_CODE (XEXP (src, 1)) != PLUS ||
GET_CODE (val) != CONST_INT)
abort ();
offset = -INTVAL (val);
}
else
offset = GET_MODE_SIZE (GET_MODE (dest));
}
else
return 0;
if (code == PLUS || code == PRE_INC)
offset = -offset;
return offset;
}
static void
dwarf2out_stack_adjust (insn)
rtx insn;
{
HOST_WIDE_INT offset;
const char *label;
int i;
if (!flag_asynchronous_unwind_tables && GET_CODE (insn) == CALL_INSN)
{
insn = PATTERN (insn);
if (GET_CODE (insn) == PARALLEL)
insn = XVECEXP (insn, 0, 0);
if (GET_CODE (insn) == SET)
insn = SET_SRC (insn);
if (GET_CODE (insn) != CALL)
abort ();
dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
return;
}
else if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
return;
if (GET_CODE (insn) == BARRIER)
{
#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);
dwarf2out_args_size (label, args_size);
}
struct queued_reg_save
{
struct queued_reg_save *next;
rtx reg;
long cfa_offset;
};
static struct queued_reg_save *queued_reg_saves;
static const char *last_reg_save_label;
static void
queue_reg_save (label, reg, offset)
const char *label;
rtx reg;
long offset;
{
struct queued_reg_save *q = (struct queued_reg_save *) xmalloc (sizeof (*q));
q->next = queued_reg_saves;
q->reg = reg;
q->cfa_offset = offset;
queued_reg_saves = q;
last_reg_save_label = label;
}
static void
flush_queued_reg_saves ()
{
struct queued_reg_save *q, *next;
for (q = queued_reg_saves; q ; q = next)
{
dwarf2out_reg_save (last_reg_save_label, REGNO (q->reg), q->cfa_offset);
next = q->next;
free (q);
}
queued_reg_saves = NULL;
last_reg_save_label = NULL;
}
static bool
clobbers_queued_reg_save (insn)
rtx insn;
{
struct queued_reg_save *q;
for (q = queued_reg_saves; q ; q = q->next)
if (modified_in_p (q->reg, insn))
return true;
return false;
}
static dw_cfa_location cfa_temp;
static void
dwarf2out_frame_debug_expr (expr, label)
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;
}
if (GET_CODE (expr) != SET)
abort ();
src = SET_SRC (expr);
dest = SET_DEST (expr);
switch (GET_CODE (dest))
{
case REG:
switch (GET_CODE (src))
{
case REG:
if (cfa.reg == (unsigned) REGNO (src))
;
else
abort ();
cfa.reg = REGNO (dest);
cfa_temp.reg = cfa.reg;
cfa_temp.offset = cfa.offset;
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:
if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp.reg)
abort ();
offset = cfa_temp.offset;
break;
default:
abort ();
}
if (XEXP (src, 0) == hard_frame_pointer_rtx)
{
if (cfa.reg != (unsigned) HARD_FRAME_POINTER_REGNUM)
abort ();
cfa.reg = STACK_POINTER_REGNUM;
}
else if (GET_CODE (src) == LO_SUM)
;
else if (XEXP (src, 0) != stack_pointer_rtx)
abort ();
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)
{
if (! frame_pointer_needed)
abort ();
if (GET_CODE (XEXP (src, 0)) == REG
&& (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
abort ();
}
else
{
if (GET_CODE (src) == MINUS)
abort ();
if (GET_CODE (XEXP (src, 0)) == REG
&& 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 (GET_CODE (XEXP (src, 0)) == REG
&& REGNO (XEXP (src, 0)) == cfa_temp.reg
&& XEXP (src, 1) == stack_pointer_rtx)
{
if (cfa.reg != STACK_POINTER_REGNUM)
abort ();
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
abort ();
}
break;
case CONST_INT:
cfa_temp.reg = REGNO (dest);
cfa_temp.offset = INTVAL (src);
break;
case IOR:
if (GET_CODE (XEXP (src, 0)) != REG
|| (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg
|| GET_CODE (XEXP (src, 1)) != CONST_INT)
abort ();
if ((unsigned) REGNO (dest) != cfa_temp.reg)
cfa_temp.reg = REGNO (dest);
cfa_temp.offset |= INTVAL (XEXP (src, 1));
break;
case HIGH:
break;
default:
abort ();
}
def_cfa_1 (label, &cfa);
break;
case MEM:
if (GET_CODE (src) != REG)
abort ();
switch (GET_CODE (XEXP (dest, 0)))
{
case PRE_MODIFY:
if (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1)) != CONST_INT)
abort ();
offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
|| cfa_store.reg != STACK_POINTER_REGNUM)
abort ();
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;
if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
|| cfa_store.reg != STACK_POINTER_REGNUM)
abort ();
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:
if (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT)
offset = INTVAL (XEXP (XEXP (dest, 0), 1));
#if 1
else if (GET_CODE (XEXP (XEXP (dest, 0), 1)) == REG)
{
int the_reg = REGNO (XEXP (XEXP (dest, 0), 1));
rtx insn;
insn = XEXP (XEXP (XEXP (PATTERN (current_output_insn),
0), 0), 1);
if (GET_CODE (insn) == REG)
the_reg = REGNO (insn);
insn = PREV_INSN (current_output_insn);
for (; insn != NULL; insn = PREV_INSN (insn))
{
if (PATTERN (insn) == NULL)
;
else
if (GET_CODE (PATTERN (insn)) == SET)
{
rtx p = PATTERN (insn);
if (SET_DEST (p) != NULL
&& GET_CODE (SET_DEST (p)) == REG
&& REGNO (SET_DEST (p)) == the_reg)
{
if (GET_CODE (SET_SRC (p)) == CONST_INT)
{
offset = INTVAL (SET_SRC (p));
break;
}
else
abort ();
}
}
else
if (GET_CODE (PATTERN (insn)) == CODE_LABEL)
abort ();
}
insn = XEXP (XEXP (dest, 0), 0);
if (GET_CODE (insn) == PLUS && GET_CODE (XEXP (insn, 0)) == REG
&& GET_CODE (XEXP (insn, 1)) == CONST_INT)
{
offset += INTVAL (XEXP (insn, 1));
dest = XEXP (dest, 0);
}
}
#endif
else
abort ();
if (GET_CODE (XEXP (dest, 0)) == MINUS)
offset = -offset;
if (cfa_store.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
offset -= cfa_store.offset;
else if (cfa_temp.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
offset -= cfa_temp.offset;
else
abort ();
break;
case REG:
if (cfa_store.reg == (unsigned) REGNO (XEXP (dest, 0)))
offset = -cfa_store.offset;
else if (cfa_temp.reg == (unsigned) REGNO (XEXP (dest, 0)))
offset = -cfa_temp.offset;
else
abort ();
break;
case POST_INC:
if (cfa_temp.reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
abort ();
offset = -cfa_temp.offset;
cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
break;
default:
abort ();
}
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, offset);
break;
}
else
{
rtx x = XEXP (dest, 0);
if (GET_CODE (x) != REG)
x = XEXP (x, 0);
if (GET_CODE (x) != REG)
abort ();
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, offset);
break;
default:
#ifdef TARGET_ALTIVEC
if (GET_CODE (dest) == UNSPEC_VOLATILE && flag_altivec)
return;
#endif
abort ();
}
}
void
dwarf2out_frame_debug (insn)
rtx insn;
{
const char *label;
rtx src;
if (insn == NULL_RTX)
{
flush_queued_reg_saves ();
lookup_cfa (&cfa);
if (cfa.reg != (unsigned long) DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM))
abort ();
cfa.reg = STACK_POINTER_REGNUM;
cfa_store = cfa;
cfa_temp.reg = -1;
cfa_temp.offset = 0;
return;
}
if (GET_CODE (insn) != INSN || clobbers_queued_reg_save (insn))
flush_queued_reg_saves ();
if (! RTX_FRAME_RELATED_P (insn))
{
if (!ACCUMULATE_OUTGOING_ARGS)
dwarf2out_stack_adjust (insn);
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);
}
static void
output_cfi (cfi, fde, for_eh)
dw_cfi_ref cfi;
dw_fde_ref fde;
int for_eh;
{
if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
dw2_asm_output_data (1, (cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
"DW_CFA_advance_loc 0x%lx",
cfi->dw_cfi_oprnd1.dw_cfi_offset);
else if (cfi->dw_cfi_opc == DW_CFA_offset)
{
dw2_asm_output_data (1, (cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)),
"DW_CFA_offset, column 0x%lx",
cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
}
else if (cfi->dw_cfi_opc == DW_CFA_restore)
dw2_asm_output_data (1, (cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)),
"DW_CFA_restore, column 0x%lx",
cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
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),
NULL);
else
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
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:
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
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:
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
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:
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
NULL);
break;
case DW_CFA_register:
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
NULL);
dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num,
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:
abort ();
default:
break;
}
}
}
static void
output_call_frame_info (for_eh)
int for_eh;
{
unsigned int i;
dw_fde_ref fde;
dw_cfi_ref cfi;
char l1[20], l2[20], section_start_label[20];
int any_lsda_needed = 0;
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;
if (for_eh)
{
int any_eh_needed = flag_asynchronous_unwind_tables;
for (i = 0; i < fde_table_in_use; i++)
if (fde_table[i].uses_eh_lsda)
any_eh_needed = any_lsda_needed = 1;
else if (! fde_table[i].nothrow)
any_eh_needed = 1;
if (! any_eh_needed)
return;
}
if (flag_debug_asm)
app_enable ();
if (for_eh)
(*targetm.asm_out.eh_frame_section) ();
else
named_section_flags (DEBUG_FRAME_SECTION, SECTION_DEBUG);
#ifdef COALESCED_UNWIND_INFO
ASM_OUTPUT_LABEL (asm_out_file, "EH_unwind_info");
#endif
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);
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 : DW_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 = flag_export_coalesced
? ASM_PREFERRED_EH_DATA_FORMAT (2, 1)
: 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;
if (size_of_uleb128 (augmentation_size) != 1)
abort ();
}
}
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");
dw2_asm_output_data (1, DWARF_FRAME_RETURN_COLUMN, "CIE RA Column");
if (augmentation[0])
{
dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
if (eh_personality_libfunc)
{
#ifdef DW2_ENCODE_PERSONALITY_FUNC
DW2_ENCODE_PERSONALITY_FUNC (eh_personality_libfunc);
#else
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, NULL);
#endif
}
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 && (fde->all_throwers_are_sibcalls || (fde->nothrow && ! fde->uses_eh_lsda)))
continue;
#ifdef COALESCED_UNWIND_INFO
ASM_OUTPUT_COAL_UNWIND_LABEL (asm_out_file, fde->dw_real_name,
fde->coalesced,
fde->public && !fde->private_extern,
fde->coalesced
|| fde->public
|| fde->private_extern
|| fde->explicit);
#endif
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, FDE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"FDE Length");
ASM_OUTPUT_LABEL (asm_out_file, l1);
if (for_eh)
dw2_asm_output_reloc_delta (4, l1, section_start_label,
"FDE CIE offset");
else
dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
"FDE CIE offset");
if (for_eh)
{
#ifdef COALESCED_UNWIND_INFO
if (fde->coalesced)
dw2_asm_output_encoded_addr_rtx (fde_encoding,
gen_rtx_SYMBOL_REF (Pmode, fde->dw_real_name),
"FDE initial location");
else
#endif
dw2_asm_output_encoded_addr_rtx (fde_encoding,
gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin),
"FDE initial location");
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");
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;
if (size_of_uleb128 (size) != 1)
abort ();
}
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),
"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 0
if (for_eh)
dw2_asm_output_data (4, 0, "End of Table");
#endif
#ifdef MIPS_DEBUGGING_INFO
ASM_OUTPUT_ALIGN (asm_out_file, 0);
#endif
if (flag_debug_asm)
app_disable ();
}
void
dwarf2out_begin_prologue (line, file)
unsigned int line ATTRIBUTE_UNUSED;
const char *file ATTRIBUTE_UNUSED;
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
dw_fde_ref fde;
current_function_func_begin_label = 0;
#ifdef IA64_UNWIND_INFO
if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
&& ! dwarf2out_do_frame ())
return;
#else
if (! dwarf2out_do_frame ())
return;
#endif
current_funcdef_number++;
function_section (current_function_decl);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_funcdef_number);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
current_funcdef_number);
current_function_func_begin_label = get_identifier (label);
#ifdef IA64_UNWIND_INFO
if (! dwarf2out_do_frame ())
return;
#endif
if (fde_table_in_use == fde_table_allocated)
{
fde_table_allocated += FDE_TABLE_INCREMENT;
fde_table
= (dw_fde_ref) xrealloc (fde_table,
fde_table_allocated * sizeof (dw_fde_node));
}
current_funcdef_fde = fde_table_in_use;
fde = &fde_table[fde_table_in_use++];
fde->dw_fde_begin = xstrdup (label);
fde->dw_fde_current_label = NULL;
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
fde->funcdef_number = current_funcdef_number;
fde->nothrow = current_function_nothrow;
fde->uses_eh_lsda = cfun->uses_eh_lsda;
fde->all_throwers_are_sibcalls = cfun->all_throwers_are_sibcalls;
#ifdef COALESCED_UNWIND_INFO
fde->coalesced = DECL_COALESCED (current_function_decl);
fde->explicit = !fde->coalesced && TREE_PUBLIC (current_function_decl)
&& (strstr (lang_hooks.name, "C++") != NULL)
&& DECL_LANG_FLAG_1 (current_function_decl);
fde->dw_real_name = xstrdup (IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)));
fde->public = TREE_PUBLIC(current_function_decl);
fde->private_extern = DECL_PRIVATE_EXTERN(current_function_decl);
#endif
args_size = old_args_size = 0;
#ifdef DWARF2_DEBUGGING_INFO
if (file)
dwarf2out_source_line (line, file);
#endif
}
void
dwarf2out_end_epilogue ()
{
dw_fde_ref fde;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
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 ()
{
fde_table = (dw_fde_ref) xcalloc (FDE_TABLE_INCREMENT, sizeof (dw_fde_node));
fde_table_allocated = FDE_TABLE_INCREMENT;
fde_table_in_use = 0;
#ifdef DWARF2_UNWIND_INFO
dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
initial_return_save (INCOMING_RETURN_ADDR_RTX);
#endif
}
void
dwarf2out_frame_finish ()
{
if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
output_call_frame_info (0);
if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
output_call_frame_info (1);
}
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;
typedef enum
{
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_float,
dw_val_class_flag,
dw_val_class_die_ref,
dw_val_class_fde_ref,
dw_val_class_lbl_id,
dw_val_class_lbl_offset,
dw_val_class_str
}
dw_val_class;
typedef struct dw_long_long_struct
{
unsigned long hi;
unsigned long low;
}
dw_long_long_const;
typedef struct dw_fp_struct
{
long *array;
unsigned length;
}
dw_float_const;
typedef struct dw_val_struct
{
dw_val_class val_class;
union
{
rtx val_addr;
long unsigned val_offset;
dw_loc_list_ref val_loc_list;
dw_loc_descr_ref val_loc;
long int val_int;
long unsigned val_unsigned;
dw_long_long_const val_long_long;
dw_float_const val_float;
struct
{
dw_die_ref die;
int external;
} val_die_ref;
unsigned val_fde_index;
struct indirect_string_node *val_str;
char *val_lbl_id;
unsigned char val_flag;
}
v;
}
dw_val_node;
typedef struct dw_loc_descr_struct
{
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
{
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;
static const char *dwarf_stack_op_name PARAMS ((unsigned));
static dw_loc_descr_ref new_loc_descr PARAMS ((enum dwarf_location_atom,
unsigned long,
unsigned long));
static void add_loc_descr PARAMS ((dw_loc_descr_ref *,
dw_loc_descr_ref));
static unsigned long size_of_loc_descr PARAMS ((dw_loc_descr_ref));
static unsigned long size_of_locs PARAMS ((dw_loc_descr_ref));
static void output_loc_operands PARAMS ((dw_loc_descr_ref));
static void output_loc_sequence PARAMS ((dw_loc_descr_ref));
static const char *
dwarf_stack_op_name (op)
unsigned op;
{
switch (op)
{
case DW_OP_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_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";
default:
return "OP_<unknown>";
}
}
static inline dw_loc_descr_ref
new_loc_descr (op, oprnd1, oprnd2)
enum dwarf_location_atom op;
unsigned long oprnd1;
unsigned long oprnd2;
{
dw_loc_descr_ref descr
= (dw_loc_descr_ref) xcalloc (1, 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 (list_head, 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 (loc)
dw_loc_descr_ref loc;
{
unsigned long size = 1;
switch (loc->dw_loc_opc)
{
case DW_OP_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_deref_size:
case DW_OP_xderef_size:
size += 1;
break;
default:
break;
}
return size;
}
static unsigned long
size_of_locs (loc)
dw_loc_descr_ref loc;
{
unsigned long size;
for (size = 0; loc != NULL; loc = loc->dw_loc_next)
{
loc->dw_loc_addr = size;
size += size_of_loc_descr (loc);
}
return size;
}
static void
output_loc_operands (loc)
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:
if (HOST_BITS_PER_LONG < 64)
abort ();
dw2_asm_output_data (8, val1->v.val_int, NULL);
break;
case DW_OP_skip:
case DW_OP_bra:
{
int offset;
if (val1->val_class == dw_val_class_loc)
offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
else
abort ();
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:
abort ();
#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_deref_size:
case DW_OP_xderef_size:
dw2_asm_output_data (1, val1->v.val_int, NULL);
break;
default:
break;
}
}
static void
output_loc_sequence (loc)
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 (cfi)
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 (cfa)
dw_cfa_location *cfa;
{
struct dw_loc_descr_struct *head, *tmp;
if (cfa->indirect == 0)
abort ();
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 (cfa->offset != 0)
{
tmp = new_loc_descr (DW_OP_plus_uconst, cfa->offset, 0);
add_loc_descr (&head, tmp);
}
return head;
}
static void
get_cfa_from_loc_descr (cfa, loc)
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\n",
dwarf_stack_op_name (ptr->dw_loc_opc));
}
}
}
#endif
#ifdef DWARF2_DEBUGGING_INFO
static hashnode indirect_string_alloc PARAMS ((hash_table *));
static int output_indirect_string PARAMS ((struct cpp_reader *,
hashnode, const PTR));
static void dwarf2out_init PARAMS ((const char *));
static void dwarf2out_finish PARAMS ((const char *));
static void dwarf2out_define PARAMS ((unsigned int, const char *));
static void dwarf2out_undef PARAMS ((unsigned int, const char *));
static void dwarf2out_start_source_file PARAMS ((unsigned, const char *));
static void dwarf2out_end_source_file PARAMS ((unsigned));
static void dwarf2out_begin_block PARAMS ((unsigned, unsigned));
static void dwarf2out_end_block PARAMS ((unsigned, unsigned));
static bool dwarf2out_ignore_block PARAMS ((tree));
static void dwarf2out_global_decl PARAMS ((tree));
static void dwarf2out_abstract_function PARAMS ((tree));
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,
dwarf2out_end_epilogue,
debug_nothing_tree,
debug_nothing_int,
dwarf2out_decl,
dwarf2out_global_decl,
debug_nothing_tree,
dwarf2out_abstract_function,
debug_nothing_rtx
};
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 dw_line_info_struct
{
unsigned long dw_file_num;
unsigned long dw_line_num;
}
dw_line_info_entry;
typedef struct dw_separate_line_info_struct
{
unsigned long dw_file_num;
unsigned long dw_line_num;
unsigned long function;
}
dw_separate_line_info_entry;
typedef struct dw_attr_struct
{
enum dwarf_attribute dw_attr;
dw_attr_ref dw_attr_next;
dw_val_node dw_attr_val;
}
dw_attr_node;
typedef struct die_struct
{
enum dwarf_tag die_tag;
char *die_symbol;
dw_attr_ref die_attr;
dw_die_ref die_parent;
dw_die_ref die_child;
dw_die_ref die_sib;
dw_offset die_offset;
unsigned long die_abbrev;
int die_mark;
}
die_node;
typedef struct pubname_struct
{
dw_die_ref die;
char *name;
}
pubname_entry;
struct dw_ranges_struct
{
int block_num;
};
typedef struct limbo_die_struct
{
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)))))))
extern int flag_traditional;
#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3)
#define DWARF_LINE_PROLOG_HEADER_SIZE 5
#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
#define DWARF_ARANGES_HEADER_SIZE \
(DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, DWARF2_ADDR_SIZE * 2) \
- DWARF_OFFSET_SIZE)
#define DWARF_ARANGES_PAD_SIZE \
(DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, DWARF2_ADDR_SIZE * 2) \
- (2 * 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
static unsigned long next_die_offset;
static dw_die_ref comp_unit_die;
static limbo_die_node *limbo_die_list = 0;
struct file_table
{
char **table;
unsigned allocated;
unsigned in_use;
unsigned last_lookup_index;
};
#define FILE_TABLE_INCREMENT 64
static struct file_table file_table;
static const char *primary_filename;
static dw_die_ref *decl_die_table;
static unsigned decl_die_table_allocated;
static unsigned decl_die_table_in_use;
#define DECL_DIE_TABLE_INCREMENT 256
varray_type decl_scope_table;
static dw_die_ref *abbrev_die_table;
static unsigned abbrev_die_table_allocated;
static unsigned abbrev_die_table_in_use;
#define ABBREV_DIE_TABLE_INCREMENT 256
static dw_line_info_ref line_info_table;
static unsigned line_info_table_allocated;
static unsigned separate_line_info_table_in_use;
static dw_separate_line_info_ref separate_line_info_table;
static unsigned separate_line_info_table_allocated;
static unsigned line_info_table_in_use;
#define LINE_INFO_TABLE_INCREMENT 1024
static pubname_ref pubname_table;
static unsigned pubname_table_allocated;
static unsigned pubname_table_in_use;
#define PUBNAME_TABLE_INCREMENT 64
static dw_die_ref *arange_table;
static unsigned arange_table_allocated;
static unsigned arange_table_in_use;
#define ARANGE_TABLE_INCREMENT 64
static dw_ranges_ref ranges_table;
static unsigned ranges_table_allocated;
static unsigned ranges_table_in_use;
#define RANGES_TABLE_INCREMENT 64
static unsigned have_location_lists;
varray_type incomplete_types;
static int current_function_has_inlines;
#if 0 && defined (MIPS_DEBUGGING_INFO)
static int comp_unit_has_inlines;
#endif
static varray_type used_rtx_varray;
static int is_pseudo_reg PARAMS ((rtx));
static tree type_main_variant PARAMS ((tree));
static int is_tagged_type PARAMS ((tree));
static const char *dwarf_tag_name PARAMS ((unsigned));
static const char *dwarf_attr_name PARAMS ((unsigned));
static const char *dwarf_form_name PARAMS ((unsigned));
#if 0
static const char *dwarf_type_encoding_name PARAMS ((unsigned));
#endif
static tree decl_ultimate_origin PARAMS ((tree));
static tree block_ultimate_origin PARAMS ((tree));
static tree decl_class_context PARAMS ((tree));
static void add_dwarf_attr PARAMS ((dw_die_ref, dw_attr_ref));
static inline dw_val_class AT_class PARAMS ((dw_attr_ref));
static void add_AT_flag PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned));
static inline unsigned AT_flag PARAMS ((dw_attr_ref));
static void add_AT_int PARAMS ((dw_die_ref,
enum dwarf_attribute, long));
static inline long int AT_int PARAMS ((dw_attr_ref));
static void add_AT_unsigned PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned long));
static inline unsigned long AT_unsigned PARAMS ((dw_attr_ref));
static void add_AT_long_long PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned long,
unsigned long));
static void add_AT_float PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned, long *));
static void add_AT_string PARAMS ((dw_die_ref,
enum dwarf_attribute,
const char *));
static inline const char *AT_string PARAMS ((dw_attr_ref));
static int AT_string_form PARAMS ((dw_attr_ref));
static void add_AT_die_ref PARAMS ((dw_die_ref,
enum dwarf_attribute,
dw_die_ref));
static inline dw_die_ref AT_ref PARAMS ((dw_attr_ref));
static inline int AT_ref_external PARAMS ((dw_attr_ref));
static inline void set_AT_ref_external PARAMS ((dw_attr_ref, int));
static void add_AT_fde_ref PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned));
static void add_AT_loc PARAMS ((dw_die_ref,
enum dwarf_attribute,
dw_loc_descr_ref));
static inline dw_loc_descr_ref AT_loc PARAMS ((dw_attr_ref));
static void add_AT_loc_list PARAMS ((dw_die_ref,
enum dwarf_attribute,
dw_loc_list_ref));
static inline dw_loc_list_ref AT_loc_list PARAMS ((dw_attr_ref));
static void add_AT_addr PARAMS ((dw_die_ref,
enum dwarf_attribute,
rtx));
static inline rtx AT_addr PARAMS ((dw_attr_ref));
static void add_AT_lbl_id PARAMS ((dw_die_ref,
enum dwarf_attribute,
const char *));
static void add_AT_lbl_offset PARAMS ((dw_die_ref,
enum dwarf_attribute,
const char *));
static void add_AT_offset PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned long));
static void add_AT_range_list PARAMS ((dw_die_ref,
enum dwarf_attribute,
unsigned long));
static inline const char *AT_lbl PARAMS ((dw_attr_ref));
static dw_attr_ref get_AT PARAMS ((dw_die_ref,
enum dwarf_attribute));
static const char *get_AT_low_pc PARAMS ((dw_die_ref));
static const char *get_AT_hi_pc PARAMS ((dw_die_ref));
static const char *get_AT_string PARAMS ((dw_die_ref,
enum dwarf_attribute));
static int get_AT_flag PARAMS ((dw_die_ref,
enum dwarf_attribute));
static unsigned get_AT_unsigned PARAMS ((dw_die_ref,
enum dwarf_attribute));
static inline dw_die_ref get_AT_ref PARAMS ((dw_die_ref,
enum dwarf_attribute));
static int is_c_family PARAMS ((void));
static int is_cxx PARAMS ((void));
static int is_java PARAMS ((void));
static int is_fortran PARAMS ((void));
static void remove_AT PARAMS ((dw_die_ref,
enum dwarf_attribute));
static inline void free_die PARAMS ((dw_die_ref));
static void remove_children PARAMS ((dw_die_ref));
static void add_child_die PARAMS ((dw_die_ref, dw_die_ref));
static dw_die_ref new_die PARAMS ((enum dwarf_tag, dw_die_ref,
tree));
static dw_die_ref lookup_type_die PARAMS ((tree));
static void equate_type_number_to_die PARAMS ((tree, dw_die_ref));
static dw_die_ref lookup_decl_die PARAMS ((tree));
static void equate_decl_number_to_die PARAMS ((tree, dw_die_ref));
static void print_spaces PARAMS ((FILE *));
static void print_die PARAMS ((dw_die_ref, FILE *));
static void print_dwarf_line_table PARAMS ((FILE *));
static void reverse_die_lists PARAMS ((dw_die_ref));
static void reverse_all_dies PARAMS ((dw_die_ref));
static dw_die_ref push_new_compile_unit PARAMS ((dw_die_ref, dw_die_ref));
static dw_die_ref pop_compile_unit PARAMS ((dw_die_ref));
static void loc_checksum PARAMS ((dw_loc_descr_ref,
struct md5_ctx *));
static void attr_checksum PARAMS ((dw_attr_ref,
struct md5_ctx *));
static void die_checksum PARAMS ((dw_die_ref,
struct md5_ctx *));
static void compute_section_prefix PARAMS ((dw_die_ref));
static int is_type_die PARAMS ((dw_die_ref));
static int is_comdat_die PARAMS ((dw_die_ref));
static int is_symbol_die PARAMS ((dw_die_ref));
static void assign_symbol_names PARAMS ((dw_die_ref));
static void break_out_includes PARAMS ((dw_die_ref));
static void add_sibling_attributes PARAMS ((dw_die_ref));
static void build_abbrev_table PARAMS ((dw_die_ref));
static void output_location_lists PARAMS ((dw_die_ref));
static int constant_size PARAMS ((long unsigned));
static unsigned long size_of_die PARAMS ((dw_die_ref));
static void calc_die_sizes PARAMS ((dw_die_ref));
static void mark_dies PARAMS ((dw_die_ref));
static void unmark_dies PARAMS ((dw_die_ref));
static unsigned long size_of_pubnames PARAMS ((void));
static unsigned long size_of_aranges PARAMS ((void));
static enum dwarf_form value_format PARAMS ((dw_attr_ref));
static void output_value_format PARAMS ((dw_attr_ref));
static void output_abbrev_section PARAMS ((void));
static void output_die_symbol PARAMS ((dw_die_ref));
static void output_die PARAMS ((dw_die_ref));
static void output_compilation_unit_header PARAMS ((void));
static void output_comp_unit PARAMS ((dw_die_ref));
static const char *dwarf2_name PARAMS ((tree, int));
static void add_pubname PARAMS ((tree, dw_die_ref));
static void output_pubnames PARAMS ((void));
static void add_arange PARAMS ((tree, dw_die_ref));
static void output_aranges PARAMS ((void));
static unsigned int add_ranges PARAMS ((tree));
static void output_ranges PARAMS ((void));
static void output_line_info PARAMS ((void));
static void output_file_names PARAMS ((void));
static dw_die_ref base_type_die PARAMS ((tree));
static tree root_type PARAMS ((tree));
static int is_base_type PARAMS ((tree));
static dw_die_ref modified_type_die PARAMS ((tree, int, int, dw_die_ref));
static int type_is_enum PARAMS ((tree));
static unsigned int reg_number PARAMS ((rtx));
static dw_loc_descr_ref reg_loc_descriptor PARAMS ((rtx));
static dw_loc_descr_ref int_loc_descriptor PARAMS ((HOST_WIDE_INT));
static dw_loc_descr_ref based_loc_descr PARAMS ((unsigned, long));
static int is_based_loc PARAMS ((rtx));
static dw_loc_descr_ref mem_loc_descriptor PARAMS ((rtx, enum machine_mode mode));
static dw_loc_descr_ref concat_loc_descriptor PARAMS ((rtx, rtx));
static dw_loc_descr_ref loc_descriptor PARAMS ((rtx));
static dw_loc_descr_ref loc_descriptor_from_tree PARAMS ((tree, int));
static HOST_WIDE_INT ceiling PARAMS ((HOST_WIDE_INT, unsigned int));
static tree field_type PARAMS ((tree));
static unsigned int simple_type_align_in_bits PARAMS ((tree));
static unsigned int simple_decl_align_in_bits PARAMS ((tree));
static unsigned HOST_WIDE_INT simple_type_size_in_bits PARAMS ((tree));
static HOST_WIDE_INT field_byte_offset PARAMS ((tree));
static void add_AT_location_description PARAMS ((dw_die_ref,
enum dwarf_attribute, rtx));
static void add_data_member_location_attribute PARAMS ((dw_die_ref, tree));
static void add_const_value_attribute PARAMS ((dw_die_ref, rtx));
static rtx rtl_for_decl_location PARAMS ((tree));
static void add_location_or_const_value_attribute PARAMS ((dw_die_ref, tree));
static void tree_add_const_value_attribute PARAMS ((dw_die_ref, tree));
static void add_name_attribute PARAMS ((dw_die_ref, const char *));
static void add_bound_info PARAMS ((dw_die_ref,
enum dwarf_attribute, tree));
static void add_subscript_info PARAMS ((dw_die_ref, tree));
static void add_byte_size_attribute PARAMS ((dw_die_ref, tree));
static void add_bit_offset_attribute PARAMS ((dw_die_ref, tree));
static void add_bit_size_attribute PARAMS ((dw_die_ref, tree));
static void add_prototyped_attribute PARAMS ((dw_die_ref, tree));
static void add_abstract_origin_attribute PARAMS ((dw_die_ref, tree));
static void add_pure_or_virtual_attribute PARAMS ((dw_die_ref, tree));
static void add_src_coords_attributes PARAMS ((dw_die_ref, tree));
static void add_name_and_src_coords_attributes PARAMS ((dw_die_ref, tree));
static void push_decl_scope PARAMS ((tree));
static void pop_decl_scope PARAMS ((void));
static dw_die_ref scope_die_for PARAMS ((tree, dw_die_ref));
static inline int local_scope_p PARAMS ((dw_die_ref));
static inline int class_scope_p PARAMS ((dw_die_ref));
static void add_type_attribute PARAMS ((dw_die_ref, tree, int, int,
dw_die_ref));
static const char *type_tag PARAMS ((tree));
static tree member_declared_type PARAMS ((tree));
#if 0
static const char *decl_start_label PARAMS ((tree));
#endif
static void gen_array_type_die PARAMS ((tree, dw_die_ref));
static void gen_set_type_die PARAMS ((tree, dw_die_ref));
#if 0
static void gen_entry_point_die PARAMS ((tree, dw_die_ref));
#endif
static void gen_inlined_enumeration_type_die PARAMS ((tree, dw_die_ref));
static void gen_inlined_structure_type_die PARAMS ((tree, dw_die_ref));
static void gen_inlined_union_type_die PARAMS ((tree, dw_die_ref));
static void gen_enumeration_type_die PARAMS ((tree, dw_die_ref));
static dw_die_ref gen_formal_parameter_die PARAMS ((tree, dw_die_ref));
static void gen_unspecified_parameters_die PARAMS ((tree, dw_die_ref));
static void gen_formal_types_die PARAMS ((tree, dw_die_ref));
static void gen_subprogram_die PARAMS ((tree, dw_die_ref));
static void gen_variable_die PARAMS ((tree, dw_die_ref));
static void gen_label_die PARAMS ((tree, dw_die_ref));
static void gen_lexical_block_die PARAMS ((tree, dw_die_ref, int));
static void gen_inlined_subroutine_die PARAMS ((tree, dw_die_ref, int));
static void gen_field_die PARAMS ((tree, dw_die_ref));
static void gen_ptr_to_mbr_type_die PARAMS ((tree, dw_die_ref));
static dw_die_ref gen_compile_unit_die PARAMS ((const char *));
static void gen_string_type_die PARAMS ((tree, dw_die_ref));
static void gen_inheritance_die PARAMS ((tree, dw_die_ref));
static void gen_member_die PARAMS ((tree, dw_die_ref));
static void gen_struct_or_union_type_die PARAMS ((tree, dw_die_ref));
static void gen_subroutine_type_die PARAMS ((tree, dw_die_ref));
static void gen_typedef_die PARAMS ((tree, dw_die_ref));
static void gen_type_die PARAMS ((tree, dw_die_ref));
static void gen_tagged_type_instantiation_die PARAMS ((tree, dw_die_ref));
static void gen_block_die PARAMS ((tree, dw_die_ref, int));
static void decls_for_scope PARAMS ((tree, dw_die_ref, int));
static int is_redundant_typedef PARAMS ((tree));
static void gen_decl_die PARAMS ((tree, dw_die_ref));
static unsigned lookup_filename PARAMS ((const char *));
static void init_file_table PARAMS ((void));
static void retry_incomplete_types PARAMS ((void));
static void gen_type_die_for_member PARAMS ((tree, tree, dw_die_ref));
static void splice_child_die PARAMS ((dw_die_ref, dw_die_ref));
static int file_info_cmp PARAMS ((const void *, const void *));
static dw_loc_list_ref new_loc_list PARAMS ((dw_loc_descr_ref,
const char *, const char *,
const char *, unsigned));
static void add_loc_descr_to_loc_list PARAMS ((dw_loc_list_ref *,
dw_loc_descr_ref,
const char *, const char *, const char *));
static void output_loc_list PARAMS ((dw_loc_list_ref));
static char *gen_internal_sym PARAMS ((const char *));
static void mark_limbo_die_list PARAMS ((void *));
#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
#ifdef HAVE_GAS_SHF_MERGE
#define DEBUG_STR_SECTION_FLAGS \
(SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1)
#else
#define DEBUG_STR_SECTION_FLAGS SECTION_DEBUG
#endif
#ifndef TEXT_SECTION_LABEL
#define TEXT_SECTION_LABEL "Ltext"
#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 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 DATA_END_LABEL
#define DATA_END_LABEL "Ledata"
#endif
#ifndef BSS_END_LABEL
#define BSS_END_LABEL "Lebss"
#endif
#ifndef BLOCK_BEGIN_LABEL
#define BLOCK_BEGIN_LABEL "LBB"
#endif
#ifndef BLOCK_END_LABEL
#define BLOCK_END_LABEL "LBE"
#endif
#ifndef BODY_BEGIN_LABEL
#define BODY_BEGIN_LABEL "Lbb"
#endif
#ifndef BODY_END_LABEL
#define BODY_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) PARAMS ((const char *));
void
dwarf2out_set_demangle_name_func (func)
const char *(*func) PARAMS ((const char *));
{
demangle_name_func = func;
}
static inline int
is_pseudo_reg (rtl)
rtx rtl;
{
return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
|| (GET_CODE (rtl) == SUBREG
&& REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
}
static inline tree
type_main_variant (type)
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 (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 (tag)
unsigned 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_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_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";
default:
return "DW_TAG_<unknown>";
}
}
static const char *
dwarf_attr_name (attr)
unsigned 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_VMS_rtnbeg_pd_address:
return "DW_AT_VMS_rtnbeg_pd_address";
default:
return "DW_AT_<unknown>";
}
}
static const char *
dwarf_form_name (form)
unsigned 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>";
}
}
#if 0
static const char *
dwarf_type_encoding_name (enc)
unsigned enc;
{
switch (enc)
{
case DW_ATE_address:
return "DW_ATE_address";
case DW_ATE_boolean:
return "DW_ATE_boolean";
case DW_ATE_complex_float:
return "DW_ATE_complex_float";
case DW_ATE_float:
return "DW_ATE_float";
case DW_ATE_signed:
return "DW_ATE_signed";
case DW_ATE_signed_char:
return "DW_ATE_signed_char";
case DW_ATE_unsigned:
return "DW_ATE_unsigned";
case DW_ATE_unsigned_char:
return "DW_ATE_unsigned_char";
default:
return "DW_ATE_<unknown>";
}
}
#endif
static tree
decl_ultimate_origin (decl)
tree decl;
{
if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
return NULL_TREE;
#ifdef ENABLE_CHECKING
if (DECL_FROM_INLINE (DECL_ORIGIN (decl)))
abort ();
#endif
return DECL_ABSTRACT_ORIGIN (decl);
}
static tree
block_ultimate_origin (block)
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);
return ret_val;
}
}
static tree
decl_class_context (decl)
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 (die, attr)
dw_die_ref die;
dw_attr_ref attr;
{
if (die != NULL && attr != NULL)
{
attr->dw_attr_next = die->die_attr;
die->die_attr = attr;
}
}
static inline dw_val_class
AT_class (a)
dw_attr_ref a;
{
return a->dw_attr_val.val_class;
}
static inline void
add_AT_flag (die, attr_kind, flag)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned flag;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_flag)
return a->dw_attr_val.v.val_flag;
abort ();
}
static inline void
add_AT_int (die, attr_kind, int_val)
dw_die_ref die;
enum dwarf_attribute attr_kind;
long int int_val;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 long int
AT_int (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_const)
return a->dw_attr_val.v.val_int;
abort ();
}
static inline void
add_AT_unsigned (die, attr_kind, unsigned_val)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned long unsigned_val;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 long
AT_unsigned (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_unsigned_const)
return a->dw_attr_val.v.val_unsigned;
abort ();
}
static inline void
add_AT_long_long (die, attr_kind, val_hi, val_low)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned long val_hi;
unsigned long val_low;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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_float (die, attr_kind, length, array)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned length;
long *array;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
attr->dw_attr_val.val_class = dw_val_class_float;
attr->dw_attr_val.v.val_float.length = length;
attr->dw_attr_val.v.val_float.array = array;
add_dwarf_attr (die, attr);
}
static inline void
add_AT_string (die, attr_kind, str)
dw_die_ref die;
enum dwarf_attribute attr_kind;
const char *str;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
struct indirect_string_node *node;
if (! debug_str_hash)
{
debug_str_hash = ht_create (10);
debug_str_hash->alloc_node = indirect_string_alloc;
}
node = (struct indirect_string_node *)
ht_lookup (debug_str_hash, (const unsigned char *) str,
strlen (str), HT_ALLOC);
node->refcount++;
attr->dw_attr_next = NULL;
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 (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_str)
return (const char *) HT_STR (&a->dw_attr_val.v.val_str->id);
abort ();
}
static int
AT_string_form (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_str)
{
struct indirect_string_node *node;
unsigned int len;
extern int const_labelno;
char label[32];
node = a->dw_attr_val.v.val_str;
if (node->form)
return node->form;
len = HT_LEN (&node->id) + 1;
if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
return node->form = DW_FORM_string;
if ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0
&& (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
return node->form = DW_FORM_string;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
++const_labelno;
node->label = xstrdup (label);
return node->form = DW_FORM_strp;
}
abort ();
}
static inline void
add_AT_die_ref (die, attr_kind, targ_die)
dw_die_ref die;
enum dwarf_attribute attr_kind;
dw_die_ref targ_die;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 dw_die_ref
AT_ref (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_die_ref)
return a->dw_attr_val.v.val_die_ref.die;
abort ();
}
static inline int
AT_ref_external (a)
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 (a, i)
dw_attr_ref a;
int i;
{
if (a && AT_class (a) == dw_val_class_die_ref)
a->dw_attr_val.v.val_die_ref.external = i;
else
abort ();
}
static inline void
add_AT_fde_ref (die, attr_kind, targ_fde)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned targ_fde;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 (die, attr_kind, loc)
dw_die_ref die;
enum dwarf_attribute attr_kind;
dw_loc_descr_ref loc;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_loc)
return a->dw_attr_val.v.val_loc;
abort ();
}
static inline void
add_AT_loc_list (die, attr_kind, loc_list)
dw_die_ref die;
enum dwarf_attribute attr_kind;
dw_loc_list_ref loc_list;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 = 1;
}
static inline dw_loc_list_ref
AT_loc_list (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_loc_list)
return a->dw_attr_val.v.val_loc_list;
abort ();
}
static inline void
add_AT_addr (die, attr_kind, addr)
dw_die_ref die;
enum dwarf_attribute attr_kind;
rtx addr;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 (a)
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_addr)
return a->dw_attr_val.v.val_addr;
abort ();
}
static inline void
add_AT_lbl_id (die, attr_kind, lbl_id)
dw_die_ref die;
enum dwarf_attribute attr_kind;
const char *lbl_id;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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_lbl_offset (die, attr_kind, label)
dw_die_ref die;
enum dwarf_attribute attr_kind;
const char *label;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
attr->dw_attr_val.val_class = dw_val_class_lbl_offset;
attr->dw_attr_val.v.val_lbl_id = xstrdup (label);
add_dwarf_attr (die, attr);
}
static inline void
add_AT_offset (die, attr_kind, offset)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned long offset;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 (die, attr_kind, offset)
dw_die_ref die;
enum dwarf_attribute attr_kind;
unsigned long offset;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
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 (a)
dw_attr_ref a;
{
if (a && (AT_class (a) == dw_val_class_lbl_id
|| AT_class (a) == dw_val_class_lbl_offset))
return a->dw_attr_val.v.val_lbl_id;
abort ();
}
static inline dw_attr_ref
get_AT (die, attr_kind)
dw_die_ref die;
enum dwarf_attribute attr_kind;
{
dw_attr_ref a;
dw_die_ref spec = NULL;
if (die != NULL)
{
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
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 (die)
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 (die)
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 (die, attr_kind)
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 (die, attr_kind)
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 (die, attr_kind)
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 (die, attr_kind)
dw_die_ref die;
enum dwarf_attribute attr_kind;
{
dw_attr_ref a = get_AT (die, attr_kind);
return a ? AT_ref (a) : NULL;
}
static inline int
is_c_family ()
{
unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_C || lang == DW_LANG_C89
|| lang == DW_LANG_C_plus_plus);
}
static inline int
is_cxx ()
{
return (get_AT_unsigned (comp_unit_die, DW_AT_language)
== DW_LANG_C_plus_plus);
}
static inline int
is_fortran ()
{
unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
}
static inline int
is_java ()
{
unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_Java);
}
static inline void free_AT PARAMS ((dw_attr_ref));
static inline void
free_AT (a)
dw_attr_ref a;
{
switch (AT_class (a))
{
case dw_val_class_str:
if (a->dw_attr_val.v.val_str->refcount)
a->dw_attr_val.v.val_str->refcount--;
break;
case dw_val_class_lbl_id:
case dw_val_class_lbl_offset:
free (a->dw_attr_val.v.val_lbl_id);
break;
case dw_val_class_float:
free (a->dw_attr_val.v.val_float.array);
break;
default:
break;
}
free (a);
}
static void
remove_AT (die, attr_kind)
dw_die_ref die;
enum dwarf_attribute attr_kind;
{
dw_attr_ref *p;
dw_attr_ref removed = NULL;
if (die != NULL)
{
for (p = &(die->die_attr); *p; p = &((*p)->dw_attr_next))
if ((*p)->dw_attr == attr_kind)
{
removed = *p;
*p = (*p)->dw_attr_next;
break;
}
if (removed != 0)
free_AT (removed);
}
}
static inline void
free_die (die)
dw_die_ref die;
{
remove_children (die);
free (die);
}
static void
remove_children (die)
dw_die_ref die;
{
dw_die_ref child_die = die->die_child;
die->die_child = NULL;
while (child_die != NULL)
{
dw_die_ref tmp_die = child_die;
dw_attr_ref a;
child_die = child_die->die_sib;
for (a = tmp_die->die_attr; a != NULL;)
{
dw_attr_ref tmp_a = a;
a = a->dw_attr_next;
free_AT (tmp_a);
}
free_die (tmp_die);
}
}
static inline void
add_child_die (die, child_die)
dw_die_ref die;
dw_die_ref child_die;
{
if (die != NULL && child_die != NULL)
{
if (die == child_die)
abort ();
child_die->die_parent = die;
child_die->die_sib = die->die_child;
die->die_child = child_die;
}
}
static void
splice_child_die (parent, child)
dw_die_ref parent, 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;
}
if (child->die_parent != parent
&& child->die_parent != get_AT_ref (parent, DW_AT_specification))
abort ();
for (p = &(child->die_parent->die_child); *p; p = &((*p)->die_sib))
if (*p == child)
{
*p = child->die_sib;
break;
}
child->die_sib = parent->die_child;
parent->die_child = child;
}
static inline dw_die_ref
new_die (tag_value, parent_die, t)
enum dwarf_tag tag_value;
dw_die_ref parent_die;
tree t;
{
dw_die_ref die = (dw_die_ref) xcalloc (1, 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 = (limbo_die_node *) xmalloc (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 (type)
tree type;
{
if (TREE_CODE (type) == VECTOR_TYPE)
type = TYPE_DEBUG_REPRESENTATION_TYPE (type);
return (dw_die_ref) TYPE_SYMTAB_POINTER (type);
}
static inline void
equate_type_number_to_die (type, type_die)
tree type;
dw_die_ref type_die;
{
TYPE_SYMTAB_POINTER (type) = (char *) type_die;
}
static inline dw_die_ref
lookup_decl_die (decl)
tree decl;
{
unsigned decl_id = DECL_UID (decl);
return (decl_id < decl_die_table_in_use ? decl_die_table[decl_id] : NULL);
}
static void
equate_decl_number_to_die (decl, decl_die)
tree decl;
dw_die_ref decl_die;
{
unsigned int decl_id = DECL_UID (decl);
unsigned int num_allocated;
if (decl_id >= decl_die_table_allocated)
{
num_allocated
= ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1)
/ DECL_DIE_TABLE_INCREMENT)
* DECL_DIE_TABLE_INCREMENT;
decl_die_table
= (dw_die_ref *) xrealloc (decl_die_table,
sizeof (dw_die_ref) * num_allocated);
memset ((char *) &decl_die_table[decl_die_table_allocated], 0,
(num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
decl_die_table_allocated = num_allocated;
}
if (decl_id >= decl_die_table_in_use)
decl_die_table_in_use = (decl_id + 1);
decl_die_table[decl_id] = decl_die;
}
static int print_indent;
static inline void
print_spaces (outfile)
FILE *outfile;
{
fprintf (outfile, "%*s", print_indent, "");
}
static void
print_die (die, outfile)
dw_die_ref die;
FILE *outfile;
{
dw_attr_ref a;
dw_die_ref c;
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 (a = die->die_attr; a != NULL; a = a->dw_attr_next)
{
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, "%ld", AT_int (a));
break;
case dw_val_class_unsigned_const:
fprintf (outfile, "%lu", 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_float:
fprintf (outfile, "floating-point 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_lbl_offset:
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;
default:
break;
}
fprintf (outfile, "\n");
}
if (die->die_child != NULL)
{
print_indent += 4;
for (c = die->die_child; c != NULL; c = c->die_sib)
print_die (c, outfile);
print_indent -= 4;
}
if (print_indent == 0)
fprintf (outfile, "\n");
}
static void
print_dwarf_line_table (outfile)
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: ", i);
fprintf (outfile, "%-20s", file_table.table[line_info->dw_file_num]);
fprintf (outfile, "%6ld", line_info->dw_line_num);
fprintf (outfile, "\n");
}
fprintf (outfile, "\n\n");
}
void
debug_dwarf_die (die)
dw_die_ref die;
{
print_die (die, stderr);
}
void
debug_dwarf ()
{
print_indent = 0;
print_die (comp_unit_die, stderr);
if (! DWARF2_ASM_LINE_DEBUG_INFO)
print_dwarf_line_table (stderr);
}
static void
reverse_die_lists (die)
dw_die_ref die;
{
dw_die_ref c, cp, cn;
dw_attr_ref a, ap, an;
for (a = die->die_attr, ap = 0; a; a = an)
{
an = a->dw_attr_next;
a->dw_attr_next = ap;
ap = a;
}
die->die_attr = ap;
for (c = die->die_child, cp = 0; c; c = cn)
{
cn = c->die_sib;
c->die_sib = cp;
cp = c;
}
die->die_child = cp;
}
static void
reverse_all_dies (die)
dw_die_ref die;
{
dw_die_ref c;
reverse_die_lists (die);
for (c = die->die_child; c; c = c->die_sib)
reverse_all_dies (c);
}
static dw_die_ref
push_new_compile_unit (old_unit, bincl_die)
dw_die_ref old_unit, 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 (old_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 (loc, ctx)
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 (at, ctx)
dw_attr_ref at;
struct md5_ctx *ctx;
{
dw_loc_descr_ref loc;
rtx r;
CHECKSUM (at->dw_attr);
if (at->dw_attr == DW_AT_decl_file
|| 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_float:
CHECKSUM (at->dw_attr_val.v.val_float);
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);
switch (GET_CODE (r))
{
case SYMBOL_REF:
CHECKSUM_STRING (XSTR (r, 0));
break;
default:
abort ();
}
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:
if (AT_ref (at)->die_offset)
CHECKSUM (AT_ref (at)->die_offset);
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
case dw_val_class_lbl_offset:
break;
default:
break;
}
}
static void
die_checksum (die, ctx)
dw_die_ref die;
struct md5_ctx *ctx;
{
dw_die_ref c;
dw_attr_ref a;
CHECKSUM (die->die_tag);
for (a = die->die_attr; a; a = a->dw_attr_next)
attr_checksum (a, ctx);
for (c = die->die_child; c; c = c->die_sib)
die_checksum (c, ctx);
}
#undef CHECKSUM
#undef CHECKSUM_STRING
static char *comdat_symbol_id;
static unsigned int comdat_symbol_number;
static void
compute_section_prefix (unit_die)
dw_die_ref unit_die;
{
const char *base = lbasename (get_AT_string (unit_die, DW_AT_name));
char *name = (char *) alloca (strlen (base) + 64);
char *p;
int i;
unsigned char checksum[16];
struct md5_ctx ctx;
md5_init_ctx (&ctx);
die_checksum (unit_die, &ctx);
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 (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:
return 1;
default:
return 0;
}
}
static int
is_comdat_die (c)
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 (c)
dw_die_ref c;
{
return (is_type_die (c)
|| (get_AT (c, DW_AT_declaration)
&& !get_AT (c, DW_AT_specification)));
}
static char *
gen_internal_sym (prefix)
const char *prefix;
{
char buf[256];
static int label_num;
ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
return xstrdup (buf);
}
static void
assign_symbol_names (die)
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 (c = die->die_child; c != NULL; c = c->die_sib)
assign_symbol_names (c);
}
static void
break_out_includes (die)
dw_die_ref die;
{
dw_die_ref *ptr;
dw_die_ref unit = NULL;
limbo_die_node *node;
for (ptr = &(die->die_child); *ptr; )
{
dw_die_ref c = *ptr;
if (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
|| (unit && is_comdat_die (c)))
{
*ptr = c->die_sib;
if (c->die_tag == DW_TAG_GNU_BINCL)
{
unit = push_new_compile_unit (unit, c);
free_die (c);
}
else if (c->die_tag == DW_TAG_GNU_EINCL)
{
unit = pop_compile_unit (unit);
free_die (c);
}
else
add_child_die (unit, c);
}
else
{
ptr = &(c->die_sib);
continue;
}
}
#if 0
if (unit != NULL)
abort ();
#endif
assign_symbol_names (die);
for (node = limbo_die_list; node; node = node->next)
{
compute_section_prefix (node->die);
assign_symbol_names (node->die);
}
}
static void
add_sibling_attributes (die)
dw_die_ref die;
{
dw_die_ref c;
if (die->die_tag != DW_TAG_compile_unit
&& die->die_sib && die->die_child != NULL)
add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
for (c = die->die_child; c != NULL; c = c->die_sib)
add_sibling_attributes (c);
}
static void
output_location_lists (die)
dw_die_ref die;
{
dw_die_ref c;
dw_attr_ref d_attr;
for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
if (AT_class (d_attr) == dw_val_class_loc_list)
output_loc_list (AT_loc_list (d_attr));
for (c = die->die_child; c != NULL; c = c->die_sib)
output_location_lists (c);
}
static void
build_abbrev_table (die)
dw_die_ref die;
{
unsigned long abbrev_id;
unsigned int n_alloc;
dw_die_ref c;
dw_attr_ref d_attr, a_attr;
for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
if (AT_class (d_attr) == dw_val_class_die_ref
&& AT_ref (d_attr)->die_mark == 0)
{
if (AT_ref (d_attr)->die_symbol == 0)
abort ();
set_AT_ref_external (d_attr, 1);
}
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
if (abbrev->die_tag == die->die_tag)
{
if ((abbrev->die_child != NULL) == (die->die_child != NULL))
{
a_attr = abbrev->die_attr;
d_attr = die->die_attr;
while (a_attr != NULL && d_attr != NULL)
{
if ((a_attr->dw_attr != d_attr->dw_attr)
|| (value_format (a_attr) != value_format (d_attr)))
break;
a_attr = a_attr->dw_attr_next;
d_attr = d_attr->dw_attr_next;
}
if (a_attr == NULL && d_attr == NULL)
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
= (dw_die_ref *) xrealloc (abbrev_die_table,
sizeof (dw_die_ref) * n_alloc);
memset ((char *) &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 (c = die->die_child; c != NULL; c = c->die_sib)
build_abbrev_table (c);
}
static int
constant_size (value)
long unsigned 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 (die)
dw_die_ref die;
{
unsigned long size = 0;
dw_attr_ref a;
size += size_of_uleb128 (die->die_abbrev);
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
{
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_float:
size += 1 + a->dw_attr_val.v.val_float.length * 4;
break;
case dw_val_class_flag:
size += 1;
break;
case dw_val_class_die_ref:
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_lbl_offset:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
if (AT_string_form (a) == DW_FORM_strp)
size += DWARF_OFFSET_SIZE;
else
size += HT_LEN (&a->dw_attr_val.v.val_str->id) + 1;
break;
default:
abort ();
}
}
return size;
}
static void
calc_die_sizes (die)
dw_die_ref die;
{
dw_die_ref c;
die->die_offset = next_die_offset;
next_die_offset += size_of_die (die);
for (c = die->die_child; c != NULL; c = c->die_sib)
calc_die_sizes (c);
if (die->die_child != NULL)
next_die_offset += 1;
}
static void
mark_dies (die)
dw_die_ref die;
{
dw_die_ref c;
die->die_mark = 1;
for (c = die->die_child; c; c = c->die_sib)
mark_dies (c);
}
static void
unmark_dies (die)
dw_die_ref die;
{
dw_die_ref c;
die->die_mark = 0;
for (c = die->die_child; c; c = c->die_sib)
unmark_dies (c);
}
static unsigned long
size_of_pubnames ()
{
unsigned long size;
unsigned i;
size = DWARF_PUBNAMES_HEADER_SIZE;
for (i = 0; i < pubname_table_in_use; i++)
{
pubname_ref p = &pubname_table[i];
size += DWARF_OFFSET_SIZE + strlen (p->name) + 1;
}
size += DWARF_OFFSET_SIZE;
return size;
}
static unsigned long
size_of_aranges ()
{
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 (a)
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:
if (DWARF_OFFSET_SIZE == 4)
return DW_FORM_data4;
if (DWARF_OFFSET_SIZE == 8)
return DW_FORM_data8;
abort ();
case dw_val_class_loc_list:
return DW_FORM_data4;
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:
abort ();
}
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:
abort ();
}
case dw_val_class_long_long:
return DW_FORM_block1;
case dw_val_class_float:
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_lbl_offset:
return DW_FORM_data;
case dw_val_class_str:
return AT_string_form (a);
default:
abort ();
}
}
static void
output_value_format (a)
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 ()
{
unsigned long abbrev_id;
dw_attr_ref a_attr;
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
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 (a_attr = abbrev->die_attr; a_attr != NULL;
a_attr = a_attr->dw_attr_next)
{
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 (die)
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)
ASM_GLOBALIZE_LABEL (asm_out_file, sym);
ASM_OUTPUT_LABEL (asm_out_file, sym);
}
static inline dw_loc_list_ref
new_loc_list (expr, begin, end, section, gensym)
dw_loc_descr_ref expr;
const char *begin;
const char *end;
const char *section;
unsigned gensym;
{
dw_loc_list_ref retlist
= (dw_loc_list_ref) xcalloc (1, 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 (list_head, descr, begin, end, section)
dw_loc_list_ref *list_head;
dw_loc_descr_ref descr;
const char *begin;
const char *end;
const char *section;
{
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
output_loc_list (list_head)
dw_loc_list_ref list_head;
{
dw_loc_list_ref curr = list_head;
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
if (strcmp (curr->section, ".text") == 0)
{
dw2_asm_output_data (DWARF2_ADDR_SIZE, ~(unsigned HOST_WIDE_INT) 0,
"Location list base address specifier fake entry");
dw2_asm_output_offset (DWARF2_ADDR_SIZE, curr->section,
"Location list base address specifier base");
}
for (curr = list_head; curr != NULL; curr=curr->dw_loc_next)
{
unsigned long size;
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);
size = size_of_locs (curr->expr);
if (size > 0xffff)
abort ();
dw2_asm_output_data (2, size, "%s", "Location expression size");
output_loc_sequence (curr->expr);
}
dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
"Location list terminator begin (%s)",
list_head->ll_symbol);
dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
"Location list terminator end (%s)",
list_head->ll_symbol);
}
static void
output_die (die)
dw_die_ref die;
{
dw_attr_ref a;
dw_die_ref c;
unsigned long size;
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 (a = die->die_attr; a != NULL; a = a->dw_attr_next)
{
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, "+0x%lx", a->dw_attr_val.v.val_offset);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
"%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_float:
{
unsigned int i;
dw2_asm_output_data (1, a->dw_attr_val.v.val_float.length * 4,
"%s", name);
for (i = 0; i < a->dw_attr_val.v.val_float.length; i++)
dw2_asm_output_data (4, a->dw_attr_val.v.val_float.array[i],
"fp 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;
if (sym == 0)
abort ();
dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym,
loc_section_label, "%s", name);
}
break;
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
char *sym = AT_ref (a)->die_symbol;
if (sym == 0)
abort ();
dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, "%s", name);
}
else if (AT_ref (a)->die_offset == 0)
abort ();
else
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, "%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_lbl_offset:
dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a), "%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,
"%s: \"%s\"", name, AT_string (a));
else
dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
break;
default:
abort ();
}
}
for (c = die->die_child; c != NULL; c = c->die_sib)
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 ()
{
dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset - DWARF_OFFSET_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,
"Offset Into Abbrev. Section");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
}
static void
output_comp_unit (die)
dw_die_ref die;
{
const char *secname;
mark_dies (die);
build_abbrev_table (die);
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
calc_die_sizes (die);
if (die->die_symbol)
{
char *tmp = (char *) alloca (strlen (die->die_symbol) + 24);
sprintf (tmp, ".gnu.linkonce.wi.%s", die->die_symbol);
secname = tmp;
die->die_symbol = NULL;
}
else
secname = (const char *) DEBUG_INFO_SECTION;
named_section_flags (secname, SECTION_DEBUG);
output_compilation_unit_header ();
output_die (die);
if (die->die_symbol)
unmark_dies (die);
}
static const char *
dwarf2_name (decl, scope)
tree decl;
int scope;
{
return (*decl_printable_name) (decl, scope ? 1 : 0);
}
static void
add_pubname (decl, die)
tree decl;
dw_die_ref die;
{
pubname_ref p;
if (! TREE_PUBLIC (decl))
return;
if (pubname_table_in_use == pubname_table_allocated)
{
pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
pubname_table
= (pubname_ref) xrealloc (pubname_table,
(pubname_table_allocated
* sizeof (pubname_entry)));
}
p = &pubname_table[pubname_table_in_use++];
p->die = die;
p->name = xstrdup (dwarf2_name (decl, 1));
}
static void
output_pubnames ()
{
unsigned i;
unsigned long pubnames_length = size_of_pubnames ();
dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
"Length of Public Names Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
"Offset of Compilation Unit Info");
dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
"Compilation Unit Length");
for (i = 0; i < pubname_table_in_use; i++)
{
pubname_ref pub = &pubname_table[i];
if (pub->die->die_mark == 0)
abort ();
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 (decl, die)
tree decl;
dw_die_ref die;
{
if (! DECL_SECTION_NAME (decl))
return;
if (arange_table_in_use == arange_table_allocated)
{
arange_table_allocated += ARANGE_TABLE_INCREMENT;
arange_table = (dw_die_ref *)
xrealloc (arange_table, arange_table_allocated * sizeof (dw_die_ref));
}
arange_table[arange_table_in_use++] = die;
}
static void
output_aranges ()
{
unsigned i;
unsigned long aranges_length = size_of_aranges ();
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,
"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");
for (i = 0; i < arange_table_in_use; i++)
{
dw_die_ref die = arange_table[i];
if (die->die_mark == 0)
abort ();
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;
if (! a || AT_class (a) != dw_val_class_loc)
abort ();
loc = AT_loc (a);
if (loc->dw_loc_opc != DW_OP_addr)
abort ();
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 (block)
tree block;
{
unsigned int in_use = ranges_table_in_use;
if (in_use == ranges_table_allocated)
{
ranges_table_allocated += RANGES_TABLE_INCREMENT;
ranges_table = (dw_ranges_ref)
xrealloc (ranges_table, (ranges_table_allocated
* sizeof (struct dw_ranges_struct)));
}
ranges_table[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 ()
{
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 (separate_line_info_table_in_use == 0)
{
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
{
char *path;
char *fname;
int length;
int file_idx;
int dir_idx;
};
struct dir_info
{
char *path;
int length;
int prefix;
int count;
int dir_idx;
int used;
};
static int
file_info_cmp (p1, p2)
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;
}
}
static void
output_file_names ()
{
struct file_info *files;
struct dir_info *dirs;
int *saved;
int *savehere;
int *backmap;
int ndirs;
int idx_offset;
int i;
int idx;
files = (struct file_info *) alloca (file_table.in_use
* sizeof (struct file_info));
dirs = (struct dir_info *) alloca (file_table.in_use
* sizeof (struct dir_info));
for (i = 1; i < (int) file_table.in_use; i++)
{
char *f;
f = file_table.table[i];
while (f[0] == '.' && f[1] == '/')
f += 2;
files[i].path = f;
files[i].length = strlen (f);
files[i].file_idx = i;
f = strrchr (f, '/');
files[i].fname = f == NULL ? files[i].path : f + 1;
}
qsort (files + 1, file_table.in_use - 1, sizeof (files[0]), file_info_cmp);
dirs[0].path = files[1].path;
dirs[0].length = files[1].fname - files[1].path;
dirs[0].prefix = -1;
dirs[0].count = 1;
dirs[0].dir_idx = 0;
dirs[0].used = 0;
files[1].dir_idx = 0;
ndirs = 1;
for (i = 2; i < (int) file_table.in_use; 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;
dirs[ndirs].used = 0;
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 = (int *) alloca (ndirs * sizeof (int));
savehere = (int *) 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 != i)
k = dirs[k].prefix;
if (k == 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;
}
}
}
backmap = (int *) alloca (file_table.in_use * sizeof (int));
for (i = 1; i < (int) file_table.in_use; i++)
{
backmap[files[i].file_idx] = i;
dirs[dirs[files[i].dir_idx].dir_idx].used = 1;
}
idx = 1;
idx_offset = dirs[0].length > 0 ? 1 : 0;
for (i = 1 - idx_offset; i < ndirs; i++)
if (dirs[i].used != 0)
{
dirs[i].used = idx++;
dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
"Directory Entry: 0x%x", dirs[i].used);
}
dw2_asm_output_data (1, 0, "End directory table");
if (idx_offset == 0)
dirs[0].used = 0;
for (i = 1; i < (int) file_table.in_use; i++)
{
int file_idx = backmap[i];
int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
"File Entry: 0x%x", i);
dw2_asm_output_data_uleb128 (dirs[dir_idx].used, 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 ()
{
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);
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;
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, "(\"%s\")",
file_table.table[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, "(\"%s\")",
file_table.table[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 (type)
tree type;
{
dw_die_ref base_type_result;
const char *type_name;
enum dwarf_type encoding;
tree name = TYPE_NAME (type);
if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
return 0;
if (name)
{
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
type_name = IDENTIFIER_POINTER (name);
}
else
type_name = "__unknown__";
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
&& (type == char_type_node
|| ! strcmp (type_name, "signed char")
|| ! strcmp (type_name, "unsigned char"))))
{
if (TREE_UNSIGNED (type))
encoding = DW_ATE_unsigned;
else
encoding = DW_ATE_signed;
break;
}
case CHAR_TYPE:
if (TREE_UNSIGNED (type))
encoding = DW_ATE_unsigned_char;
else
encoding = DW_ATE_signed_char;
break;
case REAL_TYPE:
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:
abort ();
}
base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
if (demangle_name_func)
type_name = (*demangle_name_func) (type_name);
add_AT_string (base_type_result, DW_AT_name, type_name);
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 (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 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 (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:
case CHAR_TYPE:
return 1;
case SET_TYPE:
case ARRAY_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
case ENUMERAL_TYPE:
case FUNCTION_TYPE:
case METHOD_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
case FILE_TYPE:
case OFFSET_TYPE:
case LANG_TYPE:
case VECTOR_TYPE:
return 0;
default:
abort ();
}
return 0;
}
static dw_die_ref
modified_type_die (type, is_const_type, is_volatile_type, context_die)
tree type;
int is_const_type;
int is_volatile_type;
dw_die_ref context_die;
{
enum tree_code code = TREE_CODE (type);
dw_die_ref mod_type_die = NULL;
dw_die_ref sub_die = NULL;
tree item_type = NULL;
if (code != ERROR_MARK)
{
tree qualified_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;
}
if (qualified_type && TYPE_NAME (qualified_type)
&& TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (TYPE_NAME (qualified_type)))
{
tree type_name = TYPE_NAME (qualified_type);
tree dtype = TREE_TYPE (type_name);
if (qualified_type == dtype)
{
gen_type_die (qualified_type, context_die);
mod_type_die = lookup_type_die (qualified_type);
}
else if (is_const_type < TYPE_READONLY (dtype)
|| is_volatile_type < TYPE_VOLATILE (dtype))
mod_type_die
= modified_type_die (DECL_ORIGINAL_TYPE (type_name),
is_const_type, is_volatile_type,
context_die);
}
if (mod_type_die)
;
else 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)
{
mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
#if 0
add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
#endif
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, PTR_SIZE);
#if 0
add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
#endif
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);
mod_type_die = lookup_type_die (type_main_variant (type));
if (mod_type_die == NULL)
abort ();
}
if (qualified_type)
type = qualified_type;
}
equate_type_number_to_die (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);
return mod_type_die;
}
static inline int
type_is_enum (type)
tree type;
{
return TREE_CODE (type) == ENUMERAL_TYPE;
}
static unsigned int
reg_number (rtl)
rtx rtl;
{
unsigned regno = REGNO (rtl);
if (regno >= FIRST_PSEUDO_REGISTER)
abort ();
return DBX_REGISTER_NUMBER (regno);
}
static dw_loc_descr_ref
reg_loc_descriptor (rtl)
rtx rtl;
{
dw_loc_descr_ref loc_result = NULL;
unsigned reg;
if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
return 0;
reg = reg_number (rtl);
if (reg <= 31)
loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
else
loc_result = new_loc_descr (DW_OP_regx, reg, 0);
return loc_result;
}
static dw_loc_descr_ref
int_loc_descriptor (i)
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 (reg, offset)
unsigned reg;
long int offset;
{
dw_loc_descr_ref loc_result;
unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed
? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM);
if (reg == fp_reg)
loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
else if (reg <= 31)
loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
else
loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
return loc_result;
}
static inline int
is_based_loc (rtl)
rtx rtl;
{
return (GET_CODE (rtl) == PLUS
&& ((GET_CODE (XEXP (rtl, 0)) == REG
&& REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
&& GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
}
static dw_loc_descr_ref
mem_loc_descriptor (rtl, mode)
rtx rtl;
enum machine_mode mode;
{
dw_loc_descr_ref mem_loc_result = NULL;
#ifdef ASM_SIMPLIFY_DWARF_ADDR
rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
#endif
switch (GET_CODE (rtl))
{
case POST_INC:
case POST_DEC:
case POST_MODIFY:
case SUBREG:
rtl = SUBREG_REG (rtl);
case REG:
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
mem_loc_result = based_loc_descr (reg_number (rtl), 0);
break;
case MEM:
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
if (mem_loc_result != 0)
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
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;
VARRAY_PUSH_RTX (used_rtx_varray, 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 (reg_number (XEXP (rtl, 0)),
INTVAL (XEXP (rtl, 1)));
else
{
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
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));
add_loc_descr (&mem_loc_result,
new_loc_descr (DW_OP_plus, 0, 0));
}
}
break;
case MULT:
{
dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode);
dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode);
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 (DW_OP_mul, 0, 0));
break;
}
case CONST_INT:
mem_loc_result = int_loc_descriptor (INTVAL (rtl));
break;
case ADDRESSOF:
if (GET_CODE (XEXP (rtl, 0)) == MEM)
return mem_loc_descriptor (XEXP (XEXP (rtl, 0), 0), mode);
else
return 0;
default:
abort ();
}
return mem_loc_result;
}
static dw_loc_descr_ref
concat_loc_descriptor (x0, x1)
rtx x0, x1;
{
dw_loc_descr_ref cc_loc_result = NULL;
dw_loc_descr_ref x0_ref = loc_descriptor (x0);
dw_loc_descr_ref x1_ref = loc_descriptor (x1);
if (x0_ref == 0 || x1_ref == 0)
return 0;
cc_loc_result = x0_ref;
add_loc_descr (&cc_loc_result,
new_loc_descr (DW_OP_piece,
GET_MODE_SIZE (GET_MODE (x0)), 0));
add_loc_descr (&cc_loc_result, x1_ref);
add_loc_descr (&cc_loc_result,
new_loc_descr (DW_OP_piece,
GET_MODE_SIZE (GET_MODE (x1)), 0));
return cc_loc_result;
}
static dw_loc_descr_ref
loc_descriptor (rtl)
rtx rtl;
{
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);
break;
case MEM:
loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
break;
case CONCAT:
loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
break;
default:
abort ();
}
return loc_result;
}
static dw_loc_descr_ref
loc_descriptor_from_tree (loc, addressp)
tree loc;
int addressp;
{
dw_loc_descr_ref ret, ret1;
int indirect_p = 0;
int unsignedp = TREE_UNSIGNED (TREE_TYPE (loc));
enum dwarf_location_atom op;
switch (TREE_CODE (loc))
{
case ERROR_MARK:
return 0;
case WITH_RECORD_EXPR:
case PLACEHOLDER_EXPR:
return 0;
case CALL_EXPR:
return 0;
case ADDR_EXPR:
for (loc = TREE_OPERAND (loc, 0);
TREE_CODE (loc) == CONVERT_EXPR || TREE_CODE (loc) == NOP_EXPR
|| TREE_CODE (loc) == NON_LVALUE_EXPR
|| TREE_CODE (loc) == VIEW_CONVERT_EXPR
|| TREE_CODE (loc) == SAVE_EXPR;
loc = TREE_OPERAND (loc, 0))
;
return (TREE_CODE (loc) == INDIRECT_REF
? loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp)
: 0);
case VAR_DECL:
case PARM_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
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;
indirect_p = 1;
}
else
{
enum machine_mode mode = GET_MODE (rtl);
if (GET_CODE (rtl) == MEM)
{
indirect_p = 1;
rtl = XEXP (rtl, 0);
}
ret = mem_loc_descriptor (rtl, mode);
}
}
break;
case INDIRECT_REF:
ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
indirect_p = 1;
break;
case COMPOUND_EXPR:
return loc_descriptor_from_tree (TREE_OPERAND (loc, 1), addressp);
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
return loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp);
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;
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep);
if (obj == loc)
return 0;
ret = loc_descriptor_from_tree (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 (offset, 0));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
if (!addressp)
indirect_p = 1;
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));
}
break;
}
case INTEGER_CST:
if (host_integerp (loc, 0))
ret = int_loc_descriptor (tree_low_cst (loc, 0));
else
return 0;
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 TRUNC_DIV_EXPR:
op = DW_OP_div;
goto do_binop;
case MINUS_EXPR:
op = DW_OP_minus;
goto do_binop;
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 = (unsignedp ? 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 (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 (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_le;
goto do_binop;
case GE_EXPR:
if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_ge;
goto do_binop;
case LT_EXPR:
if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
return 0;
op = DW_OP_lt;
goto do_binop;
case GT_EXPR:
if (TREE_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 (TREE_OPERAND (loc, 0), 0);
ret1 = loc_descriptor_from_tree (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 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
add_loc_descr (&ret, new_loc_descr (op, 0, 0));
break;
case MAX_EXPR:
loc = build (COND_EXPR, TREE_TYPE (loc),
build (LT_EXPR, 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 (TREE_OPERAND (loc, 1), 0);
dw_loc_descr_ref rhs
= loc_descriptor_from_tree (TREE_OPERAND (loc, 2), 0);
dw_loc_descr_ref bra_node, jump_node, tmp;
ret = loc_descriptor_from_tree (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;
default:
abort ();
}
if (addressp && indirect_p == 0)
return 0;
if (!addressp && indirect_p > 0)
{
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 HOST_WIDE_INT
ceiling (value, boundary)
HOST_WIDE_INT value;
unsigned int boundary;
{
return (((value + boundary - 1) / boundary) * boundary);
}
static inline tree
field_type (decl)
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 (type)
tree type;
{
return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
}
static inline unsigned
simple_decl_align_in_bits (decl)
tree decl;
{
return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
}
static inline unsigned HOST_WIDE_INT
simple_type_size_in_bits (type)
tree type;
{
if (TREE_CODE (type) == ERROR_MARK)
return BITS_PER_WORD;
else if (TYPE_SIZE (type) == NULL_TREE)
return 0;
else if (host_integerp (TYPE_SIZE (type), 1))
return tree_low_cst (TYPE_SIZE (type), 1);
else
return TYPE_ALIGN (type);
}
static HOST_WIDE_INT
field_byte_offset (decl)
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;
else if (TREE_CODE (decl) != FIELD_DECL)
abort ();
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 void
add_AT_location_description (die, attr_kind, rtl)
dw_die_ref die;
enum dwarf_attribute attr_kind;
rtx rtl;
{
dw_loc_descr_ref descr = loc_descriptor (rtl);
if (descr != 0)
add_AT_loc (die, attr_kind, descr);
}
static void
add_data_member_location_attribute (die, decl)
dw_die_ref die;
tree decl;
{
long offset;
dw_loc_descr_ref loc_descr = 0;
if (TREE_CODE (decl) == TREE_VEC)
{
if (TREE_VIA_VIRTUAL (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);
if (offset >= 0)
abort ();
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
add_const_value_attribute (die, rtl)
dw_die_ref die;
rtx rtl;
{
switch (GET_CODE (rtl))
{
case CONST_INT:
{
HOST_WIDE_INT val = INTVAL (rtl);
if (val < 0 && (long) val == val)
add_AT_int (die, DW_AT_const_value, (long) val);
else if ((unsigned long) val == (unsigned HOST_WIDE_INT) val)
add_AT_unsigned (die, DW_AT_const_value, (unsigned long) val);
else
{
#if HOST_BITS_PER_LONG * 2 == HOST_BITS_PER_WIDE_INT
add_AT_long_long (die, DW_AT_const_value,
val >> HOST_BITS_PER_LONG, val);
#else
abort ();
#endif
}
}
break;
case CONST_DOUBLE:
{
enum machine_mode mode = GET_MODE (rtl);
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
unsigned length = GET_MODE_SIZE (mode) / 4;
long *array = (long *) xmalloc (sizeof (long) * length);
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
switch (mode)
{
case SFmode:
REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]);
break;
case DFmode:
REAL_VALUE_TO_TARGET_DOUBLE (rv, array);
break;
case XFmode:
case TFmode:
REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array);
break;
default:
abort ();
}
add_AT_float (die, DW_AT_const_value, length, array);
}
else
{
if (HOST_BITS_PER_LONG != HOST_BITS_PER_WIDE_INT)
abort ();
add_AT_long_long (die, DW_AT_const_value,
CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
}
}
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);
VARRAY_PUSH_RTX (used_rtx_varray, rtl);
break;
case PLUS:
break;
default:
abort ();
}
}
static rtx
rtl_for_decl_location (decl)
tree decl;
{
rtx rtl;
rtl = DECL_RTL_IF_SET (decl);
if (! reload_completed)
{
if (rtl
&& (CONSTANT_P (rtl)
|| (GET_CODE (rtl) == MEM
&& CONSTANT_P (XEXP (rtl, 0)))))
{
#ifdef ASM_SIMPLIFY_DWARF_ADDR
rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
#endif
return rtl;
}
rtl = NULL_RTX;
}
else if (TREE_CODE (decl) == PARM_DECL)
{
if (rtl == NULL_RTX || is_pseudo_reg (rtl))
{
tree declared_type = type_main_variant (TREE_TYPE (decl));
tree passed_type = type_main_variant (DECL_ARG_TYPE (decl));
if (declared_type == passed_type)
rtl = DECL_INCOMING_RTL (decl);
else if (! BYTES_BIG_ENDIAN
&& TREE_CODE (declared_type) == INTEGER_TYPE
&& (GET_MODE_SIZE (TYPE_MODE (declared_type))
<= GET_MODE_SIZE (TYPE_MODE (passed_type))))
rtl = DECL_INCOMING_RTL (decl);
}
else if (GET_CODE (rtl) == MEM
&& XEXP (rtl, 0) != const0_rtx
&& ! CONSTANT_P (XEXP (rtl, 0))
&& GET_CODE (DECL_INCOMING_RTL (decl)) != MEM
&& (GET_CODE (XEXP (rtl, 0)) != REG
|| 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));
}
}
if (rtl != NULL_RTX)
{
rtl = eliminate_regs (rtl, 0, NULL_RTX);
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
leaf_renumber_regs_insn (rtl);
#endif
}
else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
{
if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
&& TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
{
tree arrtype = TREE_TYPE (decl);
tree enttype = TREE_TYPE (arrtype);
tree domain = TYPE_DOMAIN (arrtype);
tree init = DECL_INITIAL (decl);
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, TREE_STRING_POINTER (init));
}
if (rtl == NULL)
{
rtl = expand_expr (DECL_INITIAL (decl), NULL_RTX, VOIDmode,
EXPAND_INITIALIZER);
if (rtl && GET_CODE (rtl) == MEM)
rtl = NULL;
}
}
#ifdef ASM_SIMPLIFY_DWARF_ADDR
if (rtl)
rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
#endif
return rtl;
}
static void
add_location_or_const_value_attribute (die, decl)
dw_die_ref die;
tree decl;
{
rtx rtl;
if (TREE_CODE (decl) == ERROR_MARK)
return;
else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
abort ();
rtl = rtl_for_decl_location (decl);
if (rtl == NULL_RTX)
return;
rtl = avoid_constant_pool_reference (rtl);
switch (GET_CODE (rtl))
{
case ADDRESSOF:
break;
case CONST_INT:
case CONST_DOUBLE:
case CONST_STRING:
case SYMBOL_REF:
case LABEL_REF:
case CONST:
case PLUS:
add_const_value_attribute (die, rtl);
break;
case MEM:
case REG:
case SUBREG:
case CONCAT:
add_AT_location_description (die, DW_AT_location, rtl);
break;
default:
abort ();
}
}
static void
tree_add_const_value_attribute (var_die, decl)
dw_die_ref var_die;
tree decl;
{
tree init = DECL_INITIAL (decl);
tree type = TREE_TYPE (decl);
if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init
&& initializer_constant_valid_p (init, type) == null_pointer_node)
;
else
return;
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
if (host_integerp (init, 0))
add_AT_unsigned (var_die, DW_AT_const_value,
tree_low_cst (init, 0));
else
add_AT_long_long (var_die, DW_AT_const_value,
TREE_INT_CST_HIGH (init),
TREE_INT_CST_LOW (init));
break;
default:;
}
}
static inline void
add_name_attribute (die, name_string)
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_bound_info (subrange_die, bound_attr, bound)
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:
if (SAVE_EXPR_RTL (bound)
&& (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM))
{
dw_die_ref ctx = lookup_decl_die (current_function_decl);
dw_die_ref decl_die = new_die (DW_TAG_variable, ctx, bound);
rtx loc = SAVE_EXPR_RTL (bound);
if (GET_CODE (loc) == MEM)
{
rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound);
if (XEXP (loc, 0) != new_addr)
loc = gen_rtx_MEM (GET_MODE (loc), new_addr);
}
add_AT_flag (decl_die, DW_AT_artificial, 1);
add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
add_AT_location_description (decl_die, DW_AT_location, loc);
add_AT_die_ref (subrange_die, bound_attr, decl_die);
}
break;
case VAR_DECL:
case PARM_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, 0);
if (loc == NULL)
break;
if (current_function_decl == 0)
ctx = comp_unit_die;
else
ctx = lookup_decl_die (current_function_decl);
if (ctx == 0)
bound = build (SAVE_EXPR, TREE_TYPE (bound), bound,
current_function_decl, NULL_TREE);
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 (type_die, type)
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 (die, tree_node)
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:
abort ();
}
add_AT_unsigned (die, DW_AT_byte_size, size);
}
static inline void
add_bit_offset_attribute (die, decl)
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;
if (!type
|| TREE_CODE (decl) != FIELD_DECL)
abort ();
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 (die, decl)
dw_die_ref die;
tree decl;
{
if (TREE_CODE (decl) != FIELD_DECL
|| ! DECL_BIT_FIELD_TYPE (decl))
abort ();
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 (die, func_type)
dw_die_ref die;
tree func_type;
{
if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
&& TYPE_ARG_TYPES (func_type) != NULL)
add_AT_flag (die, DW_AT_prototyped, 1);
}
static inline void
add_abstract_origin_attribute (die, origin)
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 == NULL)
abort ();
add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
}
static inline void
add_pure_or_virtual_attribute (die, func_decl)
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 (die, decl)
dw_die_ref die;
tree decl;
{
unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
add_AT_unsigned (die, DW_AT_decl_file, file_index);
add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
}
static void
add_name_and_src_coords_attributes (die, decl)
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)
&& DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
&& !DECL_ABSTRACT (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));
VARRAY_PUSH_RTX (used_rtx_varray, XEXP (DECL_RTL (decl), 0));
}
#endif
}
static void
push_decl_scope (scope)
tree scope;
{
VARRAY_PUSH_TREE (decl_scope_table, scope);
}
static inline void
pop_decl_scope ()
{
if (VARRAY_ACTIVE_SIZE (decl_scope_table) <= 0)
abort ();
VARRAY_POP (decl_scope_table);
}
static dw_die_ref
scope_die_for (t, context_die)
tree t;
dw_die_ref context_die;
{
dw_die_ref scope_die = NULL;
tree containing_scope;
int i;
if (! TYPE_P (t))
abort ();
containing_scope = TYPE_CONTEXT (t);
if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
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 = VARRAY_ACTIVE_SIZE (decl_scope_table) - 1; i >= 0; --i)
if (VARRAY_TREE (decl_scope_table, i) == containing_scope)
break;
if (i < 0)
{
if (debug_info_level > DINFO_LEVEL_TERSE
&& !TREE_ASM_WRITTEN (containing_scope))
abort ();
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 (context_die)
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_scope_p (context_die)
dw_die_ref context_die;
{
return (context_die
&& (context_die->die_tag == DW_TAG_structure_type
|| context_die->die_tag == DW_TAG_union_type));
}
static void
add_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
dw_die_ref object_die;
tree type;
int decl_const;
int decl_volatile;
dw_die_ref context_die;
{
enum tree_code code = TREE_CODE (type);
dw_die_ref type_die = NULL;
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;
if (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 const char *
type_tag (type)
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 (member)
tree member;
{
return (DECL_BIT_FIELD_TYPE (member)
? DECL_BIT_FIELD_TYPE (member) : TREE_TYPE (member));
}
#if 0
static const char *
decl_start_label (decl)
tree decl;
{
rtx x;
const char *fnname;
x = DECL_RTL (decl);
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
if (GET_CODE (x) != SYMBOL_REF)
abort ();
fnname = XSTR (x, 0);
return fnname;
}
#endif
static void
gen_array_type_die (type, context_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);
#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_unsigned (array_die, DW_AT_declaration, 1);
else
#endif
add_subscript_info (array_die, type);
add_name_attribute (array_die, type_tag (type));
equate_type_number_to_die (type, array_die);
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);
}
static void
gen_set_type_die (type, context_die)
tree type;
dw_die_ref context_die;
{
dw_die_ref type_die
= new_die (DW_TAG_set_type, scope_die_for (type, context_die), type);
equate_type_number_to_die (type, type_die);
add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die);
}
#if 0
static void
gen_entry_point_die (decl, context_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 ()
{
int i;
for (i = VARRAY_ACTIVE_SIZE (incomplete_types) - 1; i >= 0; i--)
gen_type_die (VARRAY_TREE (incomplete_types, i), comp_unit_die);
}
static void
gen_inlined_enumeration_type_die (type, context_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 (type, context_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 (type, context_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 void
gen_enumeration_type_die (type, context_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;
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_FIELDS (type);
link != NULL; link = TREE_CHAIN (link))
{
dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
add_name_attribute (enum_die,
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
if (host_integerp (TREE_VALUE (link), 0))
{
if (tree_int_cst_sgn (TREE_VALUE (link)) < 0)
add_AT_int (enum_die, DW_AT_const_value,
tree_low_cst (TREE_VALUE (link), 0));
else
add_AT_unsigned (enum_die, DW_AT_const_value,
tree_low_cst (TREE_VALUE (link), 0));
}
}
}
else
add_AT_flag (type_die, DW_AT_declaration, 1);
}
static dw_die_ref
gen_formal_parameter_die (node, context_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 'd':
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);
break;
case 't':
add_type_attribute (parm_die, node, 0, 0, context_die);
break;
default:
abort ();
}
return parm_die;
}
static void
gen_unspecified_parameters_die (decl_or_type, context_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 (function_or_method_type, context_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 (type, member, context_die)
tree type, 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))
{
if (decl_ultimate_origin (member))
abort ();
push_decl_scope (type);
if (TREE_CODE (member) == FUNCTION_DECL)
gen_subprogram_die (member, lookup_type_die (type));
else
gen_variable_die (member, lookup_type_die (type));
pop_decl_scope ();
}
}
static void
dwarf2out_abstract_function (decl)
tree decl;
{
dw_die_ref old_die;
tree save_fn;
tree context;
int was_abstract = DECL_ABSTRACT (decl);
decl = DECL_ORIGIN (decl);
old_die = lookup_decl_die (decl);
if (old_die && get_AT_unsigned (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;
current_function_decl = decl;
set_decl_abstract_flags (decl, 1);
dwarf2out_decl (decl);
if (! was_abstract)
set_decl_abstract_flags (decl, 0);
current_function_decl = save_fn;
}
static void
gen_subprogram_die (decl, context_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;
rtx fp_reg;
tree fn_arg_types;
tree outer_scope;
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (current_function_decl != decl
|| class_scope_p (context_die));
if (origin && declaration && class_scope_p (context_die))
{
origin = NULL;
if (old_die)
abort ();
}
if (origin != NULL)
{
if (declaration && ! local_scope_p (context_die))
abort ();
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)
{
unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
if (!get_AT_flag (old_die, DW_AT_declaration)
&& !get_AT_unsigned (old_die, DW_AT_inline))
{
if (errorcount)
return;
abort ();
}
if ((old_die->die_parent == comp_unit_die || context_die == NULL)
&& (DECL_ARTIFICIAL (decl)
|| (get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) DECL_SOURCE_LINE (decl)))))
{
subr_die = old_die;
remove_AT (subr_die, DW_AT_declaration);
remove_children (subr_die);
}
else
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
add_AT_die_ref (subr_die, DW_AT_specification, old_die);
if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
add_AT_unsigned (subr_die, DW_AT_decl_file, file_index);
if (get_AT_unsigned (old_die, DW_AT_decl_line)
!= (unsigned) DECL_SOURCE_LINE (decl))
add_AT_unsigned
(subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (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_unsigned (old_die, DW_AT_inline))
{
add_AT_flag (subr_die, DW_AT_declaration, 1);
if (DECL_CONTEXT (decl) || DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, subr_die);
}
}
else if (DECL_ABSTRACT (decl))
{
if (DECL_INLINE (decl) && !flag_no_inline)
{
if (DECL_DEFER_OUTPUT (decl))
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
else
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
}
else
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
equate_decl_number_to_die (decl, subr_die);
}
else if (!DECL_EXTERNAL (decl))
{
if (!old_die || !get_AT_unsigned (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
current_funcdef_number);
add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_funcdef_number);
add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
add_pubname (decl, subr_die);
add_arange (decl, subr_die);
#ifdef MIPS_DEBUGGING_INFO
add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
#endif
fp_reg
= frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
#if 0
if (current_function_needs_context)
add_AT_location_description (subr_die, DW_AT_static_link,
lookup_static_chain (decl));
#endif
}
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)
{
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
}
}
static void
gen_variable_die (decl, context_die)
tree decl;
dw_die_ref context_die;
{
tree origin = decl_ultimate_origin (decl);
dw_die_ref var_die = new_die (DW_TAG_variable, context_die, decl);
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (DECL_EXTERNAL (decl)
|| class_scope_p (context_die));
if (origin != NULL)
add_abstract_origin_attribute (var_die, origin);
else if (old_die && TREE_STATIC (decl)
&& get_AT_flag (old_die, DW_AT_declaration) == 1)
{
add_AT_die_ref (var_die, DW_AT_specification, old_die);
if (DECL_NAME (decl))
{
unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
if (get_AT_unsigned (old_die, DW_AT_decl_line)
!= (unsigned) DECL_SOURCE_LINE (decl))
add_AT_unsigned (var_die, DW_AT_decl_line,
DECL_SOURCE_LINE (decl));
}
}
else
{
add_name_and_src_coords_attributes (var_die, decl);
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 (class_scope_p (context_die) || DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, var_die);
if (! declaration && ! DECL_ABSTRACT (decl))
{
add_location_or_const_value_attribute (var_die, decl);
add_pubname (decl, var_die);
}
else
tree_add_const_value_attribute (var_die, decl);
}
static void
gen_label_die (decl, context_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 (decl);
if (GET_CODE (insn) == CODE_LABEL
|| ((GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
{
if (INSN_DELETED_P (insn))
abort ();
ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
}
}
}
static void
gen_lexical_block_die (stmt, context_die, depth)
tree stmt;
dw_die_ref context_die;
int depth;
{
dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
if (! BLOCK_ABSTRACT (stmt))
{
if (BLOCK_FRAGMENT_CHAIN (stmt))
{
tree chain;
add_AT_range_list (stmt_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 (stmt_die, DW_AT_low_pc, label);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
BLOCK_NUMBER (stmt));
add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
}
}
decls_for_scope (stmt, stmt_die, depth);
}
static void
gen_inlined_subroutine_die (stmt, context_die, depth)
tree stmt;
dw_die_ref context_die;
int depth;
{
if (! BLOCK_ABSTRACT (stmt))
{
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
tree decl = block_ultimate_origin (stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
dwarf2out_abstract_function (decl);
add_abstract_origin_attribute (subr_die, decl);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
BLOCK_NUMBER (stmt));
add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
decls_for_scope (stmt, subr_die, depth);
current_function_has_inlines = 1;
}
else
gen_lexical_block_die (stmt, context_die, depth);
}
static void
gen_field_die (decl, context_die)
tree decl;
dw_die_ref context_die;
{
dw_die_ref 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);
}
#if 0
static void
gen_pointer_type_die (type, context_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 (type, context_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 (type, context_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 (filename)
const char *filename;
{
dw_die_ref die;
char producer[250];
const char *wd = getpwd ();
const char *language_string = lang_hooks.name;
int language;
die = new_die (DW_TAG_compile_unit, NULL, NULL);
add_name_attribute (die, filename);
if (wd != NULL && filename[0] != DIR_SEPARATOR)
add_AT_string (die, DW_AT_comp_dir, wd);
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_Ada83;
else if (strcmp (language_string, "GNU F77") == 0)
language = DW_LANG_Fortran77;
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 (flag_traditional)
language = DW_LANG_C;
else
language = DW_LANG_C89;
add_AT_unsigned (die, DW_AT_language, language);
return die;
}
static void
gen_string_type_die (type, context_die)
tree type;
dw_die_ref context_die;
{
dw_die_ref type_die
= new_die (DW_TAG_string_type, scope_die_for (type, context_die), type);
equate_type_number_to_die (type, type_die);
#if 0
string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
bound_representation (upper_bound, 0, 'u');
#endif
}
static void
gen_inheritance_die (binfo, context_die)
tree binfo;
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 (TREE_VIA_VIRTUAL (binfo))
add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
if (TREE_VIA_PUBLIC (binfo))
add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
else if (TREE_VIA_PROTECTED (binfo))
add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
}
static void
gen_member_die (type, context_die)
tree type;
dw_die_ref context_die;
{
tree member;
dw_die_ref child;
if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
{
tree bases = TYPE_BINFO_BASETYPES (type);
int n_bases = TREE_VEC_LENGTH (bases);
int i;
for (i = 0; i < n_bases; i++)
gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die);
}
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 (type, context_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))));
if (type_die && ! complete)
return;
if (TYPE_CONTEXT (type) != NULL_TREE
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type)))
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_die_ref (type_die, DW_AT_specification, old_die);
else
add_name_attribute (type_die, type_tag (type));
}
else
remove_AT (type_die, DW_AT_declaration);
if (complete)
{
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)))
VARRAY_PUSH_TREE (incomplete_types, type);
}
}
static void
gen_subroutine_type_die (type, context_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);
}
static void
gen_typedef_die (decl, context_die)
tree decl;
dw_die_ref context_die;
{
dw_die_ref type_die;
tree origin;
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);
if (type == TREE_TYPE (decl))
abort ();
else
equate_type_number_to_die (TREE_TYPE (decl), type_die);
}
else
type = TREE_TYPE (decl);
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);
}
static void
gen_type_die (type, context_die)
tree type;
dw_die_ref context_die;
{
int need_pop;
if (type == NULL_TREE || type == error_mark_node)
return;
type = type_main_variant (type);
if (TREE_ASM_WRITTEN (type))
return;
if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
{
TREE_ASM_WRITTEN (type) = 1;
gen_decl_die (TYPE_NAME (type), context_die);
return;
}
switch (TREE_CODE (type))
{
case ERROR_MARK:
break;
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 SET_TYPE:
gen_type_die (TYPE_DOMAIN (type), context_die);
gen_set_type_die (type, context_die);
break;
case FILE_TYPE:
gen_type_die (TREE_TYPE (type), context_die);
abort ();
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:
if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE)
{
gen_type_die (TREE_TYPE (type), context_die);
gen_string_type_die (type, context_die);
}
else
gen_array_type_die (type, context_die);
break;
case VECTOR_TYPE:
gen_type_die (TYPE_DEBUG_REPRESENTATION_TYPE (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
need_pop = 0;
if (TREE_CODE (type) == ENUMERAL_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:
case CHAR_TYPE:
break;
case LANG_TYPE:
break;
default:
abort ();
}
TREE_ASM_WRITTEN (type) = 1;
}
static void
gen_tagged_type_instantiation_die (type, context_die)
tree type;
dw_die_ref context_die;
{
if (type == NULL_TREE || type == error_mark_node)
return;
if (type != type_main_variant (type))
abort ();
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:
abort ();
}
}
static void
gen_block_die (stmt, context_die, depth)
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 || !TREE_USED (stmt)
|| (!TREE_ASM_WRITTEN (stmt) && !BLOCK_ABSTRACT (stmt)))
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);
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 (stmt, context_die, depth)
tree stmt;
dw_die_ref context_die;
int depth;
{
tree decl;
tree subblocks;
if (stmt == NULL_TREE || ! TREE_USED (stmt))
return;
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);
else
gen_decl_die (decl, context_die);
}
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 (decl)
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 void
gen_decl_die (decl, context_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 (DECL_ORIGIN (decl) != decl)
dwarf2out_abstract_function (DECL_ABSTRACT_ORIGIN (decl));
else if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl)
&& ! class_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);
}
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:
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);
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)
{
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:
break;
default:
abort ();
}
}
static void
mark_limbo_die_list (ptr)
void *ptr ATTRIBUTE_UNUSED;
{
limbo_die_node *node;
for (node = limbo_die_list; node ; node = node->next)
ggc_mark_tree (node->created_for);
}
void
dwarf2out_add_library_unit_info (filename, context_list)
const char *filename;
const char *context_list;
{
unsigned int file_index;
if (filename != NULL)
{
dw_die_ref unit_die = new_die (DW_TAG_module, comp_unit_die, NULL);
tree context_list_decl
= build_decl (LABEL_DECL, get_identifier (context_list),
void_type_node);
TREE_PUBLIC (context_list_decl) = TRUE;
add_name_attribute (unit_die, context_list);
file_index = lookup_filename (filename);
add_AT_unsigned (unit_die, DW_AT_decl_file, file_index);
add_pubname (context_list_decl, unit_die);
}
}
static void
dwarf2out_global_decl (decl)
tree decl;
{
if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
dwarf2out_decl (decl);
}
void
dwarf2out_decl (decl)
tree decl;
{
dw_die_ref context_die = comp_unit_die;
switch (TREE_CODE (decl))
{
case ERROR_MARK:
return;
case FUNCTION_DECL:
if (DECL_EXTERNAL (decl) && DECL_BUILT_IN (decl))
return;
if (DECL_INITIAL (decl) == NULL_TREE)
return;
if (decl_function_context (decl))
context_die = NULL;
break;
case VAR_DECL:
if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
return;
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
break;
case TYPE_DECL:
if (TYPE_DECL_SUPPRESS_DEBUG (decl))
return;
if (DECL_SOURCE_LINE (decl) == 0)
{
if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
== DW_LANG_C_plus_plus)
&& 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 (line, blocknum)
unsigned int line ATTRIBUTE_UNUSED;
unsigned int blocknum;
{
function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
static void
dwarf2out_end_block (line, blocknum)
unsigned int line ATTRIBUTE_UNUSED;
unsigned int blocknum;
{
function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
static bool
dwarf2out_ignore_block (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 unsigned
lookup_filename (file_name)
const char *file_name;
{
unsigned i;
if (strcmp (file_name, "<internal>") == 0
|| strcmp (file_name, "<built-in>") == 0)
return 0;
if (file_table.last_lookup_index != 0)
if (0 == strcmp (file_name,
file_table.table[file_table.last_lookup_index]))
return file_table.last_lookup_index;
for (i = 1; i < file_table.in_use; i++)
if (strcmp (file_name, file_table.table[i]) == 0)
{
file_table.last_lookup_index = i;
return i;
}
if (i == file_table.allocated)
{
file_table.allocated = i + FILE_TABLE_INCREMENT;
file_table.table = (char **)
xrealloc (file_table.table, file_table.allocated * sizeof (char *));
}
file_table.table[i] = xstrdup (file_name);
file_table.in_use = i + 1;
file_table.last_lookup_index = i;
if (DWARF2_ASM_LINE_DEBUG_INFO)
fprintf (asm_out_file, "\t.file %u \"%s\"\n", i, file_name);
return i;
}
static void
init_file_table ()
{
file_table.table = (char **) xcalloc (FILE_TABLE_INCREMENT, sizeof (char *));
file_table.allocated = FILE_TABLE_INCREMENT;
file_table.in_use = 1;
file_table.last_lookup_index = 0;
}
static void
dwarf2out_source_line (line, filename)
unsigned int line;
const char *filename;
{
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
function_section (current_function_decl);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
filename, line);
if (DWARF2_ASM_LINE_DEBUG_INFO)
{
unsigned file_num = lookup_filename (filename);
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
line_info_table_in_use++;
if (DECL_SECTION_NAME (current_function_decl))
separate_line_info_table_in_use++;
}
else if (DECL_SECTION_NAME (current_function_decl))
{
dw_separate_line_info_ref line_info;
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
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
= (dw_separate_line_info_ref)
xrealloc (separate_line_info_table,
separate_line_info_table_allocated
* sizeof (dw_separate_line_info_entry));
}
line_info
= &separate_line_info_table[separate_line_info_table_in_use++];
line_info->dw_file_num = lookup_filename (filename);
line_info->dw_line_num = line;
line_info->function = current_funcdef_number;
}
else
{
dw_line_info_ref line_info;
ASM_OUTPUT_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
= (dw_line_info_ref)
xrealloc (line_info_table,
(line_info_table_allocated
* sizeof (dw_line_info_entry)));
}
line_info = &line_info_table[line_info_table_in_use++];
line_info->dw_file_num = lookup_filename (filename);
line_info->dw_line_num = line;
}
}
}
static void
dwarf2out_start_source_file (lineno, filename)
unsigned int lineno;
const char *filename;
{
if (flag_eliminate_dwarf2_dups)
{
dw_die_ref 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)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
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 (lookup_filename (filename),
"Filename we just started");
}
}
static void
dwarf2out_end_source_file (lineno)
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)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
}
}
static void
dwarf2out_define (lineno, buffer)
unsigned lineno ATTRIBUTE_UNUSED;
const char *buffer ATTRIBUTE_UNUSED;
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
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 (lineno, buffer)
unsigned lineno ATTRIBUTE_UNUSED;
const char *buffer ATTRIBUTE_UNUSED;
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
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 (main_input_filename)
const char *main_input_filename;
{
init_file_table ();
primary_filename = main_input_filename;
lookup_filename (main_input_filename);
decl_die_table
= (dw_die_ref *) xcalloc (DECL_DIE_TABLE_INCREMENT, sizeof (dw_die_ref));
decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
decl_die_table_in_use = 0;
VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");
ggc_add_tree_varray_root (&decl_scope_table, 1);
abbrev_die_table
= (dw_die_ref *) xcalloc (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
= (dw_line_info_ref) xcalloc (LINE_INFO_TABLE_INCREMENT,
sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
line_info_table_in_use = 1;
comp_unit_die = gen_compile_unit_die (main_input_filename);
VARRAY_TREE_INIT (incomplete_types, 64, "incomplete_types");
ggc_add_tree_varray_root (&incomplete_types, 1);
VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray");
ggc_add_rtx_varray_root (&used_rtx_varray, 1);
ggc_add_root (&limbo_die_list, 1, 1, mark_limbo_die_list);
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
DEBUG_ABBREV_SECTION_LABEL, 0);
if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
else
strcpy (text_section_label, stripattributes (TEXT_SECTION_NAME));
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);
named_section_flags (DEBUG_ABBREV_SECTION, SECTION_DEBUG);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
named_section_flags (DEBUG_INFO_SECTION, SECTION_DEBUG);
ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
named_section_flags (DEBUG_LINE_SECTION, SECTION_DEBUG);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
DEBUG_MACINFO_SECTION_LABEL, 0);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
}
if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
{
text_section ();
ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
}
}
static hashnode
indirect_string_alloc (tab)
hash_table *tab ATTRIBUTE_UNUSED;
{
struct indirect_string_node *node;
node = xmalloc (sizeof (struct indirect_string_node));
node->refcount = 0;
node->form = 0;
node->label = NULL;
return (hashnode) node;
}
static int
output_indirect_string (pfile, h, v)
struct cpp_reader *pfile ATTRIBUTE_UNUSED;
hashnode h;
const PTR v ATTRIBUTE_UNUSED;
{
struct indirect_string_node *node = (struct indirect_string_node *) h;
if (node->form == DW_FORM_strp)
{
named_section_flags (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS);
ASM_OUTPUT_LABEL (asm_out_file, node->label);
assemble_string ((const char *) HT_STR (&node->id),
HT_LEN (&node->id) + 1);
}
return 1;
}
static void
dwarf2out_finish (input_filename)
const char *input_filename ATTRIBUTE_UNUSED;
{
limbo_die_node *node, *next_node;
dw_die_ref die = 0;
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);
tree context;
if (origin)
add_child_die (origin->die_parent, die);
else if (die == comp_unit_die)
;
else if (node->created_for
&& TREE_CODE (node->created_for) == SAVE_EXPR
&& 0 != (origin = (lookup_decl_die
(SAVE_EXPR_CONTEXT
(node->created_for)))))
add_child_die (origin, die);
else if (errorcount > 0 || sorrycount > 0)
add_child_die (comp_unit_die, die);
else if (node->created_for
&& ((DECL_P (node->created_for)
&& (context = DECL_CONTEXT (node->created_for)))
|| (TYPE_P (node->created_for)
&& (context = TYPE_CONTEXT (node->created_for))))
&& TREE_CODE (context) == FUNCTION_DECL)
{
origin = lookup_decl_die (context);
if (! origin)
abort ();
add_child_die (origin, die);
}
else
abort ();
}
free (node);
}
limbo_die_list = NULL;
retry_incomplete_types ();
reverse_all_dies (comp_unit_die);
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);
text_section ();
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
if (! DWARF2_ASM_LINE_DEBUG_INFO)
{
named_section_flags (DEBUG_LINE_SECTION, SECTION_DEBUG);
output_line_info ();
}
if (have_location_lists)
{
named_section_flags (DEBUG_LOC_SECTION, SECTION_DEBUG);
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);
have_location_lists = 0;
}
if (separate_line_info_table_in_use == 0)
{
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 (debug_info_level >= DINFO_LEVEL_NORMAL)
add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
add_AT_lbl_offset (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
for (node = limbo_die_list; node; node = node->next)
output_comp_unit (node->die);
output_comp_unit (comp_unit_die);
named_section_flags (DEBUG_ABBREV_SECTION, SECTION_DEBUG);
output_abbrev_section ();
if (pubname_table_in_use)
{
named_section_flags (DEBUG_PUBNAMES_SECTION, SECTION_DEBUG);
output_pubnames ();
}
if (fde_table_in_use)
{
named_section_flags (DEBUG_ARANGES_SECTION, SECTION_DEBUG);
output_aranges ();
}
if (ranges_table_in_use)
{
named_section_flags (DEBUG_RANGES_SECTION, SECTION_DEBUG);
ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
output_ranges ();
}
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
}
if (debug_str_hash)
ht_forall (debug_str_hash, output_indirect_string, NULL);
}
#endif