#include "regs.h"
#include "insn-config.h"
#include "reload.h"
+#include "function.h"
#include "output.h"
#include "expr.h"
#include "except.h"
#include "ggc.h"
#include "md5.h"
#include "tm_p.h"
+#include "diagnostic.h"
+#include "debug.h"
+
+#ifdef DWARF2_DEBUGGING_INFO
+static void dwarf2out_source_line PARAMS ((unsigned int, const char *));
+#endif
/* DWARF2 Abbreviation Glossary:
CFA = Canonical Frame Address
#endif
#ifdef DWARF2_UNWIND_INFO
|| flag_unwind_tables
- || (flag_exceptions && ! exceptions_via_longjmp)
+ || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)
#endif
);
}
+/* The number of the current function definition for which debugging
+ information is being generated. These numbers range from 1 up to the
+ maximum number of function definitions contained within the current
+ compilation unit. These numbers are used to create unique label id's
+ unique to each function definition. */
+unsigned current_funcdef_number = 0;
+
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
/* How to start an assembler comment. */
const char *dw_fde_current_label;
const char *dw_fde_end;
dw_cfi_ref dw_fde_cfi;
- int nothrow;
+ unsigned funcdef_number;
+ unsigned nothrow : 1;
+ unsigned uses_eh_lsda : 1;
}
dw_fde_node;
/* A list of call frame insns for the CIE. */
static dw_cfi_ref cie_cfi_head;
-/* The number of the current function definition for which debugging
- information is being generated. These numbers range from 1 up to the
- maximum number of function definitions contained within the current
- compilation unit. These numbers are used to create unique label id's
- unique to each function definition. */
-static unsigned current_funcdef_number = 0;
-
/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
attribute that accelerates the lookup of the FDE associated
with the subprogram. This variable holds the table index of the FDE
unsigned, long));
static void initial_return_save PARAMS ((rtx));
static long stack_adjust_offset PARAMS ((rtx));
-static void output_cfi PARAMS ((dw_cfi_ref, dw_fde_ref));
+static void output_cfi PARAMS ((dw_cfi_ref, dw_fde_ref, int));
static void output_call_frame_info PARAMS ((int));
static void dwarf2out_stack_adjust PARAMS ((rtx));
static void queue_reg_save PARAMS ((const char *, rtx, long));
#endif
#endif
-#ifndef FRAME_SECTION
-#define FRAME_SECTION ".debug_frame"
+#ifndef DEBUG_FRAME_SECTION
+#define DEBUG_FRAME_SECTION ".debug_frame"
#endif
#ifndef FUNC_BEGIN_LABEL
#ifndef INCOMING_FRAME_SP_OFFSET
#define INCOMING_FRAME_SP_OFFSET 0
#endif
-
+\f
/* Return a pointer to a copy of the section string name S with all
attributes stripped off, and an asterisk prepended (for assemble_name). */
if (offset < 0)
continue;
- emit_move_insn (change_address (mem, mode,
- plus_constant (addr, offset)),
- GEN_INT (size));
+ emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
}
}
long offset;
const char *label;
- if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN)
+ if (! flag_non_call_exceptions && GET_CODE (insn) == CALL_INSN)
{
/* Extract the size of the args from the CALL rtx itself. */
/* If only calls can throw, and we have a frame pointer,
save up adjustments until we see the CALL_INSN. */
- else if (! asynchronous_exceptions
+ else if (! flag_non_call_exceptions
&& cfa.reg != STACK_POINTER_REGNUM)
return;
cfa_store.reg to the actual CFA
cfa_temp register holding an integral value. cfa_temp.offset
stores the value, which will be used to adjust the
- stack pointer.
+ stack pointer. cfa_temp is also used like cfa_store,
+ to track stores to the stack via fp or a temp reg.
Rules 1- 4: Setting a register's value to cfa.reg or an expression
with cfa.reg as the first operand changes the cfa.reg and its
- cfa.offset.
+ cfa.offset. Rule 1 and 4 also set cfa_temp.reg and
+ cfa_temp.offset.
Rules 6- 9: Set a non-cfa.reg register value to a constant or an
expression yielding a constant. This sets cfa_temp.reg
Rule 5: Create a new register cfa_store used to save items to the
stack.
- Rules 10-13: Save a register to the stack. Define offset as the
+ Rules 10-14: Save a register to the stack. Define offset as the
difference of the original location and cfa_store's
- location.
+ location (or cfa_temp's location if cfa_temp is used).
The Rules
Rule 1:
(set <reg1> <reg2>:cfa.reg)
- effects: cfa.reg = <REG1>
+ effects: cfa.reg = <reg1>
cfa.offset unchanged
+ cfa_temp.reg = <reg1>
+ cfa_temp.offset = cfa.offset
Rule 2:
- (set sp ({minus,plus} {sp,fp}:cfa.reg {<const_int>,<reg>:cfa_temp.reg}))
+ (set sp ({minus,plus,losum} {sp,fp}:cfa.reg {<const_int>,<reg>:cfa_temp.reg}))
effects: cfa.reg = sp if fp used
cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
if cfa_store.reg==sp
Rule 3:
- (set fp ({minus,plus} <reg>:cfa.reg <const_int>))
+ (set fp ({minus,plus,losum} <reg>:cfa.reg <const_int>))
effects: cfa.reg = fp
cfa_offset += +/- <const_int>
Rule 4:
- (set <reg1> (plus <reg2>:cfa.reg <const_int>))
+ (set <reg1> ({plus,losum} <reg2>:cfa.reg <const_int>))
constraints: <reg1> != fp
<reg1> != sp
effects: cfa.reg = <reg1>
+ cfa_temp.reg = <reg1>
+ cfa_temp.offset = cfa.offset
Rule 5:
(set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
(set (mem (pre_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
effects: cfa_store.offset -= <const_int>
cfa.offset = cfa_store.offset if cfa.reg == sp
- offset = -cfa_store.offset
cfa.reg = sp
- cfa.base_offset = offset
+ cfa.base_offset = -cfa_store.offset
Rule 11:
(set (mem ({pre_inc,pre_dec} sp:cfa_store.reg)) <reg>)
effects: cfa_store.offset += -/+ mode_size(mem)
cfa.offset = cfa_store.offset if cfa.reg == sp
- offset = -cfa_store.offset
cfa.reg = sp
- cfa.base_offset = offset
+ cfa.base_offset = -cfa_store.offset
Rule 12:
- (set (mem ({minus,plus} <reg1>:cfa_store <const_int>)) <reg2>)
- effects: cfa_store.offset += -/+ <const_int>
- offset = -cfa_store.offset
- cfa.reg = <reg1
- cfa.base_offset = offset
+ (set (mem ({minus,plus,losum} <reg1>:{cfa_store,cfa_temp} <const_int>)) <reg2>)
+ effects: cfa.reg = <reg1>
+ cfa.base_offset = -/+ <const_int> - {cfa_store,cfa_temp}.offset
Rule 13:
- (set (mem <reg1>:cfa_store) <reg2>)
- effects: offset = -cfa_store.offset
- cfa.reg = <reg1>
- cfa.base_offset = offset */
+ (set (mem <reg1>:{cfa_store,cfa_temp}) <reg2>)
+ effects: cfa.reg = <reg1>
+ cfa.base_offset = -{cfa_store,cfa_temp}.offset
+
+ Rule 14:
+ (set (mem (postinc <reg1>:cfa_temp <const_int>)) <reg2>)
+ effects: cfa.reg = <reg1>
+ cfa.base_offset = -cfa_temp.offset
+ cfa_temp.offset -= mode_size(mem) */
static void
dwarf2out_frame_debug_expr (expr, label)
FP. So we just rely on the backends to only set
RTX_FRAME_RELATED_P on appropriate insns. */
cfa.reg = REGNO (dest);
+ cfa_temp.reg = cfa.reg;
+ cfa_temp.offset = cfa.offset;
break;
case PLUS:
case MINUS:
+ case LO_SUM:
if (dest == stack_pointer_rtx)
{
/* Rule 2 */
abort ();
cfa.reg = STACK_POINTER_REGNUM;
}
+ else if (GET_CODE (src) == LO_SUM)
+ /* Assume we've set the source reg of the LO_SUM from sp. */
+ ;
else if (XEXP (src, 0) != stack_pointer_rtx)
abort ();
- if (GET_CODE (src) == PLUS)
+ if (GET_CODE (src) != MINUS)
offset = -offset;
if (cfa.reg == STACK_POINTER_REGNUM)
cfa.offset += offset;
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
offset = INTVAL (XEXP (src, 1));
- if (GET_CODE (src) == PLUS)
+ if (GET_CODE (src) != MINUS)
offset = -offset;
cfa.offset += offset;
cfa.reg = HARD_FRAME_POINTER_REGNUM;
}
else
{
- if (GET_CODE (src) != PLUS)
+ if (GET_CODE (src) == MINUS)
abort ();
/* Rule 4 */
{
/* Setting a temporary CFA register that will be copied
into the FP later on. */
- offset = INTVAL (XEXP (src, 1));
- if (GET_CODE (src) == PLUS)
- offset = -offset;
+ offset = - INTVAL (XEXP (src, 1));
cfa.offset += offset;
cfa.reg = REGNO (dest);
+ /* Or used to save regs to the stack. */
+ cfa_temp.reg = cfa.reg;
+ cfa_temp.offset = cfa.offset;
}
/* Rule 5 */
- else
+ else if (GET_CODE (XEXP (src, 0)) == REG
+ && REGNO (XEXP (src, 0)) == cfa_temp.reg
+ && XEXP (src, 1) == stack_pointer_rtx)
{
/* Setting a scratch register that we will use instead
of SP for saving registers to the stack. */
- if (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.offset;
}
+ /* Rule 9 */
+ else if (GET_CODE (src) == LO_SUM
+ && GET_CODE (XEXP (src, 1)) == CONST_INT)
+ {
+ cfa_temp.reg = REGNO (dest);
+ cfa_temp.offset = INTVAL (XEXP (src, 1));
+ }
+ else
+ abort ();
}
break;
cfa_temp.offset |= INTVAL (XEXP (src, 1));
break;
+ /* Skip over HIGH, assuming it will be followed by a LO_SUM,
+ which will fill in all of the bits. */
+ /* Rule 8 */
+ case HIGH:
+ break;
+
default:
abort ();
}
def_cfa_1 (label, &cfa);
break;
- /* Skip over HIGH, assuming it will be followed by a LO_SUM, which
- will fill in all of the bits. */
- /* Rule 8 */
- case HIGH:
- break;
-
- /* Rule 9 */
- case LO_SUM:
- if (GET_CODE (XEXP (src, 1)) != CONST_INT)
- abort ();
- cfa_temp.reg = REGNO (dest);
- cfa_temp.offset = INTVAL (XEXP (src, 1));
- break;
-
case MEM:
if (GET_CODE (src) != REG)
abort ();
/* With an offset. */
case PLUS:
case MINUS:
+ case LO_SUM:
if (GET_CODE (XEXP (XEXP (dest, 0), 1)) != CONST_INT)
abort ();
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)))
+ if (cfa_store.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+ offset -= cfa_store.offset;
+ else if (cfa_temp.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+ offset -= cfa_temp.offset;
+ else
abort ();
- offset -= cfa_store.offset;
break;
/* Rule 13 */
/* Without an offset. */
case REG:
- if (cfa_store.reg != (unsigned) REGNO (XEXP (dest, 0)))
+ if (cfa_store.reg == (unsigned) REGNO (XEXP (dest, 0)))
+ offset = -cfa_store.offset;
+ else if (cfa_temp.reg == (unsigned) REGNO (XEXP (dest, 0)))
+ offset = -cfa_temp.offset;
+ else
abort ();
- offset = -cfa_store.offset;
+ break;
+
+ /* Rule 14 */
+ case POST_INC:
+ if (cfa_temp.reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+ abort ();
+ offset = -cfa_temp.offset;
+ cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
break;
default:
/* Output a Call Frame Information opcode and its operand(s). */
static void
-output_cfi (cfi, fde)
+output_cfi (cfi, fde, for_eh)
register dw_cfi_ref cfi;
register dw_fde_ref fde;
+ int for_eh;
{
if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
{
switch (cfi->dw_cfi_opc)
{
case DW_CFA_set_loc:
- dw2_asm_output_addr (DWARF2_ADDR_SIZE,
- cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
+ if (for_eh)
+ dw2_asm_output_encoded_addr_rtx (
+ ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
+ gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
+ NULL);
+ else
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
break;
case DW_CFA_advance_loc1:
dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
output_call_frame_info (for_eh)
int for_eh;
{
- register unsigned long i;
+ register unsigned int 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
-
- /* Do we want to include a pointer to the exception table? */
- int eh_ptr = for_eh && exception_table_p ();
+ int any_lsda_needed = 0;
+ char augmentation[6];
+ int augmentation_size;
+ int fde_encoding = DW_EH_PE_absptr;
+ int per_encoding = DW_EH_PE_absptr;
+ int lsda_encoding = DW_EH_PE_absptr;
/* If we don't have any functions we'll want to unwind out of, don't
emit any EH unwind information. */
if (for_eh)
{
+ int any_eh_needed = 0;
for (i = 0; i < fde_table_in_use; ++i)
- if (! fde_table[i].nothrow)
- goto found;
- return;
- found:;
+ if (fde_table[i].uses_eh_lsda)
+ any_eh_needed = any_lsda_needed = 1;
+ else if (! fde_table[i].nothrow)
+ any_eh_needed = 1;
+
+ if (! any_eh_needed)
+ return;
}
/* We're going to be generating comments, so turn on app. */
tree label = get_file_function_name ('F');
force_data_section ();
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
+ 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_OUTPUT_SECTION (asm_out_file, DEBUG_FRAME_SECTION);
/* Output the CIE. */
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);
- dw2_asm_output_offset (for_eh ? 4 : DWARF_OFFSET_SIZE, ld,
- "Length of Common Information Entry");
-#else
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"Length of Common Information Entry");
-#endif
ASM_OUTPUT_LABEL (asm_out_file, l1);
/* Now that the CIE pointer is PC-relative for EH,
dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
- if (eh_ptr)
- {
- /* The CIE contains a pointer to the exception region info for the
- frame. Make the augmentation string three bytes (including the
- trailing null) so the pointer is 4-byte aligned. The Solaris ld
- can't handle unaligned relocs. */
- dw2_asm_output_nstring ("eh", -1, "CIE Augmentation");
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, "__EXCEPTION_TABLE__",
- "pointer to exception region info");
- }
- else
+ augmentation[0] = 0;
+ augmentation_size = 0;
+ if (for_eh)
{
- dw2_asm_output_data (1, 0, "CIE Augmentation (none)");
+ char *p;
+
+ /* Augmentation:
+ z Indicates that a uleb128 is present to size the
+ augmentation section.
+ L Indicates the encoding (and thus presence) of
+ an LSDA pointer in the FDE augmentation.
+ R Indicates a non-default pointer encoding for
+ FDE code pointers.
+ P Indicates the presence of an encoding + language
+ personality routine in the CIE augmentation. */
+
+ fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
+ per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
+ lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
+
+ p = augmentation + 1;
+ if (eh_personality_libfunc)
+ {
+ *p++ = 'P';
+ augmentation_size += 1 + size_of_encoded_value (per_encoding);
+ }
+ if (any_lsda_needed)
+ {
+ *p++ = 'L';
+ augmentation_size += 1;
+ }
+ if (fde_encoding != DW_EH_PE_absptr)
+ {
+ *p++ = 'R';
+ augmentation_size += 1;
+ }
+ if (p > augmentation + 1)
+ {
+ augmentation[0] = 'z';
+ *p = '\0';
+ }
+
+ /* Ug. Some platforms can't do unaligned dynamic relocations at all. */
+ if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned)
+ {
+ int offset = ( 4 /* Length */
+ + 4 /* CIE Id */
+ + 1 /* CIE version */
+ + strlen (augmentation) + 1 /* Augmentation */
+ + size_of_uleb128 (1) /* Code alignment */
+ + size_of_sleb128 (DWARF_CIE_DATA_ALIGNMENT)
+ + 1 /* RA column */
+ + 1 /* Augmentation size */
+ + 1 /* Personality encoding */ );
+ int pad = -offset & (PTR_SIZE - 1);
+
+ augmentation_size += pad;
+
+ /* Augmentations should be small, so there's scarce need to
+ iterate for a solution. Die if we exceed one uleb128 byte. */
+ if (size_of_uleb128 (augmentation_size) != 1)
+ abort ();
+ }
}
+ dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
dw2_asm_output_data (1, DWARF_FRAME_RETURN_COLUMN, "CIE RA Column");
+ if (augmentation[0])
+ {
+ dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
+ if (eh_personality_libfunc)
+ {
+ dw2_asm_output_data (1, per_encoding, "Personality (%s)",
+ eh_data_format_name (per_encoding));
+ dw2_asm_output_encoded_addr_rtx (per_encoding,
+ eh_personality_libfunc, NULL);
+ }
+ if (any_lsda_needed)
+ dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
+ eh_data_format_name (lsda_encoding));
+ if (fde_encoding != DW_EH_PE_absptr)
+ dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
+ eh_data_format_name (fde_encoding));
+ }
+
for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
- output_cfi (cfi, NULL);
+ output_cfi (cfi, NULL, for_eh);
/* Pad the CIE out to an address sized boundary. */
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
+ ASM_OUTPUT_ALIGN (asm_out_file,
+ floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_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
/* Loop through all of the FDE's. */
for (i = 0; i < fde_table_in_use; ++i)
{
fde = &fde_table[i];
- /* Don't emit EH unwind info for leaf functions. */
- if (for_eh && fde->nothrow)
+ /* Don't emit EH unwind info for leaf functions that don't need it. */
+ if (for_eh && fde->nothrow && ! fde->uses_eh_lsda)
continue;
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, FDE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
-#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
- ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i * 2);
- dw2_asm_output_offset (for_eh ? 4 : DWARF_OFFSET_SIZE, ld, "FDE Length");
-#else
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"FDE Length");
-#endif
ASM_OUTPUT_LABEL (asm_out_file, l1);
/* ??? This always emits a 4 byte offset when for_eh is true, but it
dw2_asm_output_delta (4, l1, "__FRAME_BEGIN__", "FDE CIE offset");
else
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
- stripattributes (FRAME_SECTION),
+ stripattributes (DEBUG_FRAME_SECTION),
"FDE CIE offset");
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
- "FDE initial location");
+ if (for_eh)
+ {
+ dw2_asm_output_encoded_addr_rtx (fde_encoding,
+ gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin),
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
+ }
+ else
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
+ }
+
+ if (augmentation[0])
+ {
+ if (any_lsda_needed)
+ {
+ int size = size_of_encoded_value (lsda_encoding);
- dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_end,
- fde->dw_fde_begin, "FDE address range");
+ if (lsda_encoding == DW_EH_PE_aligned)
+ {
+ int offset = ( 4 /* Length */
+ + 4 /* CIE offset */
+ + 2 * size_of_encoded_value (fde_encoding)
+ + 1 /* Augmentation size */ );
+ int pad = -offset & (PTR_SIZE - 1);
+
+ size += pad;
+ if (size_of_uleb128 (size) != 1)
+ abort ();
+ }
+
+ dw2_asm_output_data_uleb128 (size, "Augmentation size");
+
+ if (fde->uses_eh_lsda)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
+ fde->funcdef_number);
+ dw2_asm_output_encoded_addr_rtx (
+ lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
+ "Language Specific Data Area");
+ }
+ else
+ {
+ if (lsda_encoding == DW_EH_PE_aligned)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ dw2_asm_output_data (size_of_encoded_value (lsda_encoding),
+ 0, "Language Specific Data Area (none)");
+ }
+ }
+ else
+ dw2_asm_output_data_uleb128 (0, "Augmentation size");
+ }
/* Loop through the Call Frame Instructions associated with
this FDE. */
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);
+ output_cfi (cfi, fde, for_eh);
/* Pad the FDE out to an address sized boundary. */
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
+ ASM_OUTPUT_ALIGN (asm_out_file,
+ floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_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
}
#ifndef EH_FRAME_SECTION
the prologue. */
void
-dwarf2out_begin_prologue ()
+dwarf2out_begin_prologue (line, file)
+ unsigned int line ATTRIBUTE_UNUSED;
+ const char *file ATTRIBUTE_UNUSED;
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
register dw_fde_ref fde;
+ current_function_func_begin_label = 0;
+
+#ifdef IA64_UNWIND_INFO
+ /* ??? current_function_func_begin_label is also used by except.c
+ for call-site information. We must emit this label if it might
+ be used. */
+ if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
+ && ! dwarf2out_do_frame ())
+ return;
+#else
+ if (! dwarf2out_do_frame ())
+ return;
+#endif
+
++current_funcdef_number;
function_section (current_function_decl);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_funcdef_number);
- ASM_OUTPUT_LABEL (asm_out_file, label);
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
+ current_funcdef_number);
current_function_func_begin_label = get_identifier (label);
+#ifdef IA64_UNWIND_INFO
+ /* We can elide the fde allocation if we're not emitting debug info. */
+ if (! dwarf2out_do_frame ())
+ return;
+#endif
+
/* Expand the fde table if necessary. */
if (fde_table_in_use == fde_table_allocated)
{
fde->dw_fde_current_label = NULL;
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
+ fde->funcdef_number = current_funcdef_number;
fde->nothrow = current_function_nothrow;
+ fde->uses_eh_lsda = cfun->uses_eh_lsda;
args_size = old_args_size = 0;
+
+ /* We only want to output line number information for the genuine
+ dwarf2 prologue case, not the eh frame case. */
+#ifdef DWARF2_DEBUGGING_INFO
+ if (file)
+ dwarf2out_source_line (line, file);
+#endif
}
/* Output a marker (i.e. a label) for the absolute end of the generated code
#ifdef MIPS_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG)
output_call_frame_info (0);
- if (flag_unwind_tables || (flag_exceptions && ! exceptions_via_longjmp))
+ if (flag_unwind_tables || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS))
output_call_frame_info (1);
#else
if (write_symbols == DWARF2_DEBUG
- || flag_unwind_tables || (flag_exceptions && ! exceptions_via_longjmp))
+ || flag_unwind_tables || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS))
output_call_frame_info (1);
#endif
}
typedef struct dw_val_struct *dw_val_ref;
typedef struct die_struct *dw_die_ref;
typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
+typedef struct dw_loc_list_struct *dw_loc_list_ref;
/* Each DIE may have a series of attribute/value pairs. Values
can take on several forms. The forms that are used in this
{
dw_val_class_addr,
dw_val_class_loc,
+ dw_val_class_loc_list,
dw_val_class_const,
dw_val_class_unsigned_const,
dw_val_class_long_long,
union
{
rtx val_addr;
+ dw_loc_list_ref val_loc_list;
dw_loc_descr_ref val_loc;
long int val_int;
long unsigned val_unsigned;
}
dw_loc_descr_node;
+/* Location lists are ranges + location descriptions for that range,
+ so you can track variables that are in different places over
+ their entire life. */
+typedef struct dw_loc_list_struct
+{
+ dw_loc_list_ref dw_loc_next;
+ const char *begin; /* Label for begin address of range */
+ const char *end; /* Label for end address of range */
+ char *ll_symbol; /* Label for beginning of location list. Only on head of list */
+ const char *section; /* Section this loclist is relative to */
+ dw_loc_descr_ref expr;
+} dw_loc_list_node;
+
static const char *dwarf_stack_op_name PARAMS ((unsigned));
static dw_loc_descr_ref new_loc_descr PARAMS ((enum dwarf_location_atom,
unsigned long,
return descr;
}
+
/* Add a location description term to a location description expression. */
static inline void
/* And now, the support for symbolic debugging information. */
#ifdef DWARF2_DEBUGGING_INFO
+static void dwarf2out_init PARAMS ((const char *));
+static void dwarf2out_finish PARAMS ((const char *));
+static void dwarf2out_define PARAMS ((unsigned int, const char *));
+static void dwarf2out_undef PARAMS ((unsigned int, const char *));
+static void dwarf2out_start_source_file PARAMS ((unsigned, const char *));
+static void dwarf2out_end_source_file PARAMS ((unsigned));
+static void dwarf2out_begin_block PARAMS ((unsigned, unsigned));
+static void dwarf2out_end_block PARAMS ((unsigned, unsigned));
+static bool dwarf2out_ignore_block PARAMS ((tree));
+static void dwarf2out_global_decl PARAMS ((tree));
+static void dwarf2out_abstract_function PARAMS ((tree));
+
+/* The debug hooks structure. */
+
+struct gcc_debug_hooks dwarf2_debug_hooks =
+{
+ dwarf2out_init,
+ dwarf2out_finish,
+ dwarf2out_define,
+ dwarf2out_undef,
+ dwarf2out_start_source_file,
+ dwarf2out_end_source_file,
+ dwarf2out_begin_block,
+ dwarf2out_end_block,
+ dwarf2out_ignore_block,
+ dwarf2out_source_line,
+ dwarf2out_begin_prologue,
+ debug_nothing_int, /* end_prologue */
+ dwarf2out_end_epilogue,
+ debug_nothing_tree, /* begin_function */
+ debug_nothing_int, /* end_function */
+ dwarf2out_decl, /* function_decl */
+ dwarf2out_global_decl,
+ debug_nothing_tree, /* deferred_inline_function */
+ /* The DWARF 2 backend tries to reduce debugging bloat by not
+ emitting the abstract description of inline functions until
+ something tries to reference them. */
+ dwarf2out_abstract_function, /* outlining_inline_function */
+ debug_nothing_rtx /* label */
+};
+\f
/* NOTE: In the comments in this file, many references are made to
"Debugging Information Entries". This term is abbreviated as `DIE'
throughout the remainder of this file. */
arange_table. */
#define ARANGE_TABLE_INCREMENT 64
+/* Whether we have location lists that need outputting */
+static unsigned have_location_lists;
+
/* A pointer to the base of a list of incomplete types which might be
completed at some later time. */
static void add_AT_loc PARAMS ((dw_die_ref,
enum dwarf_attribute,
dw_loc_descr_ref));
+static void add_AT_loc_list PARAMS ((dw_die_ref,
+ enum dwarf_attribute,
+ dw_loc_list_ref));
static void add_AT_addr PARAMS ((dw_die_ref,
enum dwarf_attribute,
rtx));
static int is_type_die PARAMS ((dw_die_ref));
static int is_comdat_die PARAMS ((dw_die_ref));
static int is_symbol_die PARAMS ((dw_die_ref));
-static char *gen_internal_sym PARAMS ((void));
static void assign_symbol_names PARAMS ((dw_die_ref));
static void break_out_includes PARAMS ((dw_die_ref));
static void add_sibling_attributes PARAMS ((dw_die_ref));
static void build_abbrev_table PARAMS ((dw_die_ref));
+static void output_location_lists PARAMS ((dw_die_ref));
static unsigned long size_of_string PARAMS ((const char *));
static int constant_size PARAMS ((long unsigned));
static unsigned long size_of_die PARAMS ((dw_die_ref));
static rtx save_rtx PARAMS ((rtx));
static void splice_child_die PARAMS ((dw_die_ref, dw_die_ref));
static int file_info_cmp PARAMS ((const void *, const void *));
+static dw_loc_list_ref new_loc_list PARAMS ((dw_loc_descr_ref,
+ const char *, const char *,
+ const char *, unsigned));
+static void add_loc_descr_to_loc_list PARAMS ((dw_loc_list_ref *,
+ dw_loc_descr_ref,
+ const char *, const char *, const char *));
+static void output_loc_list PARAMS ((dw_loc_list_ref));
+static char *gen_internal_sym PARAMS ((const char *));
/* Section names used to hold DWARF debugging information. */
#ifndef DEBUG_INFO_SECTION
#define DEBUG_INFO_SECTION ".debug_info"
#endif
-#ifndef ABBREV_SECTION
-#define ABBREV_SECTION ".debug_abbrev"
+#ifndef DEBUG_ABBREV_SECTION
+#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
-#ifndef ARANGES_SECTION
-#define ARANGES_SECTION ".debug_aranges"
+#ifndef DEBUG_ARANGES_SECTION
+#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
-#ifndef DW_MACINFO_SECTION
-#define DW_MACINFO_SECTION ".debug_macinfo"
+#ifndef DEBUG_MACINFO_SECTION
+#define DEBUG_MACINFO_SECTION ".debug_macinfo"
#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
-#ifndef LOC_SECTION
-#define LOC_SECTION ".debug_loc"
+#ifndef DEBUG_LOC_SECTION
+#define DEBUG_LOC_SECTION ".debug_loc"
#endif
-#ifndef PUBNAMES_SECTION
-#define PUBNAMES_SECTION ".debug_pubnames"
+#ifndef DEBUG_PUBNAMES_SECTION
+#define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
#endif
-#ifndef STR_SECTION
-#define STR_SECTION ".debug_str"
+#ifndef DEBUG_STR_SECTION
+#define DEBUG_STR_SECTION ".debug_str"
#endif
/* Standard ELF section names for compiled code and data. */
the section names themselves. */
#ifndef TEXT_SECTION_LABEL
-#define TEXT_SECTION_LABEL "Ltext"
+#define TEXT_SECTION_LABEL "Ltext"
#endif
#ifndef DEBUG_LINE_SECTION_LABEL
-#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
+#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
#endif
#ifndef DEBUG_INFO_SECTION_LABEL
-#define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
+#define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
#endif
-#ifndef ABBREV_SECTION_LABEL
-#define ABBREV_SECTION_LABEL "Ldebug_abbrev"
+#ifndef DEBUG_ABBREV_SECTION_LABEL
+#define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev"
+#endif
+#ifndef DEBUG_LOC_SECTION_LABEL
+#define DEBUG_LOC_SECTION_LABEL "Ldebug_loc"
+#endif
+#ifndef DEBUG_MACINFO_SECTION_LABEL
+#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
#endif
-
/* Definitions of defaults for formats and names of various special
(artificial) labels which may be generated within this file (when the -g
options is used and DWARF_DEBUGGING_INFO is in effect.
static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
-
+static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
#ifndef TEXT_END_LABEL
#define TEXT_END_LABEL "Letext"
#endif
{
return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
|| (GET_CODE (rtl) == SUBREG
- && REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER));
+ && REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
}
/* Return a reference to a type, with its const and volatile qualifiers
abort ();
}
+static inline void
+add_AT_loc_list (die, attr_kind, loc_list)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register dw_loc_list_ref loc_list;
+{
+ 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_list;
+ attr->dw_attr_val.v.val_loc_list = loc_list;
+ add_dwarf_attr (die, attr);
+ have_location_lists = 1;
+}
+
+static inline dw_loc_list_ref AT_loc_list PARAMS ((dw_attr_ref));
+
+static inline dw_loc_list_ref
+AT_loc_list (a)
+ register dw_attr_ref a;
+{
+ if (a && AT_class (a) == dw_val_class_loc_list)
+ return a->dw_attr_val.v.val_loc_list;
+
+ abort ();
+}
+
/* Add an address constant attribute value to a DIE. */
static inline void
case dw_val_class_loc:
fprintf (outfile, "location descriptor");
break;
+ case dw_val_class_loc_list:
+ fprintf (outfile, "location list -> label:%s", AT_loc_list (a)->ll_symbol);
+ break;
case dw_val_class_const:
fprintf (outfile, "%ld", AT_int (a));
break;
{
if (is_type_die (c))
return 1;
- if (get_AT (c, DW_AT_declaration)
+ if (get_AT (c, DW_AT_declaration)
&& ! get_AT (c, DW_AT_specification))
return 1;
return 0;
}
static char *
-gen_internal_sym ()
+gen_internal_sym (prefix)
+ const char *prefix;
{
char buf[256];
static int label_num;
- ASM_GENERATE_INTERNAL_LABEL (buf, "LDIE", label_num++);
+ ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
return xstrdup (buf);
}
die->die_symbol = xstrdup (p);
}
else
- die->die_symbol = gen_internal_sym ();
+ die->die_symbol = gen_internal_sym ("LDIE");
}
for (c = die->die_child; c != NULL; c = c->die_sib)
add_sibling_attributes (c);
}
+/* Output all location lists for the DIE and it's children */
+static void
+output_location_lists (die)
+ register dw_die_ref die;
+{
+ dw_die_ref c;
+ dw_attr_ref d_attr;
+ for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
+ {
+ if (AT_class (d_attr) == dw_val_class_loc_list)
+ {
+ output_loc_list (AT_loc_list (d_attr));
+ }
+ }
+ for (c = die->die_child; c != NULL; c = c->die_sib)
+ output_location_lists (c);
+
+}
/* The format of each DIE (and its attribute value pairs)
is encoded in an abbreviation table. This routine builds the
abbreviation table and assigns a unique abbreviation id for
register dw_die_ref die;
{
register unsigned long abbrev_id;
- register unsigned long n_alloc;
+ register unsigned int n_alloc;
register dw_die_ref c;
register dw_attr_ref d_attr, a_attr;
size += lsize;
}
break;
+ case dw_val_class_loc_list:
+ size += DWARF_OFFSET_SIZE;
+ break;
case dw_val_class_const:
size += size_of_sleb128 (AT_int (a));
break;
{
case dw_val_class_addr:
return DW_FORM_addr;
+ case dw_val_class_loc_list:
+ /* FIXME: Could be DW_FORM_data8, with a > 32 bit size
+ .debug_loc section */
+ return DW_FORM_data4;
case dw_val_class_loc:
switch (constant_size (size_of_locs (AT_loc (a))))
{
ASM_OUTPUT_LABEL (asm_out_file, sym);
}
+/* Return a new location list, given the begin and end range, and the
+ expression. gensym tells us whether to generate a new internal
+ symbol for this location list node, which is done for the head of
+ the list only. */
+static inline dw_loc_list_ref
+new_loc_list (expr, begin, end, section, gensym)
+ register dw_loc_descr_ref expr;
+ register const char *begin;
+ register const char *end;
+ register const char *section;
+ register unsigned gensym;
+{
+ register dw_loc_list_ref retlist
+ = (dw_loc_list_ref) xcalloc (1, sizeof (dw_loc_list_node));
+ retlist->begin = begin;
+ retlist->end = end;
+ retlist->expr = expr;
+ retlist->section = section;
+ if (gensym)
+ retlist->ll_symbol = gen_internal_sym ("LLST");
+ return retlist;
+}
+
+/* Add a location description expression to a location list */
+static inline void
+add_loc_descr_to_loc_list (list_head, descr, begin, end, section)
+ register dw_loc_list_ref *list_head;
+ register dw_loc_descr_ref descr;
+ register const char *begin;
+ register const char *end;
+ register const char *section;
+{
+ register dw_loc_list_ref *d;
+
+ /* Find the end of the chain. */
+ for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
+ ;
+ /* Add a new location list node to the list */
+ *d = new_loc_list (descr, begin, end, section, 0);
+}
+
+
+
+/* Output the location list given to us */
+static void
+output_loc_list (list_head)
+ register dw_loc_list_ref list_head;
+{
+ register dw_loc_list_ref curr=list_head;
+ ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
+ if (strcmp (curr->section, ".text") == 0)
+ {
+ /* dw2_asm_output_data will mask off any extra bits in the ~0. */
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, ~(unsigned HOST_WIDE_INT)0,
+ "Location list base address specifier fake entry");
+ dw2_asm_output_offset (DWARF2_ADDR_SIZE, curr->section,
+ "Location list base address specifier base");
+ }
+ for (curr = list_head; curr != NULL; curr=curr->dw_loc_next)
+ {
+ int size;
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
+ "Location list begin address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
+ "Location list end address (%s)",
+ list_head->ll_symbol);
+ size = size_of_locs (curr->expr);
+
+ /* Output the block length for this list of location operations. */
+ dw2_asm_output_data (constant_size (size), size, "%s",
+ "Location expression size");
+
+ output_loc_sequence (curr->expr);
+ }
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
+ "Location list terminator begin (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
+ "Location list terminator end (%s)",
+ list_head->ll_symbol);
+}
/* Output the DIE and its attributes. Called recursively to generate
the definitions of each child DIE. */
case dw_val_class_flag:
dw2_asm_output_data (1, AT_flag (a), "%s", name);
break;
-
+ case dw_val_class_loc_list:
+ {
+ char *sym = AT_loc_list (a)->ll_symbol;
+ if (sym == 0)
+ abort();
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, name);
+ }
+ break;
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
{
const char *secname;
- if (die->die_child == 0)
- return;
-
- /* Mark all the DIEs in this CU so we know which get local refs. */
+ /* Even if there are no children of this DIE, we must output the
+ information about the compilation unit. Otherwise, on an empty
+ translation unit, we will generate a present, but empty,
+ .debug_info section. IRIX 6.5 `nm' will then complain when
+ examining the file.
+
+ Mark all the DIEs in this CU so we know which get local refs. */
mark_dies (die);
build_abbrev_table (die);
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;
+ tree qualified_type;
+
+ /* See if we already have the appropriately qualified variant of
+ this type. */
+ qualified_type
+ = get_qualified_type (type,
+ ((is_const_type ? TYPE_QUAL_CONST : 0)
+ | (is_volatile_type
+ ? TYPE_QUAL_VOLATILE : 0)));
+ /* If we do, then we can just use its DIE, if it exists. */
+ if (qualified_type)
+ {
+ mod_type_die = lookup_type_die (qualified_type);
+ if (mod_type_die)
+ return mod_type_die;
+ }
/* Handle C typedef types. */
- if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+ if (qualified_type && TYPE_NAME (qualified_type)
+ && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (qualified_type)))
{
- tree dtype = TREE_TYPE (TYPE_NAME (type));
- if (type == dtype)
+ tree type_name = TYPE_NAME (qualified_type);
+ tree dtype = TREE_TYPE (type_name);
+ if (qualified_type == dtype)
{
/* For a named type, use the typedef. */
- gen_type_die (type, context_die);
- mod_type_die = lookup_type_die (type);
+ gen_type_die (qualified_type, context_die);
+ mod_type_die = lookup_type_die (qualified_type);
}
else if (is_const_type < TYPE_READONLY (dtype)
/* cv-unqualified version of named type. Just use the unnamed
type to which it refers. */
mod_type_die
- = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)),
+ = modified_type_die (DECL_ORIGINAL_TYPE (type_name),
is_const_type, is_volatile_type,
context_die);
/* Else cv-qualified version of named type; fall through. */
if (mod_type_die == NULL)
abort ();
}
+
+ /* We want to equate the qualified type to the die below. */
+ if (qualified_type)
+ type = qualified_type;
}
equate_type_number_to_die (type, mod_type_die);
up an entire register. For now, just assume that it is
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
- rtl = XEXP (rtl, 0);
+ rtl = SUBREG_REG (rtl);
/* Fall through. */
pool. */
case CONST:
case SYMBOL_REF:
+ /* Alternatively, the symbol in the constant pool might be referenced
+ by a different symbol. */
+ if (GET_CODE (rtl) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (rtl))
+ {
+ rtx tmp = get_pool_constant (rtl);
+ if (GET_CODE (tmp) == SYMBOL_REF)
+ rtl = tmp;
+ }
+
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 = save_rtx (rtl);
case PRE_MODIFY:
/* Extract the PLUS expression nested inside and fall into
- PLUS code bellow. */
+ PLUS code below. */
rtl = XEXP (rtl, 1);
goto plus;
up an entire register. For now, just assume that it is
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
- rtl = XEXP (rtl, 0);
+ rtl = SUBREG_REG (rtl);
/* Fall through. */
case COMPONENT_REF:
case BIT_FIELD_REF:
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
of a function which we may later generate inlined and/or
out-of-line instances of. */
-void
+static void
dwarf2out_abstract_function (decl)
tree decl;
{
/* Be sure we've emitted the in-class declaration DIE (if any) first, so
we don't get confused by DECL_ABSTRACT. */
- context = decl_class_context (decl);
- if (context)
- gen_type_die_for_member
- (context, decl, decl_function_context (decl) ? NULL : comp_unit_die);
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ {
+ context = decl_class_context (decl);
+ if (context)
+ gen_type_die_for_member
+ (context, decl, decl_function_context (decl) ? NULL : comp_unit_die);
+ }
/* Pretend we've just finished compiling this function. */
save_fn = current_function_decl;
}
}
+/* Debug information for a global DECL. Called from toplev.c after
+ compilation proper has finished. */
+static void
+dwarf2out_global_decl (decl)
+ tree decl;
+{
+ /* Output DWARF2 information for file-scope tentative data object
+ declarations, file-scope (extern) function declarations (which
+ had no corresponding body) and file-scope tagged type
+ declarations and definitions which have not yet been forced out. */
+
+ if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
+ dwarf2out_decl (decl);
+}
+
/* Write the debugging output for DECL. */
void
/* Output a marker (i.e. a label) for the beginning of the generated code for
a lexical block. */
-void
-dwarf2out_begin_block (blocknum)
- register unsigned blocknum;
+static void
+dwarf2out_begin_block (line, blocknum)
+ unsigned int line ATTRIBUTE_UNUSED;
+ unsigned int blocknum;
{
function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
/* Output a marker (i.e. a label) for the end of the generated code for a
lexical block. */
-void
-dwarf2out_end_block (blocknum)
- register unsigned blocknum;
+static void
+dwarf2out_end_block (line, blocknum)
+ unsigned int line ATTRIBUTE_UNUSED;
+ unsigned int blocknum;
{
function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
as we would end up with orphans, and in the presence of scheduling
we may end up calling them anyway. */
-int
+static bool
dwarf2out_ignore_block (block)
tree block;
{
and record information relating to this source line, in
'line_info_table' for later output of the .debug_line section. */
-void
-dwarf2out_line (filename, line)
+static void
+dwarf2out_source_line (line, filename)
+ unsigned int line;
register const char *filename;
- register unsigned line;
{
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
function_section (current_function_decl);
+ /* If requested, emit something human-readable. */
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
+ filename, line);
+
if (DWARF2_ASM_LINE_DEBUG_INFO)
{
unsigned file_num = lookup_filename (filename);
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);
- if (flag_debug_asm)
- fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
- filename, line);
/* expand the line info table if necessary */
if (separate_line_info_table_in_use
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
line_info_table_in_use);
- if (flag_debug_asm)
- fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
- filename, line);
/* Expand the line info table if necessary. */
if (line_info_table_in_use == line_info_table_allocated)
}
}
-/* Record the beginning of a new source file, for later output
- of the .debug_macinfo section. At present, unimplemented. */
+/* Record the beginning of a new source file. */
-void
-dwarf2out_start_source_file (filename)
- register const char *filename ATTRIBUTE_UNUSED;
+static void
+dwarf2out_start_source_file (lineno, filename)
+ register unsigned int lineno;
+ register const char *filename;
{
if (flag_eliminate_dwarf2_dups)
{
dw_die_ref bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die);
add_AT_string (bincl_die, DW_AT_name, filename);
}
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+ dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+ dw2_asm_output_data_uleb128 (lineno, "Included from line number %d", lineno);
+ dw2_asm_output_data_uleb128 (lookup_filename (filename), "Filename we just started");
+ }
}
-/* Record the end of a source file, for later output
- of the .debug_macinfo section. At present, unimplemented. */
+/* Record the end of a source file. */
-void
-dwarf2out_end_source_file ()
+static void
+dwarf2out_end_source_file (lineno)
+ unsigned int lineno ATTRIBUTE_UNUSED;
{
if (flag_eliminate_dwarf2_dups)
{
/* Record the end of the file for break_out_includes. */
new_die (DW_TAG_GNU_EINCL, comp_unit_die);
}
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+ dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+ }
}
-/* Called from check_newline in c-parse.y. The `buffer' parameter contains
+/* Called from debug_define in toplev.c. The `buffer' parameter contains
the tail part of the directive line, i.e. the part which is past the
initial whitespace, #, whitespace, directive-name, whitespace part. */
-void
+static void
dwarf2out_define (lineno, buffer)
register unsigned lineno ATTRIBUTE_UNUSED;
register const char *buffer ATTRIBUTE_UNUSED;
static int initialized = 0;
if (!initialized)
{
- dwarf2out_start_source_file (primary_filename);
+ dwarf2out_start_source_file (0, primary_filename);
initialized = 1;
}
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+ dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
+ dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
+ dw2_asm_output_nstring (buffer, -1, "The macro");
+ }
}
-/* Called from check_newline in c-parse.y. The `buffer' parameter contains
+/* Called from debug_undef in toplev.c. The `buffer' parameter contains
the tail part of the directive line, i.e. the part which is past the
initial whitespace, #, whitespace, directive-name, whitespace part. */
-void
+static void
dwarf2out_undef (lineno, buffer)
register unsigned lineno ATTRIBUTE_UNUSED;
register const char *buffer ATTRIBUTE_UNUSED;
{
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+ dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
+ dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
+ dw2_asm_output_nstring (buffer, -1, "The macro");
+ }
}
/* Set up for Dwarf output at the start of compilation. */
-void
-dwarf2out_init (asm_out_file, main_input_filename)
- register FILE *asm_out_file;
+static void
+dwarf2out_init (main_input_filename)
register const char *main_input_filename;
{
init_file_table ();
ggc_add_rtx_varray_root (&used_rtx_varray, 1);
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 (abbrev_section_label,
+ DEBUG_ABBREV_SECTION_LABEL, 0);
if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
else
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_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LOC_SECTION);
+ ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ABBREV_SECTION);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
{
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);
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+ ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
+ DEBUG_MACINFO_SECTION_LABEL, 0);
+ ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+ }
}
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
-void
-dwarf2out_finish ()
+static void
+dwarf2out_finish (input_filename)
+ register const char *input_filename ATTRIBUTE_UNUSED;
{
limbo_die_node *node, *next_node;
- dw_die_ref die;
+ dw_die_ref die = 0;
/* Traverse the limbo die list, and add parent/child links. The only
dies without parents that should be here are concrete instances of
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
#endif
- /* Output the source line correspondence table. */
- if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
+ /* Output the source line correspondence table. We must do this
+ even if there is no line information. Otherwise, on an empty
+ translation unit, we will generate a present, but empty,
+ .debug_info section. IRIX 6.5 `nm' will then complain when
+ examining the file. */
+ if (! DWARF2_ASM_LINE_DEBUG_INFO)
{
- if (! DWARF2_ASM_LINE_DEBUG_INFO)
- {
- ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
- output_line_info ();
- }
-
- /* We can only use the low/high_pc attributes if all of the code
- was in .text. */
- 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);
- }
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
+ output_line_info ();
+ }
- add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
- debug_line_section_label);
+ /* We can only use the low/high_pc attributes if all of the code was
+ in .text. */
+ 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);
}
-#if 0 /* unimplemented */
- if (debug_info_level >= DINFO_LEVEL_VERBOSE && primary)
- add_AT_unsigned (die, DW_AT_macro_info, 0);
-#endif
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
+ debug_line_section_label);
+
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ add_AT_lbl_offset (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
/* Output all of the compilation units. We put the main one last so that
the offsets are available to output_pubnames. */
output_comp_unit (comp_unit_die);
/* Output the abbreviation table. */
- ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ABBREV_SECTION);
output_abbrev_section ();
if (pubname_table_in_use)
{
/* Output public names table. */
- ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_PUBNAMES_SECTION);
output_pubnames ();
}
if (fde_table_in_use)
{
/* Output the address range information. */
- ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ARANGES_SECTION);
output_aranges ();
}
+ /* Output location list section if necessary */
+ if (have_location_lists)
+ {
+ /* Output the location lists info. */
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LOC_SECTION);
+ output_location_lists (die);
+ have_location_lists = 0;
+ }
+
+ /* Have to end the primary source file. */
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+ dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+ }
+
}
#endif /* DWARF2_DEBUGGING_INFO */