#include "config.h"
#include "system.h"
#include "defaults.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 "output.h"
#include "expr.h"
#include "except.h"
#include "dwarf2.h"
#include "dwarf2out.h"
#include "toplev.h"
#include "dyn-string.h"
#undef assert
#ifdef NDEBUG
# define assert(e)
#else
# define assert(e) do { if (! (e)) abort (); } while (0)
#endif
static int frame_was_required = 0;
static int this_function_needs_dwarf2_info ()
{
if (get_insns() != NULL && ! leaf_function_p ())
return frame_was_required = 1;
return 0;
}
int
dwarf2out_do_frame ()
{
int f = (write_symbols == DWARF2_DEBUG
#ifdef DWARF2_FRAME_INFO
|| DWARF2_FRAME_INFO
#endif
#ifdef DWARF2_UNWIND_INFO
#ifdef NEXT_SEMANTICS
|| (flag_exceptions && ! exceptions_via_longjmp
&& (get_insns () == NULL
|| this_function_needs_dwarf2_info ()))
#else
|| (flag_exceptions && ! exceptions_via_longjmp)
#endif
#endif
);
return f;
}
#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;
char *dw_cfi_addr;
}
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 dw_fde_struct
{
char *dw_fde_begin;
char *dw_fde_current_label;
char *dw_fde_end;
dw_cfi_ref dw_fde_cfi;
}
dw_fde_node;
#define MAX_ARTIFICIAL_LABEL_BYTES 30
#ifndef CHAR_TYPE_SIZE
#define CHAR_TYPE_SIZE BITS_PER_UNIT
#endif
#ifndef PTR_SIZE
#define PTR_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) - 1))
#ifdef STACK_GROWS_DOWNWARD
#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD)
#else
#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD
#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_number = 0;
static unsigned current_funcdef_fde;
static char *stripattributes PROTO((const char *));
static char *dwarf_cfi_name PROTO((unsigned));
static dw_cfi_ref new_cfi PROTO((void));
static void add_cfi PROTO((dw_cfi_ref *, dw_cfi_ref));
static unsigned long size_of_uleb128 PROTO((unsigned long));
static unsigned long size_of_sleb128 PROTO((long));
static void output_uleb128 PROTO((unsigned long));
static void output_sleb128 PROTO((long));
static void add_fde_cfi PROTO((char *, dw_cfi_ref));
static void lookup_cfa_1 PROTO((dw_cfi_ref, unsigned long *,
long *));
static void lookup_cfa PROTO((unsigned long *, long *));
static void reg_save PROTO((char *, unsigned, unsigned,
long));
static void initial_return_save PROTO((rtx));
static void output_cfi PROTO((dw_cfi_ref, dw_fde_ref));
static void output_call_frame_info PROTO((int));
static unsigned reg_number PROTO((rtx));
static void dwarf2out_stack_adjust PROTO((rtx));
#ifdef OBJECT_FORMAT_ELF
#ifndef UNALIGNED_SHORT_ASM_OP
#define UNALIGNED_SHORT_ASM_OP ".2byte"
#endif
#ifndef UNALIGNED_INT_ASM_OP
#define UNALIGNED_INT_ASM_OP ".4byte"
#endif
#ifndef UNALIGNED_DOUBLE_INT_ASM_OP
#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte"
#endif
#endif
#ifndef ASM_BYTE_OP
#define ASM_BYTE_OP ".byte"
#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 ".section"
#endif
#ifndef SECTION_FORMAT
#ifdef PUSHSECTION_FORMAT
#define SECTION_FORMAT PUSHSECTION_FORMAT
#else
#define SECTION_FORMAT "\t%s\t%s\n"
#endif
#endif
#ifndef FRAME_SECTION
#define 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 CIE_AFTER_SIZE_LABEL "LSCIE"
#define CIE_END_LABEL "LECIE"
#define CIE_LENGTH_LABEL "LLCIE"
#define FDE_AFTER_SIZE_LABEL "LSFDE"
#define FDE_END_LABEL "LEFDE"
#define FDE_LENGTH_LABEL "LLFDE"
#ifndef ASM_OUTPUT_SECTION
#define ASM_OUTPUT_SECTION(FILE, SECTION) \
fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
#endif
#ifndef ASM_OUTPUT_DWARF_DATA1
#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_DELTA1
#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2) \
do { fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \
assemble_name (FILE, LABEL1); \
fprintf (FILE, "-"); \
assemble_name (FILE, LABEL2); \
} while (0)
#endif
#ifdef UNALIGNED_INT_ASM_OP
#ifndef UNALIGNED_OFFSET_ASM_OP
#define UNALIGNED_OFFSET_ASM_OP \
(DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
#endif
#ifndef UNALIGNED_WORD_ASM_OP
#define UNALIGNED_WORD_ASM_OP \
(PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
#endif
#ifndef ASM_OUTPUT_DWARF_DELTA2
#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \
assemble_name (FILE, LABEL1); \
fprintf (FILE, "-"); \
assemble_name (FILE, LABEL2); \
} while (0)
#endif
#ifndef ASM_OUTPUT_DWARF_DELTA4
#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \
assemble_name (FILE, LABEL1); \
fprintf (FILE, "-"); \
assemble_name (FILE, LABEL2); \
} while (0)
#endif
#ifndef ASM_OUTPUT_DWARF_DELTA
#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \
assemble_name (FILE, LABEL1); \
fprintf (FILE, "-"); \
assemble_name (FILE, LABEL2); \
} while (0)
#endif
#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA
#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \
assemble_name (FILE, LABEL1); \
fprintf (FILE, "-"); \
assemble_name (FILE, LABEL2); \
} while (0)
#endif
#ifndef ASM_OUTPUT_DWARF_ADDR
#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \
assemble_name (FILE, LABEL); \
} while (0)
#endif
#ifdef ASM_OUTPUT_DWARF2_ADDR_CONST
#undef ASM_OUTPUT_DWARF_ADDR_CONST
#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \
ASM_OUTPUT_DWARF2_ADDR_CONST (FILE, ADDR)
#endif
#ifndef ASM_OUTPUT_DWARF_ADDR_CONST
#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \
fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR))
#endif
#ifndef ASM_OUTPUT_DWARF_OFFSET4
#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \
assemble_name (FILE, LABEL); \
} while (0)
#endif
#ifndef ASM_OUTPUT_DWARF_OFFSET
#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \
assemble_name (FILE, LABEL); \
} while (0)
#endif
#ifndef ASM_OUTPUT_DWARF_DATA2
#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_DATA4
#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_DATA
#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \
fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \
(unsigned long) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_ADDR_DATA
#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \
fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \
(unsigned long) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_DATA8
#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \
do { \
if (WORDS_BIG_ENDIAN) \
{ \
fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\
fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\
} \
else \
{ \
fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \
fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \
} \
} while (0)
#endif
#else
#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1)
#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
assemble_integer (gen_rtx_MINUS (HImode, \
gen_rtx_SYMBOL_REF (Pmode, LABEL1), \
gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
2, 1)
#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \
assemble_integer (gen_rtx_MINUS (SImode, \
gen_rtx_SYMBOL_REF (Pmode, LABEL1), \
gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
4, 1)
#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \
assemble_integer (gen_rtx_MINUS (Pmode, \
gen_rtx_SYMBOL_REF (Pmode, LABEL1), \
gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
PTR_SIZE, 1)
#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2)
#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
assemble_integer (GEN_INT (VALUE), 4, 1)
#endif
#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, "\t%s\t", SET_ASM_OP); \
assemble_name (FILE, SY); \
fputc (',', FILE); \
assemble_name (FILE, HI); \
fputc ('-', FILE); \
assemble_name (FILE, LO); \
} while (0)
#endif
#endif
#ifndef ASM_OUTPUT_DWARF_STRING
#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
do { \
register int slen = strlen(P); \
register char *p = (P); \
register int i; \
fprintf (FILE, "\t.ascii \""); \
for (i = 0; i < slen; i++) \
{ \
register int c = p[i]; \
if (c == '\"' || c == '\\') \
putc ('\\', FILE); \
if (c >= ' ' && c < 0177) \
putc (c, FILE); \
else \
{ \
fprintf (FILE, "\\%o", c); \
} \
} \
fprintf (FILE, "\\0\""); \
} \
while (0)
#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 FIRST_PSEUDO_REGISTER
#endif
#endif
#ifndef DWARF_FRAME_REGNUM
#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
#endif
rtx
expand_builtin_dwarf_fp_regnum ()
{
return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
}
#ifndef INCOMING_FRAME_SP_OFFSET
#define INCOMING_FRAME_SP_OFFSET 0
#endif
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;
}
static unsigned
reg_number (rtl)
register rtx rtl;
{
register unsigned regno = REGNO (rtl);
if (regno >= FIRST_PSEUDO_REGISTER)
{
warning ("internal regno botch: regno = %d\n", regno);
regno = 0;
}
regno = DBX_REGISTER_NUMBER (regno);
return regno;
}
struct reg_size_range
{
int beg;
int end;
int size;
};
#ifndef MAX_NUMBER_OF_REG_SIZES
#define MAX_NUMBER_OF_REG_SIZES 10
#endif
rtx
expand_builtin_dwarf_reg_size (reg_tree, target)
tree reg_tree;
rtx target;
{
enum machine_mode mode;
int size;
struct reg_size_range ranges[MAX_NUMBER_OF_REG_SIZES];
tree t, t2;
int i = 0;
int n_ranges = 0;
int last_size = -1;
for (; i < FIRST_PSEUDO_REGISTER; ++i)
{
if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
continue;
mode = reg_raw_mode[i];
if (GET_MODE_CLASS (mode) == MODE_CC)
mode = word_mode;
size = GET_MODE_SIZE (mode);
if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1)
size = last_size;
if (size != last_size)
{
ranges[n_ranges].beg = i;
ranges[n_ranges].size = last_size = size;
++n_ranges;
if (n_ranges >= MAX_NUMBER_OF_REG_SIZES)
abort ();
}
ranges[n_ranges-1].end = i;
}
if (n_ranges == 3 && ranges[0].size == ranges[2].size)
{
if ((DWARF_FRAME_REGNUM (ranges[1].end)
- DWARF_FRAME_REGNUM (ranges[1].beg))
!= ranges[1].end - ranges[1].beg)
abort ();
t = fold (build (GE_EXPR, integer_type_node, reg_tree,
build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0)));
t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0)));
t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2));
t = fold (build (COND_EXPR, integer_type_node, t,
build_int_2 (ranges[1].size, 0),
build_int_2 (ranges[0].size, 0)));
}
else
{
int last_end = 0x7fffffff;
--n_ranges;
t = build_int_2 (ranges[n_ranges].size, 0);
do
{
int beg = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
int end = DWARF_FRAME_REGNUM (ranges[n_ranges].end);
if (beg < 0)
continue;
if (end >= last_end)
abort ();
last_end = end;
if (end - beg != ranges[n_ranges].end - ranges[n_ranges].beg)
abort ();
t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
build_int_2 (end, 0)));
t = fold (build (COND_EXPR, integer_type_node, t2,
build_int_2 (ranges[n_ranges].size, 0), t));
}
while (--n_ranges >= 0);
}
return expand_expr (t, target, Pmode, 0);
}
static char *
dwarf_cfi_name (cfi_opc)
register 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_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 ()
{
register 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)
register dw_cfi_ref *list_head;
register dw_cfi_ref cfi;
{
register 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)
register char *label;
register dw_cfi_ref cfi;
{
if (label)
{
register 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)
{
register 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, regp, offsetp)
register dw_cfi_ref cfi;
register unsigned long *regp;
register long *offsetp;
{
switch (cfi->dw_cfi_opc)
{
case DW_CFA_def_cfa_offset:
*offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset;
break;
case DW_CFA_def_cfa_register:
*regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
break;
case DW_CFA_def_cfa:
*regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
*offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset;
break;
default:
break;
}
}
static void
lookup_cfa (regp, offsetp)
register unsigned long *regp;
register long *offsetp;
{
register dw_cfi_ref cfi;
*regp = (unsigned long) -1;
*offsetp = 0;
for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
lookup_cfa_1 (cfi, regp, offsetp);
if (fde_table_in_use)
{
register 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, regp, offsetp);
}
}
static unsigned long cfa_reg;
static long cfa_offset;
static unsigned cfa_store_reg;
static long cfa_store_offset;
static long args_size;
static long old_args_size;
void
dwarf2out_def_cfa (label, reg, offset)
register char *label;
register unsigned reg;
register long offset;
{
register dw_cfi_ref cfi;
unsigned long old_reg;
long old_offset;
cfa_reg = reg;
cfa_offset = offset;
if (cfa_store_reg == reg)
cfa_store_offset = offset;
reg = DWARF_FRAME_REGNUM (reg);
lookup_cfa (&old_reg, &old_offset);
if (reg == old_reg && offset == old_offset)
return;
cfi = new_cfi ();
if (reg == old_reg)
{
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
cfi->dw_cfi_oprnd1.dw_cfi_offset = offset;
}
#ifndef MIPS_DEBUGGING_INFO
else if (offset == old_offset && old_reg != (unsigned long) -1)
{
cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
}
#endif
else
{
cfi->dw_cfi_opc = DW_CFA_def_cfa;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
}
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)
register char * label;
register unsigned reg;
register unsigned sreg;
register long offset;
{
register 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;
offset /= DWARF_CIE_DATA_ALIGNMENT;
if (offset < 0)
{
cfi->dw_cfi_opc = DW_CFA_GNU_negative_offset_extended;
offset = -offset;
}
cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
}
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)
register char * label;
{
register 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)
char *label;
long size;
{
register 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)
register char * label;
register unsigned reg;
register long offset;
{
reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
}
void
dwarf2out_return_save (label, offset)
register char * label;
register long offset;
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset);
}
void
dwarf2out_return_reg (label, sreg)
register char * label;
register unsigned sreg;
{
reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0);
}
static void
initial_return_save (rtl)
register rtx rtl;
{
unsigned int reg = (unsigned int) -1;
long offset = 0;
switch (GET_CODE (rtl))
{
case REG:
reg = reg_number (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 void
dwarf2out_stack_adjust (insn)
rtx insn;
{
long offset;
char *label;
if (! asynchronous_exceptions && 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);
assert (GET_CODE (insn) == CALL);
dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
return;
}
else if (! asynchronous_exceptions
&& 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)
{
rtx src, dest;
enum rtx_code code;
insn = PATTERN (insn);
src = SET_SRC (insn);
dest = SET_DEST (insn);
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;
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)
|| XEXP (src, 0) != stack_pointer_rtx)
return;
offset = GET_MODE_SIZE (GET_MODE (dest));
}
else
return;
if (code == PLUS || code == PRE_INC)
offset = -offset;
}
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 ();
dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
dwarf2out_args_size (label, args_size);
}
static unsigned cfa_temp_reg;
static long cfa_temp_value;
static void
dwarf2out_frame_debug_expr (expr, label)
rtx expr;
char *label;
{
rtx src, dest;
long offset;
if (GET_CODE (expr) == PARALLEL)
{
int par_index;
int limit = XVECLEN (expr, 0);
for (par_index = 0; par_index < limit; par_index++)
{
rtx x = XVECEXP (expr, 0, par_index);
if (GET_CODE (x) == SET &&
(RTX_FRAME_RELATED_P (x) || par_index == 0))
dwarf2out_frame_debug_expr (x, 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))
abort ();
if (REGNO (dest) != STACK_POINTER_REGNUM
&& !(frame_pointer_needed
&& REGNO (dest) == HARD_FRAME_POINTER_REGNUM))
abort ();
cfa_reg = REGNO (dest);
break;
case PLUS:
case MINUS:
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_value;
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 (XEXP (src, 0) != stack_pointer_rtx)
abort ();
if (GET_CODE (src) == PLUS)
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
|| REGNO (dest) != HARD_FRAME_POINTER_REGNUM)
abort ();
if (XEXP (src, 0) == stack_pointer_rtx
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
if (cfa_reg != STACK_POINTER_REGNUM)
abort ();
offset = INTVAL (XEXP (src, 1));
if (GET_CODE (src) == PLUS)
offset = -offset;
cfa_offset += offset;
cfa_reg = HARD_FRAME_POINTER_REGNUM;
}
else if (XEXP (src, 0) == hard_frame_pointer_rtx
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM)
abort ();
offset = INTVAL (XEXP (src, 1));
if (GET_CODE (src) == PLUS)
offset = -offset;
cfa_offset += offset;
}
else
abort();
}
else
{
if (GET_CODE (src) != PLUS
|| XEXP (src, 1) != stack_pointer_rtx)
abort ();
if (GET_CODE (XEXP (src, 0)) != REG
|| (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg)
abort ();
if (cfa_reg != STACK_POINTER_REGNUM)
abort ();
cfa_store_reg = REGNO (dest);
cfa_store_offset = cfa_offset - cfa_temp_value;
}
break;
case CONST_INT:
cfa_temp_reg = REGNO (dest);
cfa_temp_value = INTVAL (src);
break;
case IOR:
if (GET_CODE (XEXP (src, 0)) != REG
|| (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg
|| (unsigned) REGNO (dest) != cfa_temp_reg
|| GET_CODE (XEXP (src, 1)) != CONST_INT)
abort ();
cfa_temp_value |= INTVAL (XEXP (src, 1));
break;
default:
abort ();
}
dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
break;
case MEM:
if (GET_CODE (src) != REG)
abort ();
switch (GET_CODE (XEXP (dest, 0)))
{
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:
offset = INTVAL (XEXP (XEXP (dest, 0), 1));
if (GET_CODE (XEXP (dest, 0)) == MINUS)
offset = -offset;
if (cfa_store_reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
abort ();
offset -= cfa_store_offset;
break;
case REG:
if (cfa_store_reg != (unsigned) REGNO (XEXP (dest, 0)))
abort();
offset = -cfa_store_offset;
break;
default:
abort ();
}
dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
dwarf2out_reg_save (label, REGNO (src), offset);
break;
default:
abort ();
}
}
void
dwarf2out_frame_debug (insn)
rtx insn;
{
char *label;
rtx src;
if (insn == NULL_RTX)
{
lookup_cfa (&cfa_reg, &cfa_offset);
if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM))
abort ();
cfa_reg = STACK_POINTER_REGNUM;
cfa_store_reg = cfa_reg;
cfa_store_offset = cfa_offset;
cfa_temp_reg = -1;
cfa_temp_value = 0;
return;
}
if (! RTX_FRAME_RELATED_P (insn))
{
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 inline unsigned long
size_of_uleb128 (value)
register unsigned long value;
{
register unsigned long size = 0;
register unsigned byte;
do
{
byte = (value & 0x7f);
value >>= 7;
size += 1;
}
while (value != 0);
return size;
}
static inline unsigned long
size_of_sleb128 (value)
register long value;
{
register unsigned long size = 0;
register unsigned byte;
do
{
byte = (value & 0x7f);
value >>= 7;
size += 1;
}
while (!(((value == 0) && ((byte & 0x40) == 0))
|| ((value == -1) && ((byte & 0x40) != 0))));
return size;
}
static void
output_uleb128 (value)
register unsigned long value;
{
unsigned long save_value = value;
fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
do
{
register unsigned byte = (value & 0x7f);
value >>= 7;
if (value != 0)
byte |= 0x80;
fprintf (asm_out_file, "0x%x", byte);
if (value != 0)
fprintf (asm_out_file, ",");
}
while (value != 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value);
}
static void
output_sleb128 (value)
register long value;
{
register int more;
register unsigned byte;
long save_value = value;
fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
do
{
byte = (value & 0x7f);
value >>= 7;
more = !((((value == 0) && ((byte & 0x40) == 0))
|| ((value == -1) && ((byte & 0x40) != 0))));
if (more)
byte |= 0x80;
fprintf (asm_out_file, "0x%x", byte);
if (more)
fprintf (asm_out_file, ",");
}
while (more);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value);
}
static void
output_cfi (cfi, fde)
register dw_cfi_ref cfi;
register dw_fde_ref fde;
{
if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f));
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx",
ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
fputc ('\n', asm_out_file);
}
else if (cfi->dw_cfi_opc == DW_CFA_offset)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx",
ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
fputc ('\n', asm_out_file);
}
else if (cfi->dw_cfi_opc == DW_CFA_restore)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
cfi->dw_cfi_opc
| (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx",
ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
dwarf_cfi_name (cfi->dw_cfi_opc));
fputc ('\n', asm_out_file);
switch (cfi->dw_cfi_opc)
{
case DW_CFA_set_loc:
ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr);
fputc ('\n', asm_out_file);
break;
case DW_CFA_advance_loc1:
ASM_OUTPUT_DWARF_DELTA1 (asm_out_file,
cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label);
fputc ('\n', asm_out_file);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc2:
ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label);
fputc ('\n', asm_out_file);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc4:
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
cfi->dw_cfi_oprnd1.dw_cfi_addr,
fde->dw_fde_current_label);
fputc ('\n', asm_out_file);
fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
#ifdef MIPS_DEBUGGING_INFO
case DW_CFA_MIPS_advance_loc8:
abort ();
break;
#endif
case DW_CFA_offset_extended:
case DW_CFA_GNU_negative_offset_extended:
case DW_CFA_def_cfa:
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
fputc ('\n', asm_out_file);
break;
case DW_CFA_restore_extended:
case DW_CFA_undefined:
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
break;
case DW_CFA_same_value:
case DW_CFA_def_cfa_register:
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
break;
case DW_CFA_register:
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
fputc ('\n', asm_out_file);
break;
case DW_CFA_def_cfa_offset:
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
fputc ('\n', asm_out_file);
break;
case DW_CFA_GNU_window_save:
break;
case DW_CFA_GNU_args_size:
output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
fputc ('\n', asm_out_file);
break;
default:
break;
}
}
}
#if !defined (EH_FRAME_SECTION)
#if defined (EH_FRAME_SECTION_ASM_OP)
#define EH_FRAME_SECTION() eh_frame_section();
#else
#if defined (ASM_OUTPUT_SECTION_NAME)
#define EH_FRAME_SECTION() \
do { \
named_section (NULL_TREE, ".eh_frame", 0); \
} while (0)
#endif
#endif
#endif
#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP)
#undef EH_FRAME_SECTION
#endif
static void
output_call_frame_info (for_eh)
int for_eh;
{
register unsigned long i;
register dw_fde_ref fde;
register dw_cfi_ref cfi;
char l1[20], l2[20];
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
char ld[20];
#endif
int eh_ptr = for_eh && exception_table_p ();
#ifdef TRACE_DWARF2_UNWIND
int flag_debug_asm_saved = flag_debug_asm ;
flag_debug_asm = 1 ;
#endif
fputc ('\n', asm_out_file);
if (flag_debug_asm)
app_enable ();
if (for_eh)
{
#ifdef EH_FRAME_SECTION
EH_FRAME_SECTION ();
#else
tree label = get_file_function_name ('F');
force_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
assemble_label ("__FRAME_BEGIN__");
}
else
ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
if (for_eh)
ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
else
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
#else
if (for_eh)
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
else
ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
#endif
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Length of Common Information Entry",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_LABEL (asm_out_file, l1);
if (for_eh)
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
else
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
if (! for_eh && DWARF_OFFSET_SIZE == 8)
{
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
fputc ('\n', asm_out_file);
}
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
if (eh_ptr)
{
if (flag_debug_asm)
{
ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
}
else
{
ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
}
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s pointer to exception region info",
ASM_COMMENT_START);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
ASM_COMMENT_START);
}
fputc ('\n', asm_out_file);
output_uleb128 (1);
if (flag_debug_asm)
fprintf (asm_out_file, " (CIE Code Alignment Factor)");
fputc ('\n', asm_out_file);
output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
if (flag_debug_asm)
fprintf (asm_out_file, " (CIE Data Alignment Factor)");
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
output_cfi (cfi, NULL);
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
ASM_OUTPUT_LABEL (asm_out_file, l2);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
#endif
for (i = 0; i < fde_table_in_use; ++i)
{
fde = &fde_table[i];
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);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2);
if (for_eh)
ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
else
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
#else
if (for_eh)
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
else
ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
#endif
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_LABEL (asm_out_file, l1);
if (for_eh)
ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l1, "__FRAME_BEGIN__");
else
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
fde->dw_fde_end, fde->dw_fde_begin);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
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);
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
ASM_OUTPUT_LABEL (asm_out_file, l2);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
#endif
}
#ifdef DWARF2_END_OF_SECTION
DWARF2_END_OF_SECTION(asm_out_file, flag_debug_asm) ;
#endif
#ifndef EH_FRAME_SECTION
if (for_eh)
{
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
fputc ('\n', asm_out_file);
}
#endif
#ifdef MIPS_DEBUGGING_INFO
ASM_OUTPUT_ALIGN (asm_out_file, 0);
#endif
if (flag_debug_asm)
app_disable ();
#ifdef TRACE_DWARF2_UNWIND
flag_debug_asm = flag_debug_asm_saved ;
#endif
}
void
dwarf2out_begin_prologue ()
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
register dw_fde_ref fde;
++current_funcdef_number;
function_section (current_function_decl);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
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;
args_size = old_args_size = 0;
}
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) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
fde_table_allocated = FDE_TABLE_INCREMENT;
fde_table_in_use = 0;
#ifdef DWARF2_UNWIND_INFO
#ifdef DWARF2_TARGET_CALLING_CONVENTION
DWARF2_TARGET_CALLING_CONVENTION()
#else
dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
initial_return_save (INCOMING_RETURN_ADDR_RTX);
#endif
#endif
}
void
dwarf2out_frame_finish ()
{
#ifdef MIPS_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG)
output_call_frame_info (0);
if (flag_exceptions && ! exceptions_via_longjmp)
output_call_frame_info (1);
#else
if (write_symbols == DWARF2_DEBUG
|| (flag_exceptions && ! exceptions_via_longjmp && frame_was_required))
output_call_frame_info (1);
#endif
}
#endif
#ifdef DWARF2_DEBUGGING_INFO
extern char *getpwd PROTO((void));
typedef enum
{
dw_val_class_addr,
dw_val_class_loc,
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 long int dw_offset;
typedef struct die_struct *dw_die_ref;
typedef struct dw_attr_struct *dw_attr_ref;
typedef struct dw_val_struct *dw_val_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 dw_loc_descr_struct *dw_loc_descr_ref;
typedef struct pubname_struct *pubname_ref;
typedef dw_die_ref *arange_ref;
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_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_val_struct
{
dw_val_class val_class;
union
{
char *val_addr;
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;
dw_die_ref val_die_ref;
unsigned val_fde_index;
char *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;
}
dw_loc_descr_node;
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;
dw_attr_ref die_attr;
dw_attr_ref die_attr_last;
dw_die_ref die_parent;
dw_die_ref die_child;
dw_die_ref die_child_last;
dw_die_ref die_sib;
dw_offset die_offset;
unsigned long die_abbrev;
}
die_node;
typedef struct pubname_struct
{
dw_die_ref die;
char * name;
}
pubname_entry;
typedef struct limbo_die_struct
{
dw_die_ref die;
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;
extern char *version_string;
extern char *language_string;
#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, PTR_SIZE * 2) - DWARF_OFFSET_SIZE)
#ifndef DWARF_LINE_MIN_INSTR_LENGTH
#define DWARF_LINE_MIN_INSTR_LENGTH 4
#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;
static char **file_table;
static unsigned file_table_allocated;
static unsigned file_table_in_use;
#define FILE_TABLE_INCREMENT 64
static char *primary_filename;
static unsigned next_block_number = 2;
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
typedef struct decl_scope_struct
{
tree scope;
int previous;
}
decl_scope_node;
static decl_scope_node *decl_scope_table;
static int decl_scope_table_allocated;
static int decl_scope_depth;
#define DECL_SCOPE_TABLE_INCREMENT 64
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 arange_ref arange_table;
static unsigned arange_table_allocated;
static unsigned arange_table_in_use;
#define ARANGE_TABLE_INCREMENT 64
static tree *pending_types_list;
static unsigned pending_types_allocated;
static unsigned pending_types;
#define PENDING_TYPES_INCREMENT 64
static tree *incomplete_types_list;
static unsigned incomplete_types_allocated;
static unsigned incomplete_types;
#define INCOMPLETE_TYPES_INCREMENT 64
static int current_function_has_inlines;
#if 0 && defined (MIPS_DEBUGGING_INFO)
static int comp_unit_has_inlines;
#endif
static tree dwarf_last_decl;
static void addr_const_to_string PROTO((dyn_string_t, rtx));
static char *addr_to_string PROTO((rtx));
static int is_pseudo_reg PROTO((rtx));
static tree type_main_variant PROTO((tree));
static int is_tagged_type PROTO((tree));
static char *dwarf_tag_name PROTO((unsigned));
static char *dwarf_attr_name PROTO((unsigned));
static char *dwarf_form_name PROTO((unsigned));
static char *dwarf_stack_op_name PROTO((unsigned));
#if 0
static char *dwarf_type_encoding_name PROTO((unsigned));
#endif
static tree decl_ultimate_origin PROTO((tree));
static tree block_ultimate_origin PROTO((tree));
static tree decl_class_context PROTO((tree));
static void add_dwarf_attr PROTO((dw_die_ref, dw_attr_ref));
static void add_AT_flag PROTO((dw_die_ref,
enum dwarf_attribute,
unsigned));
static void add_AT_int PROTO((dw_die_ref,
enum dwarf_attribute, long));
static void add_AT_unsigned PROTO((dw_die_ref,
enum dwarf_attribute,
unsigned long));
static void add_AT_long_long PROTO((dw_die_ref,
enum dwarf_attribute,
unsigned long, unsigned long));
static void add_AT_float PROTO((dw_die_ref,
enum dwarf_attribute,
unsigned, long *));
static void add_AT_string PROTO((dw_die_ref,
enum dwarf_attribute, char *));
static void add_AT_die_ref PROTO((dw_die_ref,
enum dwarf_attribute,
dw_die_ref));
static void add_AT_fde_ref PROTO((dw_die_ref,
enum dwarf_attribute,
unsigned));
static void add_AT_loc PROTO((dw_die_ref,
enum dwarf_attribute,
dw_loc_descr_ref));
static void add_AT_addr PROTO((dw_die_ref,
enum dwarf_attribute, char *));
static void add_AT_lbl_id PROTO((dw_die_ref,
enum dwarf_attribute, char *));
static void add_AT_lbl_offset PROTO((dw_die_ref,
enum dwarf_attribute, char *));
static int is_extern_subr_die PROTO((dw_die_ref));
static dw_attr_ref get_AT PROTO((dw_die_ref,
enum dwarf_attribute));
static char *get_AT_low_pc PROTO((dw_die_ref));
static char *get_AT_hi_pc PROTO((dw_die_ref));
static char *get_AT_string PROTO((dw_die_ref,
enum dwarf_attribute));
static int get_AT_flag PROTO((dw_die_ref,
enum dwarf_attribute));
static unsigned get_AT_unsigned PROTO((dw_die_ref,
enum dwarf_attribute));
static int is_c_family PROTO((void));
static int is_fortran PROTO((void));
static void remove_AT PROTO((dw_die_ref,
enum dwarf_attribute));
static void remove_children PROTO((dw_die_ref));
static void add_child_die PROTO((dw_die_ref, dw_die_ref));
static dw_die_ref new_die PROTO((enum dwarf_tag, dw_die_ref));
static dw_die_ref lookup_type_die PROTO((tree));
static void equate_type_number_to_die PROTO((tree, dw_die_ref));
static dw_die_ref lookup_decl_die PROTO((tree));
static void equate_decl_number_to_die PROTO((tree, dw_die_ref));
static dw_loc_descr_ref new_loc_descr PROTO((enum dwarf_location_atom,
unsigned long, unsigned long));
static void add_loc_descr PROTO((dw_loc_descr_ref *,
dw_loc_descr_ref));
static void print_spaces PROTO((FILE *));
static void print_die PROTO((dw_die_ref, FILE *));
static void print_dwarf_line_table PROTO((FILE *));
static void add_sibling_attributes PROTO((dw_die_ref));
static void build_abbrev_table PROTO((dw_die_ref));
static unsigned long size_of_string PROTO((char *));
static unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref));
static unsigned long size_of_locs PROTO((dw_loc_descr_ref));
static int constant_size PROTO((long unsigned));
static unsigned long size_of_die PROTO((dw_die_ref));
static void calc_die_sizes PROTO((dw_die_ref));
static unsigned long size_of_line_prolog PROTO((void));
static unsigned long size_of_line_info PROTO((void));
static unsigned long size_of_pubnames PROTO((void));
static unsigned long size_of_aranges PROTO((void));
static enum dwarf_form value_format PROTO((dw_val_ref));
static void output_value_format PROTO((dw_val_ref));
static void output_abbrev_section PROTO((void));
static void output_loc_operands PROTO((dw_loc_descr_ref));
static unsigned long sibling_offset PROTO((dw_die_ref));
static void output_die PROTO((dw_die_ref));
static void output_compilation_unit_header PROTO((void));
static char *dwarf2_name PROTO((tree, int));
static void add_pubname PROTO((tree, dw_die_ref));
static void output_pubnames PROTO((void));
static void add_arange PROTO((tree, dw_die_ref));
static void output_aranges PROTO((void));
static void output_line_info PROTO((void));
static int is_body_block PROTO((tree));
static dw_die_ref base_type_die PROTO((tree));
static tree root_type PROTO((tree));
static int is_base_type PROTO((tree));
static dw_die_ref modified_type_die PROTO((tree, int, int, dw_die_ref));
static int type_is_enum PROTO((tree));
static dw_loc_descr_ref reg_loc_descriptor PROTO((rtx));
static dw_loc_descr_ref based_loc_descr PROTO((unsigned, long));
static int is_based_loc PROTO((rtx));
static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx));
static dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx));
static dw_loc_descr_ref loc_descriptor PROTO((rtx));
static unsigned ceiling PROTO((unsigned, unsigned));
static tree field_type PROTO((tree));
static unsigned simple_type_align_in_bits PROTO((tree));
static unsigned simple_type_size_in_bits PROTO((tree));
static unsigned field_byte_offset PROTO((tree));
static void add_AT_location_description PROTO((dw_die_ref,
enum dwarf_attribute, rtx));
static void add_data_member_location_attribute PROTO((dw_die_ref, tree));
static void add_const_value_attribute PROTO((dw_die_ref, rtx));
static void add_location_or_const_value_attribute PROTO((dw_die_ref, tree));
static void add_name_attribute PROTO((dw_die_ref, char *));
static void add_bound_info PROTO((dw_die_ref,
enum dwarf_attribute, tree));
static void add_subscript_info PROTO((dw_die_ref, tree));
static void add_byte_size_attribute PROTO((dw_die_ref, tree));
static void add_bit_offset_attribute PROTO((dw_die_ref, tree));
static void add_bit_size_attribute PROTO((dw_die_ref, tree));
static void add_prototyped_attribute PROTO((dw_die_ref, tree));
static void add_abstract_origin_attribute PROTO((dw_die_ref, tree));
static void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree));
static void add_src_coords_attributes PROTO((dw_die_ref, tree));
static void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree));
static void push_decl_scope PROTO((tree));
static dw_die_ref scope_die_for PROTO((tree, dw_die_ref));
static void pop_decl_scope PROTO((void));
static void add_type_attribute PROTO((dw_die_ref, tree, int, int,
dw_die_ref));
static char *type_tag PROTO((tree));
static tree member_declared_type PROTO((tree));
#if 0
static char *decl_start_label PROTO((tree));
#endif
static void gen_array_type_die PROTO((tree, dw_die_ref));
static void gen_set_type_die PROTO((tree, dw_die_ref));
#if 0
static void gen_entry_point_die PROTO((tree, dw_die_ref));
#endif
static void pend_type PROTO((tree));
static void output_pending_types_for_scope PROTO((dw_die_ref));
static void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref));
static void gen_inlined_structure_type_die PROTO((tree, dw_die_ref));
static void gen_inlined_union_type_die PROTO((tree, dw_die_ref));
static void gen_enumeration_type_die PROTO((tree, dw_die_ref));
static dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref));
static void gen_unspecified_parameters_die PROTO((tree, dw_die_ref));
static void gen_formal_types_die PROTO((tree, dw_die_ref));
static void gen_subprogram_die PROTO((tree, dw_die_ref));
static void gen_variable_die PROTO((tree, dw_die_ref));
static void gen_label_die PROTO((tree, dw_die_ref));
static void gen_lexical_block_die PROTO((tree, dw_die_ref, int));
static void gen_inlined_subroutine_die PROTO((tree, dw_die_ref, int));
static void gen_field_die PROTO((tree, dw_die_ref));
static void gen_ptr_to_mbr_type_die PROTO((tree, dw_die_ref));
static void gen_compile_unit_die PROTO((char *));
static void gen_string_type_die PROTO((tree, dw_die_ref));
static void gen_inheritance_die PROTO((tree, dw_die_ref));
static void gen_member_die PROTO((tree, dw_die_ref));
static void gen_struct_or_union_type_die PROTO((tree, dw_die_ref));
static void gen_subroutine_type_die PROTO((tree, dw_die_ref));
static void gen_typedef_die PROTO((tree, dw_die_ref));
static void gen_type_die PROTO((tree, dw_die_ref));
static void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref));
static void gen_block_die PROTO((tree, dw_die_ref, int));
static void decls_for_scope PROTO((tree, dw_die_ref, int));
static int is_redundant_typedef PROTO((tree));
static void gen_decl_die PROTO((tree, dw_die_ref));
static unsigned lookup_filename PROTO((char *));
#ifndef DEBUG_INFO_SECTION
#define DEBUG_INFO_SECTION ".debug_info"
#endif
#ifndef ABBREV_SECTION
#define ABBREV_SECTION ".debug_abbrev"
#endif
#ifndef ARANGES_SECTION
#define ARANGES_SECTION ".debug_aranges"
#endif
#ifndef DW_MACINFO_SECTION
#define DW_MACINFO_SECTION ".debug_macinfo"
#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
#ifndef LOC_SECTION
#define LOC_SECTION ".debug_loc"
#endif
#ifndef PUBNAMES_SECTION
#define PUBNAMES_SECTION ".debug_pubnames"
#endif
#ifndef STR_SECTION
#define STR_SECTION ".debug_str"
#endif
#ifndef TEXT_SECTION
#define TEXT_SECTION ".text"
#endif
#ifndef DATA_SECTION
#define DATA_SECTION ".data"
#endif
#ifndef BSS_SECTION
#define BSS_SECTION ".bss"
#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 ABBREV_SECTION_LABEL
#define ABBREV_SECTION_LABEL "Ldebug_abbrev"
#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];
#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 INSN_LABEL_FMT
#define INSN_LABEL_FMT "LI%u_"
#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
#ifndef ASM_NAME_TO_STRING
#define ASM_NAME_TO_STRING(STR, NAME) \
do { \
if ((NAME)[0] == '*') \
dyn_string_append (STR, NAME + 1); \
else \
{ \
char *newstr; \
STRIP_NAME_ENCODING (newstr, NAME); \
dyn_string_append (STR, user_label_prefix); \
dyn_string_append (STR, newstr); \
} \
} \
while (0)
#endif
static void
addr_const_to_string (str, x)
dyn_string_t str;
rtx x;
{
char buf1[256];
restart:
switch (GET_CODE (x))
{
case PC:
if (flag_pic)
dyn_string_append (str, ",");
else
abort ();
break;
case SYMBOL_REF:
ASM_NAME_TO_STRING (str, XSTR (x, 0));
break;
case LABEL_REF:
ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
ASM_NAME_TO_STRING (str, buf1);
break;
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x));
ASM_NAME_TO_STRING (str, buf1);
break;
case CONST_INT:
sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
dyn_string_append (str, buf1);
break;
case CONST:
addr_const_to_string (str, XEXP (x, 0));
break;
case CONST_DOUBLE:
if (GET_MODE (x) == VOIDmode)
{
if (CONST_DOUBLE_HIGH (x))
sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
else if (CONST_DOUBLE_LOW (x) < 0)
sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
else
sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
CONST_DOUBLE_LOW (x));
dyn_string_append (str, buf1);
}
else
output_operand_lossage ("floating constant misused");
break;
case PLUS:
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
addr_const_to_string (str, XEXP (x, 1));
if (INTVAL (XEXP (x, 0)) >= 0)
dyn_string_append (str, "+");
addr_const_to_string (str, XEXP (x, 0));
}
else
{
addr_const_to_string (str, XEXP (x, 0));
if (INTVAL (XEXP (x, 1)) >= 0)
dyn_string_append (str, "+");
addr_const_to_string (str, XEXP (x, 1));
}
break;
case MINUS:
x = simplify_subtraction (x);
if (GET_CODE (x) != MINUS)
goto restart;
addr_const_to_string (str, XEXP (x, 0));
dyn_string_append (str, "-");
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < 0)
{
dyn_string_append (str, ASM_OPEN_PAREN);
addr_const_to_string (str, XEXP (x, 1));
dyn_string_append (str, ASM_CLOSE_PAREN);
}
else
addr_const_to_string (str, XEXP (x, 1));
break;
case ZERO_EXTEND:
case SIGN_EXTEND:
addr_const_to_string (str, XEXP (x, 0));
break;
default:
output_operand_lossage ("invalid expression as operand");
}
}
static char *
addr_to_string (x)
rtx x;
{
dyn_string_t ds = dyn_string_new (256);
char *s;
addr_const_to_string (ds, x);
s = ds->s;
free (ds);
return s;
}
static inline int
is_pseudo_reg (rtl)
register rtx rtl;
{
return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
|| ((GET_CODE (rtl) == SUBREG)
&& (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
}
static inline tree
type_main_variant (type)
register 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)
register tree type;
{
register enum tree_code code = TREE_CODE (type);
return (code == RECORD_TYPE || code == UNION_TYPE
|| code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
}
static char *
dwarf_tag_name (tag)
register 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";
default:
return "DW_TAG_<unknown>";
}
}
static char *
dwarf_attr_name (attr)
register 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_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";
default:
return "DW_AT_<unknown>";
}
}
static char *
dwarf_form_name (form)
register 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>";
}
}
static char *
dwarf_stack_op_name (op)
register 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>";
}
}
#if 0
static char *
dwarf_type_encoding_name (enc)
register 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)
register tree decl;
{
#ifdef ENABLE_CHECKING
if (DECL_FROM_INLINE (DECL_ORIGIN (decl)))
abort ();
#endif
return DECL_ABSTRACT_ORIGIN (decl);
}
static tree
block_ultimate_origin (block)
register tree block;
{
register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
if (immediate_origin == NULL_TREE)
return NULL_TREE;
else
{
register tree ret_val;
register 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 && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
context = NULL_TREE;
return context;
}
static inline void
add_dwarf_attr (die, attr)
register dw_die_ref die;
register dw_attr_ref attr;
{
if (die != NULL && attr != NULL)
{
if (die->die_attr == NULL)
{
die->die_attr = attr;
die->die_attr_last = attr;
}
else
{
die->die_attr_last->dw_attr_next = attr;
die->die_attr_last = attr;
}
}
}
static inline void
add_AT_flag (die, attr_kind, flag)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register unsigned flag;
{
register 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 void
add_AT_int (die, attr_kind, int_val)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register long int int_val;
{
register 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 void
add_AT_unsigned (die, attr_kind, unsigned_val)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register unsigned long unsigned_val;
{
register 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 void
add_AT_long_long (die, attr_kind, val_hi, val_low)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register unsigned long val_hi;
register unsigned long val_low;
{
register 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)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register unsigned length;
register long *array;
{
register 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)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register char *str;
{
register 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_str;
attr->dw_attr_val.v.val_str = xstrdup (str);
add_dwarf_attr (die, attr);
}
static inline void
add_AT_die_ref (die, attr_kind, targ_die)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register dw_die_ref targ_die;
{
register 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 = targ_die;
add_dwarf_attr (die, attr);
}
static inline void
add_AT_fde_ref (die, attr_kind, targ_fde)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register unsigned targ_fde;
{
register 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)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register dw_loc_descr_ref loc;
{
register 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 void
add_AT_addr (die, attr_kind, addr)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
char *addr;
{
register 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 void
add_AT_lbl_id (die, attr_kind, lbl_id)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register char *lbl_id;
{
register 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)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
register char *label;
{
register 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 = label;
add_dwarf_attr (die, attr);
}
static inline int
is_extern_subr_die (die)
register dw_die_ref die;
{
register dw_attr_ref a;
register int is_subr = FALSE;
register int is_extern = FALSE;
if (die != NULL && die->die_tag == DW_TAG_subprogram)
{
is_subr = TRUE;
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
{
if (a->dw_attr == DW_AT_external
&& a->dw_attr_val.val_class == dw_val_class_flag
&& a->dw_attr_val.v.val_flag != 0)
{
is_extern = TRUE;
break;
}
}
}
return is_subr && is_extern;
}
static inline dw_attr_ref
get_AT (die, attr_kind)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
{
register dw_attr_ref a;
register 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;
if (a->dw_attr == DW_AT_specification
|| a->dw_attr == DW_AT_abstract_origin)
spec = a->dw_attr_val.v.val_die_ref;
}
if (spec)
return get_AT (spec, attr_kind);
}
return NULL;
}
static inline char *
get_AT_low_pc (die)
register dw_die_ref die;
{
register dw_attr_ref a = get_AT (die, DW_AT_low_pc);
if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
return a->dw_attr_val.v.val_lbl_id;
return NULL;
}
static inline char *
get_AT_hi_pc (die)
register dw_die_ref die;
{
register dw_attr_ref a = get_AT (die, DW_AT_high_pc);
if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
return a->dw_attr_val.v.val_lbl_id;
return NULL;
}
static inline char *
get_AT_string (die, attr_kind)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
{
register dw_attr_ref a = get_AT (die, attr_kind);
if (a && a->dw_attr_val.val_class == dw_val_class_str)
return a->dw_attr_val.v.val_str;
return NULL;
}
static inline int
get_AT_flag (die, attr_kind)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
{
register dw_attr_ref a = get_AT (die, attr_kind);
if (a && a->dw_attr_val.val_class == dw_val_class_flag)
return a->dw_attr_val.v.val_flag;
return -1;
}
static inline unsigned
get_AT_unsigned (die, attr_kind)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
{
register dw_attr_ref a = get_AT (die, attr_kind);
if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const)
return a->dw_attr_val.v.val_unsigned;
return 0;
}
static inline int
is_c_family ()
{
register 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_fortran ()
{
register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
}
static inline void
remove_AT (die, attr_kind)
register dw_die_ref die;
register enum dwarf_attribute attr_kind;
{
register dw_attr_ref a;
register dw_attr_ref removed = NULL;;
if (die != NULL)
{
if (die->die_attr->dw_attr == attr_kind)
{
removed = die->die_attr;
if (die->die_attr_last == die->die_attr)
die->die_attr_last = NULL;
die->die_attr = die->die_attr->dw_attr_next;
}
else
for (a = die->die_attr; a->dw_attr_next != NULL;
a = a->dw_attr_next)
if (a->dw_attr_next->dw_attr == attr_kind)
{
removed = a->dw_attr_next;
if (die->die_attr_last == a->dw_attr_next)
die->die_attr_last = a;
a->dw_attr_next = a->dw_attr_next->dw_attr_next;
break;
}
if (removed != 0)
free (removed);
}
}
static inline void
remove_children (die)
register dw_die_ref die;
{
register dw_die_ref child_die = die->die_child;
die->die_child = NULL;
die->die_child_last = NULL;
while (child_die != NULL)
{
register dw_die_ref tmp_die = child_die;
register dw_attr_ref a;
child_die = child_die->die_sib;
for (a = tmp_die->die_attr; a != NULL; )
{
register dw_attr_ref tmp_a = a;
a = a->dw_attr_next;
free (tmp_a);
}
free (tmp_die);
}
}
static inline void
add_child_die (die, child_die)
register dw_die_ref die;
register 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 = NULL;
if (die->die_child == NULL)
{
die->die_child = child_die;
die->die_child_last = child_die;
}
else
{
die->die_child_last->die_sib = child_die;
die->die_child_last = child_die;
}
}
}
static inline dw_die_ref
new_die (tag_value, parent_die)
register enum dwarf_tag tag_value;
register dw_die_ref parent_die;
{
register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node));
die->die_tag = tag_value;
die->die_abbrev = 0;
die->die_offset = 0;
die->die_child = NULL;
die->die_parent = NULL;
die->die_sib = NULL;
die->die_child_last = NULL;
die->die_attr = NULL;
die->die_attr_last = NULL;
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->next = limbo_die_list;
limbo_die_list = limbo_node;
}
return die;
}
static inline dw_die_ref
lookup_type_die (type)
register tree type;
{
return (dw_die_ref) TYPE_SYMTAB_POINTER (type);
}
static void
equate_type_number_to_die (type, type_die)
register tree type;
register dw_die_ref type_die;
{
TYPE_SYMTAB_POINTER (type) = (char *) type_die;
}
static inline dw_die_ref
lookup_decl_die (decl)
register tree decl;
{
register 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)
register tree decl;
register dw_die_ref decl_die;
{
register unsigned decl_id = DECL_UID (decl);
register unsigned 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);
bzero ((char *) &decl_die_table[decl_die_table_allocated],
(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 inline dw_loc_descr_ref
new_loc_descr (op, oprnd1, oprnd2)
register enum dwarf_location_atom op;
register unsigned long oprnd1;
register unsigned long oprnd2;
{
register dw_loc_descr_ref descr
= (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node));
descr->dw_loc_next = NULL;
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)
register dw_loc_descr_ref *list_head;
register dw_loc_descr_ref descr;
{
register dw_loc_descr_ref *d;
for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
;
*d = descr;
}
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;
{
register dw_attr_ref a;
register 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 (a->dw_attr_val.val_class)
{
case dw_val_class_addr:
fprintf (outfile, "address");
break;
case dw_val_class_loc:
fprintf (outfile, "location descriptor");
break;
case dw_val_class_const:
fprintf (outfile, "%ld", a->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned);
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", a->dw_attr_val.v.val_flag);
break;
case dw_val_class_die_ref:
if (a->dw_attr_val.v.val_die_ref != NULL)
fprintf (outfile, "die -> %lu",
a->dw_attr_val.v.val_die_ref->die_offset);
else
fprintf (outfile, "die -> <null>");
break;
case dw_val_class_lbl_id:
case dw_val_class_lbl_offset:
fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id);
break;
case dw_val_class_str:
if (a->dw_attr_val.v.val_str != NULL)
fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str);
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;
}
}
static void
print_dwarf_line_table (outfile)
FILE *outfile;
{
register unsigned i;
register 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[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);
print_dwarf_line_table (stderr);
}
static void
add_sibling_attributes(die)
register dw_die_ref die;
{
register dw_die_ref c;
register dw_attr_ref attr;
if (die != comp_unit_die && die->die_child != NULL)
{
attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
attr->dw_attr_next = NULL;
attr->dw_attr = DW_AT_sibling;
attr->dw_attr_val.val_class = dw_val_class_die_ref;
attr->dw_attr_val.v.val_die_ref = die->die_sib;
attr->dw_attr_next = die->die_attr;
if (die->die_attr == NULL)
die->die_attr_last = attr;
die->die_attr = attr;
}
for (c = die->die_child; c != NULL; c = c->die_sib)
add_sibling_attributes (c);
}
static void
build_abbrev_table (die)
register dw_die_ref die;
{
register unsigned long abbrev_id;
register unsigned long n_alloc;
register dw_die_ref c;
register dw_attr_ref d_attr, a_attr;
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
register 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->dw_attr_val)
!= value_format (&d_attr->dw_attr_val)))
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);
bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated],
(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 unsigned long
size_of_string (str)
register char *str;
{
return strlen (str) + 1;
}
static unsigned long
size_of_loc_descr (loc)
register dw_loc_descr_ref loc;
{
register unsigned long size = 1;
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
size += PTR_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)
register dw_loc_descr_ref loc;
{
register unsigned long size = 0;
for (; loc != NULL; loc = loc->dw_loc_next)
size += size_of_loc_descr (loc);
return size;
}
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)
register dw_die_ref die;
{
register unsigned long size = 0;
register dw_attr_ref a;
size += size_of_uleb128 (die->die_abbrev);
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
{
switch (a->dw_attr_val.val_class)
{
case dw_val_class_addr:
size += PTR_SIZE;
break;
case dw_val_class_loc:
{
register unsigned long lsize
= size_of_locs (a->dw_attr_val.v.val_loc);
size += constant_size (lsize);
size += lsize;
}
break;
case dw_val_class_const:
size += 4;
break;
case dw_val_class_unsigned_const:
size += constant_size (a->dw_attr_val.v.val_unsigned);
break;
case dw_val_class_long_long:
size += 1 + 8;
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 += PTR_SIZE;
break;
case dw_val_class_lbl_offset:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
size += size_of_string (a->dw_attr_val.v.val_str);
break;
default:
abort ();
}
}
return size;
}
static void
calc_die_sizes (die)
dw_die_ref die;
{
register 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 unsigned long
size_of_line_prolog ()
{
register unsigned long size;
register unsigned long ft_index;
size = DWARF_LINE_PROLOG_HEADER_SIZE;
size += DWARF_LINE_OPCODE_BASE - 1;
size += 1;
for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
{
size += size_of_string (file_table[ft_index]);
size += size_of_uleb128 (0);
size += size_of_uleb128 (0);
size += size_of_uleb128 (0);
}
size += 1;
return size;
}
static unsigned long
size_of_line_info ()
{
register unsigned long size;
register unsigned long lt_index;
register unsigned long current_line;
register long line_offset;
register long line_delta;
register unsigned long current_file;
register unsigned long function;
unsigned long size_of_set_address;
size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
size = 2;
size += DWARF_OFFSET_SIZE;
size += size_of_line_prolog ();
current_file = 1;
current_line = 1;
for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
{
register dw_line_info_ref line_info = &line_info_table[lt_index];
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file)
continue;
if (0)
size += 1 + 2;
else
size += size_of_set_address;
if (line_info->dw_file_num != current_file)
{
size += 1;
current_file = line_info->dw_file_num;
size += size_of_uleb128 (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))
size += 1;
else
{
size += 1;
size += size_of_sleb128 (line_offset);
size += 1;
}
}
}
if (0)
size += 1 + 2;
else
size += size_of_set_address;
size += 1 + size_of_uleb128 (1) + 1;
function = 0;
current_file = 1;
current_line = 1;
for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
{
register dw_separate_line_info_ref line_info
= &separate_line_info_table[lt_index];
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file
&& line_info->function == function)
goto cont;
if (function != line_info->function)
{
function = line_info->function;
size += size_of_set_address;
}
else
{
if (0)
size += 1 + 2;
else
size += size_of_set_address;
}
if (line_info->dw_file_num != current_file)
{
size += 1;
current_file = line_info->dw_file_num;
size += size_of_uleb128 (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))
size += 1;
else
{
size += 1;
size += size_of_sleb128 (line_offset);
size += 1;
}
}
cont:
++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;
if (0)
size += 1 + 2;
else
size += size_of_set_address;
size += 1 + size_of_uleb128 (1) + 1;
}
}
return size;
}
static unsigned long
size_of_pubnames ()
{
register unsigned long size;
register unsigned i;
size = DWARF_PUBNAMES_HEADER_SIZE;
for (i = 0; i < pubname_table_in_use; ++i)
{
register pubname_ref p = &pubname_table[i];
size += DWARF_OFFSET_SIZE + size_of_string (p->name);
}
size += DWARF_OFFSET_SIZE;
return size;
}
static unsigned long
size_of_aranges ()
{
register unsigned long size;
size = DWARF_ARANGES_HEADER_SIZE;
size += 2 * PTR_SIZE;
size += 2 * PTR_SIZE * arange_table_in_use;
size += 2 * PTR_SIZE;
return size;
}
static enum dwarf_form
value_format (v)
dw_val_ref v;
{
switch (v->val_class)
{
case dw_val_class_addr:
return DW_FORM_addr;
case dw_val_class_loc:
switch (constant_size (size_of_locs (v->v.val_loc)))
{
case 1:
return DW_FORM_block1;
case 2:
return DW_FORM_block2;
default:
abort ();
}
case dw_val_class_const:
return DW_FORM_data4;
case dw_val_class_unsigned_const:
switch (constant_size (v->v.val_unsigned))
{
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:
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 DW_FORM_string;
default:
abort ();
}
}
static void
output_value_format (v)
dw_val_ref v;
{
enum dwarf_form form = value_format (v);
output_uleb128 (form);
if (flag_debug_asm)
fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
fputc ('\n', asm_out_file);
}
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)
{
register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
output_uleb128 (abbrev_id);
if (flag_debug_asm)
fprintf (asm_out_file, " (abbrev code)");
fputc ('\n', asm_out_file);
output_uleb128 (abbrev->die_tag);
if (flag_debug_asm)
fprintf (asm_out_file, " (TAG: %s)",
dwarf_tag_name (abbrev->die_tag));
fputc ('\n', asm_out_file);
fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP,
abbrev->die_child != NULL ? DW_children_yes : DW_children_no);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s",
ASM_COMMENT_START,
(abbrev->die_child != NULL
? "DW_children_yes" : "DW_children_no"));
fputc ('\n', asm_out_file);
for (a_attr = abbrev->die_attr; a_attr != NULL;
a_attr = a_attr->dw_attr_next)
{
output_uleb128 (a_attr->dw_attr);
if (flag_debug_asm)
fprintf (asm_out_file, " (%s)",
dwarf_attr_name (a_attr->dw_attr));
fputc ('\n', asm_out_file);
output_value_format (&a_attr->dw_attr_val);
}
fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
}
fprintf (asm_out_file, "\t%s\t0\n", ASM_BYTE_OP);
}
static void
output_loc_operands (loc)
register dw_loc_descr_ref loc;
{
register dw_val_ref val1 = &loc->dw_loc_oprnd1;
register dw_val_ref val2 = &loc->dw_loc_oprnd2;
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr);
fputc ('\n', asm_out_file);
break;
case DW_OP_const1u:
case DW_OP_const1s:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
fputc ('\n', asm_out_file);
break;
case DW_OP_const2u:
case DW_OP_const2s:
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_const4u:
case DW_OP_const4s:
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_const8u:
case DW_OP_const8s:
abort ();
fputc ('\n', asm_out_file);
break;
case DW_OP_constu:
output_uleb128 (val1->v.val_unsigned);
fputc ('\n', asm_out_file);
break;
case DW_OP_consts:
output_sleb128 (val1->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_pick:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_plus_uconst:
output_uleb128 (val1->v.val_unsigned);
fputc ('\n', asm_out_file);
break;
case DW_OP_skip:
case DW_OP_bra:
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
fputc ('\n', asm_out_file);
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:
output_sleb128 (val1->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_regx:
output_uleb128 (val1->v.val_unsigned);
fputc ('\n', asm_out_file);
break;
case DW_OP_fbreg:
output_sleb128 (val1->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_bregx:
output_uleb128 (val1->v.val_unsigned);
fputc ('\n', asm_out_file);
output_sleb128 (val2->v.val_int);
fputc ('\n', asm_out_file);
break;
case DW_OP_piece:
output_uleb128 (val1->v.val_unsigned);
fputc ('\n', asm_out_file);
break;
case DW_OP_deref_size:
case DW_OP_xderef_size:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
fputc ('\n', asm_out_file);
break;
default:
break;
}
}
static unsigned long
sibling_offset (die)
dw_die_ref die;
{
unsigned long offset;
if (die->die_child_last == NULL)
offset = die->die_offset + size_of_die (die);
else
offset = sibling_offset (die->die_child_last) + 1;
return offset;
}
static void
output_die (die)
register dw_die_ref die;
{
register dw_attr_ref a;
register dw_die_ref c;
register unsigned long ref_offset;
register unsigned long size;
register dw_loc_descr_ref loc;
output_uleb128 (die->die_abbrev);
if (flag_debug_asm)
fprintf (asm_out_file, " (DIE (0x%lx) %s)",
die->die_offset, dwarf_tag_name (die->die_tag));
fputc ('\n', asm_out_file);
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
{
switch (a->dw_attr_val.val_class)
{
case dw_val_class_addr:
ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
a->dw_attr_val.v.val_addr);
break;
case dw_val_class_loc:
size = size_of_locs (a->dw_attr_val.v.val_loc);
switch (constant_size (size))
{
case 1:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size);
break;
case 2:
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
break;
default:
abort ();
}
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s",
ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
fputc ('\n', asm_out_file);
for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
loc = loc->dw_loc_next)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
dwarf_stack_op_name (loc->dw_loc_opc));
fputc ('\n', asm_out_file);
output_loc_operands (loc);
}
break;
case dw_val_class_const:
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
switch (constant_size (a->dw_attr_val.v.val_unsigned))
{
case 1:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
a->dw_attr_val.v.val_unsigned);
break;
case 2:
ASM_OUTPUT_DWARF_DATA2 (asm_out_file,
a->dw_attr_val.v.val_unsigned);
break;
case 4:
ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
a->dw_attr_val.v.val_unsigned);
break;
case 8:
ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
a->dw_attr_val.v.val_long_long.hi,
a->dw_attr_val.v.val_long_long.low);
break;
default:
abort ();
}
break;
case dw_val_class_long_long:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s",
ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
a->dw_attr_val.v.val_long_long.hi,
a->dw_attr_val.v.val_long_long.low);
if (flag_debug_asm)
fprintf (asm_out_file,
"\t%s long long constant", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
break;
case dw_val_class_float:
{
register unsigned int i;
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
a->dw_attr_val.v.val_float.length * 4);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s",
ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
fputc ('\n', asm_out_file);
for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i)
{
ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
a->dw_attr_val.v.val_float.array[i]);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s fp constant word %u",
ASM_COMMENT_START, i);
fputc ('\n', asm_out_file);
}
break;
}
case dw_val_class_flag:
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag);
break;
case dw_val_class_die_ref:
if (a->dw_attr_val.v.val_die_ref != NULL)
ref_offset = a->dw_attr_val.v.val_die_ref->die_offset;
else if (a->dw_attr == DW_AT_sibling)
ref_offset = sibling_offset(die);
else
abort ();
ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset);
break;
case dw_val_class_fde_ref:
{
char l1[20];
ASM_GENERATE_INTERNAL_LABEL
(l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2);
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1);
fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE);
}
break;
case dw_val_class_lbl_id:
ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id);
break;
case dw_val_class_lbl_offset:
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, a->dw_attr_val.v.val_lbl_id);
break;
case dw_val_class_str:
if (flag_debug_asm)
ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str);
else
ASM_OUTPUT_ASCII (asm_out_file,
a->dw_attr_val.v.val_str,
(int) strlen (a->dw_attr_val.v.val_str) + 1);
break;
default:
abort ();
}
if (a->dw_attr_val.val_class != dw_val_class_loc
&& a->dw_attr_val.val_class != dw_val_class_long_long
&& a->dw_attr_val.val_class != dw_val_class_float)
{
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s %s",
ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
fputc ('\n', asm_out_file);
}
}
for (c = die->die_child; c != NULL; c = c->die_sib)
output_die (c);
if (die->die_child != NULL)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx",
ASM_COMMENT_START, die->die_offset);
fputc ('\n', asm_out_file);
}
}
static void
output_compilation_unit_header ()
{
ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, abbrev_section_label);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
static 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 ()
{
register unsigned i;
register unsigned long pubnames_length = size_of_pubnames ();
ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Length of Public Names Info.",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, debug_info_section_label);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
for (i = 0; i < pubname_table_in_use; ++i)
{
register pubname_ref pub = &pubname_table[i];
ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
if (flag_debug_asm)
{
ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name);
fprintf (asm_out_file, "%s external name", ASM_COMMENT_START);
}
else
{
ASM_OUTPUT_ASCII (asm_out_file, pub->name,
(int) strlen (pub->name) + 1);
}
fputc ('\n', asm_out_file);
}
ASM_OUTPUT_DWARF_DATA (asm_out_file, 0);
fputc ('\n', asm_out_file);
}
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
= (arange_ref) xrealloc (arange_table,
arange_table_allocated * sizeof (dw_die_ref));
}
arange_table[arange_table_in_use++] = die;
}
static void
output_aranges ()
{
register unsigned i;
register unsigned long aranges_length = size_of_aranges ();
ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Length of Address Ranges Info.",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_OFFSET (asm_out_file, debug_info_section_label);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Size of Segment Descriptor",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4);
if (PTR_SIZE == 8)
fprintf (asm_out_file, ",0,0");
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
ASM_COMMENT_START, 2 * PTR_SIZE);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_section_label);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label,
text_section_label);
if (flag_debug_asm)
fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
for (i = 0; i < arange_table_in_use; ++i)
{
dw_die_ref a = arange_table[i];
if (a->die_tag == DW_TAG_subprogram)
ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a));
else
{
char *name = get_AT_string (a, DW_AT_MIPS_linkage_name);
if (! name)
name = get_AT_string (a, DW_AT_name);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, name);
}
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
if (a->die_tag == DW_TAG_subprogram)
ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a),
get_AT_low_pc (a));
else
ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file,
get_AT_unsigned (a, DW_AT_byte_size));
if (flag_debug_asm)
fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
fputc ('\n', asm_out_file);
}
static void
output_line_info ()
{
char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
register unsigned opc;
register unsigned n_op_args;
register unsigned long ft_index;
register unsigned long lt_index;
register unsigned long current_line;
register long line_offset;
register long line_delta;
register unsigned long current_file;
register unsigned long function;
ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ());
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Length of Source Line Info.",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ());
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Minimum Instruction Length",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Default is_stmt_start flag",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
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;
}
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args",
ASM_COMMENT_START, opc, n_op_args);
fputc ('\n', asm_out_file);
}
if (flag_debug_asm)
fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
fputc ('\n', asm_out_file);
if (flag_debug_asm)
fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
{
if (flag_debug_asm)
{
ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]);
fprintf (asm_out_file, "%s File Entry: 0x%lx",
ASM_COMMENT_START, ft_index);
}
else
{
ASM_OUTPUT_ASCII (asm_out_file,
file_table[ft_index],
(int) strlen (file_table[ft_index]) + 1);
}
fputc ('\n', asm_out_file);
output_uleb128 (0);
fputc ('\n', asm_out_file);
output_uleb128 (0);
fputc ('\n', asm_out_file);
output_uleb128 (0);
fputc ('\n', asm_out_file);
}
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
fputc ('\n', asm_out_file);
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)
{
register dw_line_info_ref line_info = &line_info_table[lt_index];
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file)
continue;
ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
if (0)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_set_address",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1 + PTR_SIZE);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
fputc ('\n', asm_out_file);
}
strcpy (prev_line_label, line_label);
if (line_info->dw_file_num != current_file)
{
current_file = line_info->dw_file_num;
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (current_file);
if (flag_debug_asm)
fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
fputc ('\n', asm_out_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))
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
DWARF_LINE_OPCODE_BASE + line_delta);
if (flag_debug_asm)
fprintf (asm_out_file,
"\t%s line %ld", ASM_COMMENT_START, current_line);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s advance to line %ld",
ASM_COMMENT_START, current_line);
fputc ('\n', asm_out_file);
output_sleb128 (line_offset);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
}
if (0)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1 + PTR_SIZE);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label);
fputc ('\n', asm_out_file);
}
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
fputc ('\n', asm_out_file);
function = 0;
current_file = 1;
current_line = 1;
for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
{
register dw_separate_line_info_ref line_info
= &separate_line_info_table[lt_index];
if (line_info->dw_line_num == current_line
&& line_info->dw_file_num == current_file
&& line_info->function == function)
goto cont;
ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
lt_index);
if (function != line_info->function)
{
function = line_info->function;
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_set_address",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1 + PTR_SIZE);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
fputc ('\n', asm_out_file);
}
else
{
if (0)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
prev_line_label);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_set_address",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1 + PTR_SIZE);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
fputc ('\n', asm_out_file);
}
}
strcpy (prev_line_label, line_label);
if (line_info->dw_file_num != current_file)
{
current_file = line_info->dw_file_num;
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (current_file);
if (flag_debug_asm)
fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
fputc ('\n', asm_out_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))
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
DWARF_LINE_OPCODE_BASE + line_delta);
if (flag_debug_asm)
fprintf (asm_out_file,
"\t%s line %ld", ASM_COMMENT_START, current_line);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s advance to line %ld",
ASM_COMMENT_START, current_line);
fputc ('\n', asm_out_file);
output_sleb128 (line_offset);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
}
cont:
++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)
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
prev_line_label);
fputc ('\n', asm_out_file);
}
else
{
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_set_address",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1 + PTR_SIZE);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
fputc ('\n', asm_out_file);
}
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s DW_LNE_end_sequence",
ASM_COMMENT_START);
fputc ('\n', asm_out_file);
output_uleb128 (1);
fputc ('\n', asm_out_file);
ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
fputc ('\n', asm_out_file);
}
}
}
static inline int
is_body_block (stmt)
register tree stmt;
{
if (TREE_CODE (stmt) == BLOCK)
{
register tree parent = BLOCK_SUPERCONTEXT (stmt);
if (TREE_CODE (parent) == BLOCK)
{
register tree grandparent = BLOCK_SUPERCONTEXT (parent);
if (TREE_CODE (grandparent) == FUNCTION_DECL)
return 1;
}
}
return 0;
}
static dw_die_ref
base_type_die (type)
register tree type;
{
register dw_die_ref base_type_result;
register char *type_name;
register enum dwarf_type encoding;
register tree name = TYPE_NAME (type);
if (TREE_CODE (type) == ERROR_MARK
|| TREE_CODE (type) == VOID_TYPE)
return 0;
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
type_name = IDENTIFIER_POINTER (name);
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:
encoding = DW_ATE_complex_float;
break;
case BOOLEAN_TYPE:
encoding = DW_ATE_boolean;
break;
default:
abort ();
}
base_type_result = new_die (DW_TAG_base_type, comp_unit_die);
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)
register 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)
register 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 VECTOR_TYPE:
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:
return 0;
default:
abort ();
}
return 0;
}
static dw_die_ref
modified_type_die (type, is_const_type, is_volatile_type, context_die)
register tree type;
register int is_const_type;
register int is_volatile_type;
register dw_die_ref context_die;
{
register enum tree_code code = TREE_CODE (type);
register dw_die_ref mod_type_die = NULL;
register dw_die_ref sub_die = NULL;
register tree item_type = NULL;
if (code != ERROR_MARK)
{
type = build_type_variant (type, is_const_type, is_volatile_type);
mod_type_die = lookup_type_die (type);
if (mod_type_die)
return mod_type_die;
if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
{
tree dtype = TREE_TYPE (TYPE_NAME (type));
if (type == dtype)
{
gen_type_die (type, context_die);
mod_type_die = lookup_type_die (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 (type)),
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);
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);
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);
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);
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 ();
}
}
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)
register tree type;
{
return TREE_CODE (type) == ENUMERAL_TYPE;
}
static dw_loc_descr_ref
reg_loc_descriptor (rtl)
register rtx rtl;
{
register dw_loc_descr_ref loc_result = NULL;
register unsigned 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
based_loc_descr (reg, offset)
unsigned reg;
long int offset;
{
register dw_loc_descr_ref loc_result;
register 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)
register rtx rtl;
{
return (GET_CODE (rtl) == PLUS
&& ((GET_CODE (XEXP (rtl, 0)) == REG
&& GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
}
static dw_loc_descr_ref
mem_loc_descriptor (rtl)
register rtx rtl;
{
dw_loc_descr_ref mem_loc_result = NULL;
switch (GET_CODE (rtl))
{
case SUBREG:
rtl = XEXP (rtl, 0);
case REG:
mem_loc_result = based_loc_descr (reg_number (rtl), 0);
break;
case MEM:
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0));
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
case CONST:
case SYMBOL_REF:
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 = addr_to_string (rtl);
break;
case PLUS:
if (is_based_loc (rtl))
mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
INTVAL (XEXP (rtl, 1)));
else
{
add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0));
}
break;
case MULT:
add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
break;
case CONST_INT:
mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0);
break;
default:
abort ();
}
return mem_loc_result;
}
static dw_loc_descr_ref
concat_loc_descriptor (x0, x1)
register rtx x0, x1;
{
dw_loc_descr_ref cc_loc_result = NULL;
if (!is_pseudo_reg (x0)
&& (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0))))
add_loc_descr (&cc_loc_result, loc_descriptor (x0));
add_loc_descr (&cc_loc_result,
new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0));
if (!is_pseudo_reg (x1)
&& (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0))))
add_loc_descr (&cc_loc_result, loc_descriptor (x1));
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)
register rtx rtl;
{
dw_loc_descr_ref loc_result = NULL;
switch (GET_CODE (rtl))
{
case SUBREG:
rtl = XEXP (rtl, 0);
case REG:
loc_result = reg_loc_descriptor (rtl);
break;
case MEM:
loc_result = mem_loc_descriptor (XEXP (rtl, 0));
break;
case CONCAT:
loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
break;
default:
abort ();
}
return loc_result;
}
static inline unsigned
ceiling (value, boundary)
register unsigned value;
register unsigned boundary;
{
return (((value + boundary - 1) / boundary) * boundary);
}
static inline tree
field_type (decl)
register tree decl;
{
register 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)
register tree type;
{
return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
}
static inline unsigned
simple_type_size_in_bits (type)
register tree type;
{
if (TREE_CODE (type) == ERROR_MARK)
return BITS_PER_WORD;
else
{
register tree type_size_tree = TYPE_SIZE (type);
if (TREE_CODE (type_size_tree) != INTEGER_CST)
return TYPE_ALIGN (type);
return (unsigned) TREE_INT_CST_LOW (type_size_tree);
}
}
static unsigned
field_byte_offset (decl)
register tree decl;
{
register unsigned type_align_in_bytes;
register unsigned type_align_in_bits;
register unsigned type_size_in_bits;
register unsigned object_offset_in_align_units;
register unsigned object_offset_in_bits;
register unsigned object_offset_in_bytes;
register tree type;
register tree bitpos_tree;
register tree field_size_tree;
register unsigned bitpos_int;
register unsigned deepest_bitpos;
register unsigned field_size_in_bits;
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
if (TREE_CODE (decl) != FIELD_DECL)
abort ();
type = field_type (decl);
bitpos_tree = DECL_FIELD_BITPOS (decl);
field_size_tree = DECL_SIZE (decl);
if (TREE_CODE (bitpos_tree) != INTEGER_CST)
return 0;
bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
if (TREE_CODE (field_size_tree) != INTEGER_CST)
return 0;
field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree);
type_size_in_bits = simple_type_size_in_bits (type);
type_align_in_bits = simple_type_align_in_bits (type);
type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
deepest_bitpos = bitpos_int + field_size_in_bits;
object_offset_in_bits
= ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits;
object_offset_in_align_units = object_offset_in_bits / type_align_in_bits;
object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes;
return object_offset_in_bytes;
}
static void
add_AT_location_description (die, attr_kind, rtl)
dw_die_ref die;
enum dwarf_attribute attr_kind;
register rtx rtl;
{
if (is_pseudo_reg (rtl)
|| (GET_CODE (rtl) == MEM
&& is_pseudo_reg (XEXP (rtl, 0)))
|| (GET_CODE (rtl) == CONCAT
&& is_pseudo_reg (XEXP (rtl, 0))
&& is_pseudo_reg (XEXP (rtl, 1))))
return;
add_AT_loc (die, attr_kind, loc_descriptor (rtl));
}
static void
add_data_member_location_attribute (die, decl)
register dw_die_ref die;
register tree decl;
{
register unsigned long offset;
register dw_loc_descr_ref loc_descr;
register enum dwarf_location_atom op;
if (TREE_CODE (decl) == TREE_VEC)
offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl));
else
offset = field_byte_offset (decl);
#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)
register dw_die_ref die;
register rtx rtl;
{
switch (GET_CODE (rtl))
{
case CONST_INT:
add_AT_unsigned (die, DW_AT_const_value, (unsigned) INTVAL (rtl));
break;
case CONST_DOUBLE:
{
register enum machine_mode mode = GET_MODE (rtl);
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
register unsigned length = GET_MODE_SIZE (mode) / sizeof (long);
long array[4];
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
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, addr_to_string (rtl));
break;
case PLUS:
break;
default:
abort ();
}
}
static void
add_location_or_const_value_attribute (die, decl)
register dw_die_ref die;
register tree decl;
{
register rtx rtl;
register tree declared_type;
register tree passed_type;
if (TREE_CODE (decl) == ERROR_MARK)
return;
if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
abort ();
rtl = DECL_RTL (decl);
if (TREE_CODE (decl) == PARM_DECL)
{
if (rtl == NULL_RTX || is_pseudo_reg (rtl))
{
declared_type = type_main_variant (TREE_TYPE (decl));
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)
return;
rtl = eliminate_regs (rtl, 0, NULL_RTX);
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
leaf_renumber_regs_insn (rtl);
#endif
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 inline void
add_name_attribute (die, name_string)
register dw_die_ref die;
register char *name_string;
{
if (name_string != NULL && *name_string != 0)
add_AT_string (die, DW_AT_name, name_string);
}
static void
add_bound_info (subrange_die, bound_attr, bound)
register dw_die_ref subrange_die;
register enum dwarf_attribute bound_attr;
register tree bound;
{
register unsigned bound_value = 0;
if (contains_placeholder_p (bound))
return;
switch (TREE_CODE (bound))
{
case ERROR_MARK:
return;
case INTEGER_CST:
bound_value = TREE_INT_CST_LOW (bound);
if (bound_attr == DW_AT_lower_bound
&& ((is_c_family () && bound_value == 0)
|| (is_fortran () && bound_value == 1)))
;
else
add_AT_unsigned (subrange_die, bound_attr, bound_value);
break;
case CONVERT_EXPR:
case NOP_EXPR:
case NON_LVALUE_EXPR:
add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
break;
case SAVE_EXPR:
if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM)
{
register dw_die_ref ctx = lookup_decl_die (current_function_decl);
register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
register 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 MAX_EXPR:
case VAR_DECL:
case COMPONENT_REF:
break;
default:
abort ();
}
}
static void
add_subscript_info (type_die, type)
register dw_die_ref type_die;
register tree type;
{
#ifndef MIPS_DEBUGGING_INFO
register unsigned dimension_number;
#endif
register tree lower, upper;
register 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
register tree domain = TYPE_DOMAIN (type);
subrange_die = new_die (DW_TAG_subrange_type, type_die);
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);
}
else
{;}
#ifndef MIPS_DEBUGGING_INFO
}
#endif
}
static void
add_byte_size_attribute (die, tree_node)
dw_die_ref die;
register tree tree_node;
{
register 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)
register dw_die_ref die;
register tree decl;
{
register unsigned object_offset_in_bytes = field_byte_offset (decl);
register tree type = DECL_BIT_FIELD_TYPE (decl);
register tree bitpos_tree = DECL_FIELD_BITPOS (decl);
register unsigned bitpos_int;
register unsigned highest_order_object_bit_offset;
register unsigned highest_order_field_bit_offset;
register unsigned bit_offset;
if (!type
|| TREE_CODE (decl) != FIELD_DECL)
abort ();
if (TREE_CODE (bitpos_tree) != INTEGER_CST)
return;
bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
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
+= (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
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)
register dw_die_ref die;
register tree decl;
{
if (TREE_CODE (decl) != FIELD_DECL
|| ! DECL_BIT_FIELD_TYPE (decl))
abort ();
add_AT_unsigned (die, DW_AT_bit_size,
(unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)));
}
static inline void
add_prototyped_attribute (die, func_type)
register dw_die_ref die;
register 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)
register dw_die_ref die;
register tree origin;
{
dw_die_ref origin_die = NULL;
if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd')
origin_die = lookup_decl_die (origin);
else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't')
origin_die = lookup_type_die (origin);
add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
}
static inline void
add_pure_or_virtual_attribute (die, func_decl)
register dw_die_ref die;
register tree func_decl;
{
if (DECL_VINDEX (func_decl))
{
add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
add_AT_loc (die, DW_AT_vtable_elem_location,
new_loc_descr (DW_OP_constu,
TREE_INT_CST_LOW (DECL_VINDEX (func_decl)),
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)
register dw_die_ref die;
register tree decl;
{
register 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)
register dw_die_ref die;
register tree decl;
{
register 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));
add_src_coords_attributes (die, decl);
if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
&& DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
add_AT_string (die, DW_AT_MIPS_linkage_name,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
}
static void
push_decl_scope (scope)
tree scope;
{
tree containing_scope;
int i;
if (decl_scope_table_allocated == decl_scope_depth)
{
decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT;
decl_scope_table
= (decl_scope_node *) xrealloc (decl_scope_table,
(decl_scope_table_allocated
* sizeof (decl_scope_node)));
}
decl_scope_table[decl_scope_depth].scope = scope;
if (AGGREGATE_TYPE_P (scope))
containing_scope = TYPE_CONTEXT (scope);
else
containing_scope = NULL_TREE;
if (decl_scope_depth == 0
|| containing_scope == NULL_TREE
|| TREE_CODE (containing_scope) == NAMESPACE_DECL
|| containing_scope == decl_scope_table[decl_scope_depth - 1].scope)
decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1;
else
{
for (i = 0; i < decl_scope_depth; i++)
if (decl_scope_table[i].scope == containing_scope)
break;
if (i == decl_scope_depth)
abort ();
else
decl_scope_table[decl_scope_depth].previous = i;
}
decl_scope_depth++;
}
static dw_die_ref
scope_die_for (t, context_die)
register tree t;
register dw_die_ref context_die;
{
register dw_die_ref scope_die = NULL;
register tree containing_scope;
register int i;
if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
containing_scope = TYPE_CONTEXT (t);
else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t))
containing_scope = decl_class_context (t);
else
containing_scope = DECL_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 (context_die == NULL && containing_scope != NULL_TREE
&& (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t)))
return NULL;
if (containing_scope == NULL_TREE)
scope_die = comp_unit_die;
else
{
for (i = decl_scope_depth - 1, scope_die = context_die;
i >= 0 && decl_scope_table[i].scope != containing_scope;
(scope_die = scope_die->die_parent,
i = decl_scope_table[i].previous))
;
if (i < 0 && scope_die == comp_unit_die
&& TREE_CODE (containing_scope) == BLOCK
&& is_tagged_type (t)
&& (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope)
== containing_scope))
{
scope_die = context_die;
i = 0;
}
if (i < 0)
{
if (TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't')
abort ();
if (debug_info_level > DINFO_LEVEL_TERSE
&& !TREE_ASM_WRITTEN (containing_scope))
abort ();
scope_die = comp_unit_die;
}
}
return scope_die;
}
static inline void
pop_decl_scope ()
{
if (decl_scope_depth <= 0)
abort ();
--decl_scope_depth;
}
static void
add_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
register dw_die_ref object_die;
register tree type;
register int decl_const;
register int decl_volatile;
register dw_die_ref context_die;
{
register enum tree_code code = TREE_CODE (type);
register 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)
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 char *
type_tag (type)
register tree type;
{
register char *name = 0;
if (TYPE_NAME (type) != 0)
{
register 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)
register tree member;
{
return (DECL_BIT_FIELD_TYPE (member)
? DECL_BIT_FIELD_TYPE (member)
: TREE_TYPE (member));
}
#if 0
static char *
decl_start_label (decl)
register tree decl;
{
rtx x;
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)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref scope_die = scope_die_for (type, context_die);
register dw_die_ref array_die;
register 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);
#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);
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)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref type_die
= new_die (DW_TAG_set_type, scope_die_for (type, context_die));
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)
register tree decl;
register dw_die_ref context_die;
{
register tree origin = decl_ultimate_origin (decl);
register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die);
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
pend_type (type)
register tree type;
{
if (pending_types == pending_types_allocated)
{
pending_types_allocated += PENDING_TYPES_INCREMENT;
pending_types_list
= (tree *) xrealloc (pending_types_list,
sizeof (tree) * pending_types_allocated);
}
pending_types_list[pending_types++] = type;
}
static void
output_pending_types_for_scope (context_die)
register dw_die_ref context_die;
{
register tree type;
while (pending_types)
{
--pending_types;
type = pending_types_list[pending_types];
gen_type_die (type, context_die);
if (!TREE_ASM_WRITTEN (type))
abort ();
}
}
static void
add_incomplete_type (type)
tree type;
{
if (incomplete_types == incomplete_types_allocated)
{
incomplete_types_allocated += INCOMPLETE_TYPES_INCREMENT;
incomplete_types_list
= (tree *) xrealloc (incomplete_types_list,
sizeof (tree) * incomplete_types_allocated);
}
incomplete_types_list[incomplete_types++] = type;
}
static void
retry_incomplete_types ()
{
register tree type;
while (incomplete_types)
{
--incomplete_types;
type = incomplete_types_list[incomplete_types];
gen_type_die (type, comp_unit_die);
}
}
static void
gen_inlined_enumeration_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref type_die = new_die (DW_TAG_enumeration_type,
scope_die_for (type, context_die));
if (!TREE_ASM_WRITTEN (type))
abort ();
add_abstract_origin_attribute (type_die, type);
}
static void
gen_inlined_structure_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref type_die = new_die (DW_TAG_structure_type,
scope_die_for (type, context_die));
if (!TREE_ASM_WRITTEN (type))
abort ();
add_abstract_origin_attribute (type_die, type);
}
static void
gen_inlined_union_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref type_die = new_die (DW_TAG_union_type,
scope_die_for (type, context_die));
if (!TREE_ASM_WRITTEN (type))
abort ();
add_abstract_origin_attribute (type_die, type);
}
static void
gen_enumeration_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register 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));
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))
{
register 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))
{
register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die);
add_name_attribute (enum_die,
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
add_AT_unsigned (enum_die, DW_AT_const_value,
(unsigned) TREE_INT_CST_LOW (TREE_VALUE (link)));
}
}
else
add_AT_flag (type_die, DW_AT_declaration, 1);
}
static dw_die_ref
gen_formal_parameter_die (node, context_die)
register tree node;
register dw_die_ref context_die;
{
register dw_die_ref parm_die
= new_die (DW_TAG_formal_parameter, context_die);
register 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)
register tree decl_or_type;
register dw_die_ref context_die;
{
new_die (DW_TAG_unspecified_parameters, context_die);
}
static void
gen_formal_types_die (function_or_method_type, context_die)
register tree function_or_method_type;
register dw_die_ref context_die;
{
register tree link;
register tree formal_type = NULL;
register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
#if 0
if (TREE_CODE (function_or_method_type) == METHOD_TYPE)
first_parm_type = TREE_CHAIN (first_parm_type);
#endif
for (link = first_parm_type; link; link = TREE_CHAIN (link))
{
register 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)
add_AT_flag (parm_die, DW_AT_artificial, 1);
}
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;
link = TREE_CHAIN (link))
{
formal_type = TREE_VALUE (link);
if (formal_type == void_type_node)
break;
gen_type_die (formal_type, context_die);
}
}
static void
gen_subprogram_die (decl, context_die)
register tree decl;
register dw_die_ref context_die;
{
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
register tree origin = decl_ultimate_origin (decl);
register dw_die_ref subr_die;
register rtx fp_reg;
register tree fn_arg_types;
register tree outer_scope;
register dw_die_ref old_die = lookup_decl_die (decl);
register int declaration
= (current_function_decl != decl
|| (context_die
&& (context_die->die_tag == DW_TAG_structure_type
|| context_die->die_tag == DW_TAG_union_type)));
if (origin != NULL)
{
subr_die = new_die (DW_TAG_subprogram, context_die);
add_abstract_origin_attribute (subr_die, origin);
}
else if (old_die && DECL_ABSTRACT (decl)
&& get_AT_unsigned (old_die, DW_AT_inline))
{
subr_die = old_die;
remove_AT (subr_die, DW_AT_inline);
remove_children (subr_die);
}
else if (old_die)
{
register unsigned file_index
= lookup_filename (DECL_SOURCE_FILE (decl));
if (get_AT_flag (old_die, DW_AT_declaration) != 1)
{
extern int errorcount;
if (errorcount)
return;
abort ();
}
if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die
|| context_die == NULL)
&& get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== 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);
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)
!= DECL_SOURCE_LINE (decl))
add_AT_unsigned
(subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
}
}
else
{
register dw_die_ref scope_die;
if (DECL_CONTEXT (decl))
scope_die = scope_die_for (decl, context_die);
else
scope_die = context_die;
subr_die = new_die (DW_TAG_subprogram, scope_die);
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)
{
register tree type = TREE_TYPE (decl);
add_prototyped_attribute (subr_die, type);
add_type_attribute (subr_die, TREE_TYPE (type), 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)
{
add_AT_flag (subr_die, DW_AT_declaration, 1);
if (DECL_CONTEXT (decl))
equate_decl_number_to_die (decl, subr_die);
}
else if (DECL_ABSTRACT (decl))
{
if (DECL_DEFER_OUTPUT (decl))
{
if (DECL_INLINE (decl))
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
else
add_AT_unsigned (subr_die, DW_AT_inline,
DW_INL_declared_not_inlined);
}
else if (DECL_INLINE (decl))
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
else
abort ();
equate_decl_number_to_die (decl, subr_die);
}
else if (!DECL_EXTERNAL (decl))
{
if (origin == NULL_TREE)
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
}
push_decl_scope (decl);
if (debug_info_level <= DINFO_LEVEL_TERSE)
;
else if (declaration)
gen_formal_types_die (TREE_TYPE (decl), subr_die);
else
{
register tree arg_decls = DECL_ARGUMENTS (decl);
register 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
}
pop_decl_scope ();
}
static void
gen_variable_die (decl, context_die)
register tree decl;
register dw_die_ref context_die;
{
register tree origin = decl_ultimate_origin (decl);
register dw_die_ref var_die = new_die (DW_TAG_variable, context_die);
dw_die_ref old_die = lookup_decl_die (decl);
int declaration
= (DECL_EXTERNAL (decl)
|| current_function_decl != decl_function_context (decl)
|| context_die->die_tag == DW_TAG_structure_type
|| context_die->die_tag == DW_TAG_union_type);
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))
{
register 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)
!= 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 ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, var_die);
if (! declaration && ! DECL_ABSTRACT (decl))
{
equate_decl_number_to_die (decl, var_die);
add_location_or_const_value_attribute (var_die, decl);
add_pubname (decl, var_die);
}
}
static void
gen_label_die (decl, context_die)
register tree decl;
register dw_die_ref context_die;
{
register tree origin = decl_ultimate_origin (decl);
register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die);
register rtx insn;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
char label2[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 ();
sprintf (label2, INSN_LABEL_FMT, current_funcdef_number);
ASM_GENERATE_INTERNAL_LABEL (label, label2,
(unsigned) INSN_UID (insn));
add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
}
}
}
static void
gen_lexical_block_die (stmt, context_die, depth)
register tree stmt;
register dw_die_ref context_die;
int depth;
{
register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
if (! BLOCK_ABSTRACT (stmt))
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
next_block_number);
add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
}
push_decl_scope (stmt);
decls_for_scope (stmt, stmt_die, depth);
pop_decl_scope ();
}
static void
gen_inlined_subroutine_die (stmt, context_die, depth)
register tree stmt;
register dw_die_ref context_die;
int depth;
{
if (! BLOCK_ABSTRACT (stmt))
{
register dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die);
register tree decl = block_ultimate_origin (stmt);
char label[MAX_ARTIFICIAL_LABEL_BYTES];
add_abstract_origin_attribute (subr_die, decl);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
next_block_number);
add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
push_decl_scope (decl);
decls_for_scope (stmt, subr_die, depth);
pop_decl_scope ();
current_function_has_inlines = 1;
}
}
static void
gen_field_die (decl, context_die)
register tree decl;
register dw_die_ref context_die;
{
register dw_die_ref decl_die = new_die (DW_TAG_member, context_die);
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)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref ptr_die
= new_die (DW_TAG_pointer_type, scope_die_for (type, context_die));
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)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref ref_die
= new_die (DW_TAG_reference_type, scope_die_for (type, context_die));
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)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref ptr_die
= new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die));
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 void
gen_compile_unit_die (main_input_filename)
register char *main_input_filename;
{
char producer[250];
char *wd = getpwd ();
comp_unit_die = new_die (DW_TAG_compile_unit, NULL);
add_name_attribute (comp_unit_die, main_input_filename);
if (wd != NULL)
add_AT_string (comp_unit_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 (comp_unit_die, DW_AT_producer, producer);
if (strcmp (language_string, "GNU C++") == 0
|| strcmp (language_string, "GNU Obj-C++") == 0)
add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus);
else if (strcmp (language_string, "GNU Ada") == 0)
add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83);
else if (strcmp (language_string, "GNU F77") == 0)
add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77);
else if (strcmp (language_string, "GNU Pascal") == 0)
add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83);
else if (flag_traditional)
add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C);
else
add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89);
#if 0
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0);
#endif
}
static void
gen_string_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref type_die
= new_die (DW_TAG_string_type, scope_die_for (type, context_die));
equate_type_number_to_die (type, type_die);
}
static void
gen_inheritance_die (binfo, context_die)
register tree binfo;
register dw_die_ref context_die;
{
dw_die_ref die = new_die (DW_TAG_inheritance, context_die);
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)
register tree type;
register dw_die_ref context_die;
{
register tree member;
if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
{
register tree bases = TYPE_BINFO_BASETYPES (type);
register int n_bases = TREE_VEC_LENGTH (bases);
register 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))
gen_decl_die (member, context_die);
for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
gen_decl_die (member, context_die);
}
static void
gen_struct_or_union_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register dw_die_ref type_die = lookup_type_die (type);
register dw_die_ref scope_die = 0;
register int nested = 0;
if (type_die && ! TYPE_SIZE (type))
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))
{
register 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);
equate_type_number_to_die (type, type_die);
add_name_attribute (type_die, type_tag (type));
if (old_die)
add_AT_die_ref (type_die, DW_AT_specification, old_die);
}
else
remove_AT (type_die, DW_AT_declaration);
if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die)
{
add_AT_flag (type_die, DW_AT_declaration, 1);
pend_type (type);
}
else if (TYPE_SIZE (type))
{
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 (TREE_PERMANENT (type))
add_incomplete_type (type);
}
}
static void
gen_subroutine_type_die (type, context_die)
register tree type;
register dw_die_ref context_die;
{
register tree return_type = TREE_TYPE (type);
register dw_die_ref subr_die
= new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die));
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)
register tree decl;
register dw_die_ref context_die;
{
register dw_die_ref type_die;
register tree origin;
if (TREE_ASM_WRITTEN (decl))
return;
TREE_ASM_WRITTEN (decl) = 1;
type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die));
origin = decl_ultimate_origin (decl);
if (origin != NULL)
add_abstract_origin_attribute (type_die, origin);
else
{
register tree type;
add_name_and_src_coords_attributes (type_die, decl);
if (DECL_ORIGINAL_TYPE (decl))
{
type = DECL_ORIGINAL_TYPE (decl);
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)
register tree type;
register dw_die_ref context_die;
{
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 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_CONTEXT (type)))
return;
push_decl_scope (TYPE_CONTEXT (type));
context_die = lookup_type_die (TYPE_CONTEXT (type));
}
if (TREE_CODE (type) == ENUMERAL_TYPE)
gen_enumeration_type_die (type, context_die);
else
gen_struct_or_union_type_die (type, context_die);
if (TYPE_CONTEXT (type)
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
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)
register tree type;
register dw_die_ref context_die;
{
if (type == NULL_TREE || type == error_mark_node)
return;
if (type != type_main_variant (type)
|| !TREE_ASM_WRITTEN (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)
register tree stmt;
register dw_die_ref context_die;
int depth;
{
register int must_output_die = 0;
register tree origin;
register tree decl;
register enum tree_code origin_code;
if (stmt == NULL_TREE || !TREE_USED (stmt))
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)
register tree stmt;
register dw_die_ref context_die;
int depth;
{
register tree decl;
register tree subblocks;
if (stmt == NULL_TREE || ! TREE_USED (stmt))
return;
if (!BLOCK_ABSTRACT (stmt) && depth > 0)
next_block_number++;
for (decl = BLOCK_VARS (stmt);
decl != NULL; decl = TREE_CHAIN (decl))
{
register 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)
register 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)
register tree decl;
register dw_die_ref context_die;
{
register tree origin;
dwarf_last_decl = decl;
if (TREE_CODE (decl) == ERROR_MARK)
return;
if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL)
return;
switch (TREE_CODE (decl))
{
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 (debug_info_level > DINFO_LEVEL_TERSE)
{
gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
origin = decl_class_context (decl);
if (origin != NULL_TREE)
gen_type_die (origin, context_die);
if (DECL_VINDEX (decl) != NULL_TREE)
gen_type_die (DECL_CONTEXT (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_ABSTRACT_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 (origin, 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;
default:
abort ();
}
}
void
dwarf2out_decl (decl)
register tree decl;
{
register dw_die_ref context_die = comp_unit_die;
if (TREE_CODE (decl) == ERROR_MARK)
return;
if (DECL_IGNORED_P (decl))
{
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INITIAL (decl) != NULL)
abort ();
return;
}
switch (TREE_CODE (decl))
{
case FUNCTION_DECL:
if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (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 (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)
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);
output_pending_types_for_scope (comp_unit_die);
}
void
dwarf2out_begin_block (blocknum)
register unsigned blocknum;
{
function_section (current_function_decl);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
void
dwarf2out_end_block (blocknum)
register unsigned blocknum;
{
function_section (current_function_decl);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
void
dwarf2out_label (insn)
register rtx insn;
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
function_section (current_function_decl);
sprintf (label, INSN_LABEL_FMT, current_funcdef_number);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label,
(unsigned) INSN_UID (insn));
}
}
static unsigned
lookup_filename (file_name)
char *file_name;
{
static unsigned last_file_lookup_index = 0;
register unsigned i;
if (last_file_lookup_index != 0)
if (strcmp (file_name, file_table[last_file_lookup_index]) == 0)
return last_file_lookup_index;
for (i = 1; i < file_table_in_use; ++i)
if (strcmp (file_name, file_table[i]) == 0)
{
last_file_lookup_index = i;
return i;
}
if (file_table_in_use == file_table_allocated)
{
file_table_allocated += FILE_TABLE_INCREMENT;
file_table
= (char **) xrealloc (file_table,
file_table_allocated * sizeof (char *));
}
file_table[file_table_in_use] = xstrdup (file_name);
last_file_lookup_index = file_table_in_use++;
return last_file_lookup_index;
}
void
dwarf2out_line (filename, line)
register char *filename;
register unsigned line;
{
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
function_section (current_function_decl);
if (DECL_SECTION_NAME (current_function_decl))
{
register dw_separate_line_info_ref line_info;
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
separate_line_info_table_in_use);
fputc ('\n', asm_out_file);
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
{
register dw_line_info_ref line_info;
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
line_info_table_in_use);
fputc ('\n', asm_out_file);
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;
}
}
}
void
dwarf2out_start_source_file (filename)
register char *filename ATTRIBUTE_UNUSED;
{
}
void
dwarf2out_end_source_file ()
{
}
void
dwarf2out_define (lineno, buffer)
register unsigned lineno;
register char *buffer;
{
static int initialized = 0;
if (!initialized)
{
dwarf2out_start_source_file (primary_filename);
initialized = 1;
}
}
void
dwarf2out_undef (lineno, buffer)
register unsigned lineno ATTRIBUTE_UNUSED;
register char *buffer ATTRIBUTE_UNUSED;
{
}
void
dwarf2out_init (asm_out_file, main_input_filename)
register FILE *asm_out_file;
register char *main_input_filename;
{
primary_filename = main_input_filename;
file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *));
bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *));
file_table_allocated = FILE_TABLE_INCREMENT;
file_table_in_use = 1;
decl_die_table
= (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
bzero ((char *) decl_die_table,
DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
decl_die_table_in_use = 0;
decl_scope_table
= (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT
* sizeof (decl_scope_node));
bzero ((char *) decl_scope_table,
DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node));
decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
decl_scope_depth = 0;
abbrev_die_table
= (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT
* sizeof (dw_die_ref));
bzero ((char *) abbrev_die_table,
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) xmalloc (LINE_INFO_TABLE_INCREMENT
* sizeof (dw_line_info_entry));
bzero ((char *) line_info_table,
LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
line_info_table_in_use = 1;
gen_compile_unit_die (main_input_filename);
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label, ABBREV_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
DEBUG_INFO_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
DEBUG_LINE_SECTION_LABEL, 0);
ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
}
void
dwarf2out_finish ()
{
limbo_die_node *node, *next_node;
dw_die_ref die;
dw_attr_ref a;
for (node = limbo_die_list; node; node = next_node)
{
next_node = node->next;
die = node->die;
if (die->die_parent == NULL)
{
a = get_AT (die, DW_AT_abstract_origin);
if (a)
add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die);
else if (die == comp_unit_die)
;
else
abort ();
}
free (node);
}
retry_incomplete_types ();
add_sibling_attributes (comp_unit_die);
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
#if 0
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0);
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
#endif
if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
{
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
output_line_info ();
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);
}
add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
debug_line_section_label);
}
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
build_abbrev_table (comp_unit_die);
output_abbrev_section ();
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
calc_die_sizes (comp_unit_die);
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION);
output_compilation_unit_header ();
output_die (comp_unit_die);
if (pubname_table_in_use)
{
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION);
output_pubnames ();
}
if (fde_table_in_use)
{
fputc ('\n', asm_out_file);
ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
output_aranges ();
}
}
#endif