aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/dwarf2out.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/dwarf2out.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/dwarf2out.c15913
1 files changed, 15913 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/dwarf2out.c b/gcc-4.2.1-5666.3/gcc/dwarf2out.c
new file mode 100644
index 000000000..ed41d2450
--- /dev/null
+++ b/gcc-4.2.1-5666.3/gcc/dwarf2out.c
@@ -0,0 +1,15913 @@
+/* Output Dwarf2 format symbol table information from GCC.
+ Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Contributed by Gary Funck (gary@intrepid.com).
+ Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
+ Extensively modified by Jason Merrill (jason@cygnus.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+/* TODO: Emit .debug_line header even when there are no functions, since
+ the file numbers are used by .debug_info. Alternately, leave
+ out locations for types and decls.
+ Avoid talking about ctors and op= for PODs.
+ Factor out common prologue sequences into multiple CIEs. */
+
+/* The first part of this file deals with the DWARF 2 frame unwind
+ information, which is also used by the GCC efficient exception handling
+ mechanism. The second part, controlled only by an #ifdef
+ DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
+ information. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "version.h"
+/* APPLE LOCAL radar 2338865 optimization notification */
+#include "options.h"
+#include "flags.h"
+#include "real.h"
+#include "rtl.h"
+#include "hard-reg-set.h"
+#include "regs.h"
+#include "insn-config.h"
+#include "reload.h"
+#include "function.h"
+#include "output.h"
+#include "expr.h"
+#include "libfuncs.h"
+#include "except.h"
+#include "dwarf2.h"
+#include "dwarf2out.h"
+#include "dwarf2asm.h"
+#include "toplev.h"
+#include "varray.h"
+#include "ggc.h"
+#include "md5.h"
+#include "tm_p.h"
+#include "diagnostic.h"
+#include "debug.h"
+#include "target.h"
+#include "langhooks.h"
+#include "hashtab.h"
+#include "cgraph.h"
+#include "input.h"
+
+#ifdef DWARF2_DEBUGGING_INFO
+static void dwarf2out_source_line (unsigned int, const char *);
+#endif
+
+/* DWARF2 Abbreviation Glossary:
+ CFA = Canonical Frame Address
+ a fixed address on the stack which identifies a call frame.
+ We define it to be the value of SP just before the call insn.
+ The CFA register and offset, which may change during the course
+ of the function, are used to calculate its value at runtime.
+ CFI = Call Frame Instruction
+ an instruction for the DWARF2 abstract machine
+ CIE = Common Information Entry
+ information describing information common to one or more FDEs
+ DIE = Debugging Information Entry
+ FDE = Frame Description Entry
+ information describing the stack call frame, in particular,
+ how to restore registers
+
+ DW_CFA_... = DWARF2 CFA call frame instruction
+ DW_TAG_... = DWARF2 DIE tag */
+
+#ifndef DWARF2_FRAME_INFO
+# ifdef DWARF2_DEBUGGING_INFO
+# define DWARF2_FRAME_INFO \
+ (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+# else
+# define DWARF2_FRAME_INFO 0
+# endif
+#endif
+
+/* Map register numbers held in the call frame info that gcc has
+ collected using DWARF_FRAME_REGNUM to those that should be output in
+ .debug_frame and .eh_frame. */
+#ifndef DWARF2_FRAME_REG_OUT
+#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
+#endif
+
+/* Decide whether we want to emit frame unwind information for the current
+ translation unit. */
+
+int
+dwarf2out_do_frame (void)
+{
+ /* We want to emit correct CFA location expressions or lists, so we
+ have to return true if we're going to output debug info, even if
+ we're not going to output frame or unwind info. */
+ return (write_symbols == DWARF2_DEBUG
+ || write_symbols == VMS_AND_DWARF2_DEBUG
+ || DWARF2_FRAME_INFO
+#ifdef DWARF2_UNWIND_INFO
+ || (DWARF2_UNWIND_INFO
+ && (flag_unwind_tables
+ || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
+#endif
+ );
+}
+
+/* The size of the target's pointer type. */
+#ifndef PTR_SIZE
+#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
+/* Array of RTXes referenced by the debugging information, which therefore
+ must be kept around forever. */
+static GTY(()) VEC(rtx,gc) *used_rtx_array;
+
+/* A pointer to the base of a list of incomplete types which might be
+ completed at some later time. incomplete_types_list needs to be a
+ VEC(tree,gc) because we want to tell the garbage collector about
+ it. */
+static GTY(()) VEC(tree,gc) *incomplete_types;
+
+/* A pointer to the base of a table of references to declaration
+ scopes. This table is a display which tracks the nesting
+ of declaration scopes at the current scope and containing
+ scopes. This table is used to find the proper place to
+ define type declaration DIE's. */
+static GTY(()) VEC(tree,gc) *decl_scope_table;
+
+/* Pointers to various DWARF2 sections. */
+static GTY(()) section *debug_info_section;
+static GTY(()) section *debug_abbrev_section;
+static GTY(()) section *debug_aranges_section;
+static GTY(()) section *debug_macinfo_section;
+static GTY(()) section *debug_line_section;
+static GTY(()) section *debug_loc_section;
+static GTY(()) section *debug_pubnames_section;
+/* APPLE LOCAL pubtypes, approved for 4.3 4535968 */
+static GTY(()) section *debug_pubtypes_section;
+static GTY(()) section *debug_str_section;
+static GTY(()) section *debug_ranges_section;
+static GTY(()) section *debug_frame_section;
+/* APPLE LOCAL radar 6275985 debug inlined section */
+static GTY(()) section *debug_inlined_section;
+
+/* How to start an assembler comment. */
+#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;
+
+/* Call frames are described using a sequence of Call Frame
+ Information instructions. The register number, offset
+ and address fields are provided as possible operands;
+ their use is selected by the opcode field. */
+
+enum dw_cfi_oprnd_type {
+ dw_cfi_oprnd_unused,
+ dw_cfi_oprnd_reg_num,
+ dw_cfi_oprnd_offset,
+ dw_cfi_oprnd_addr,
+ dw_cfi_oprnd_loc
+};
+
+typedef union dw_cfi_oprnd_struct GTY(())
+{
+ unsigned int GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num;
+ HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset;
+ const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr;
+ struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc;
+}
+dw_cfi_oprnd;
+
+typedef struct dw_cfi_struct GTY(())
+{
+ dw_cfi_ref dw_cfi_next;
+ enum dwarf_call_frame_info dw_cfi_opc;
+ dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)")))
+ dw_cfi_oprnd1;
+ dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)")))
+ dw_cfi_oprnd2;
+}
+dw_cfi_node;
+
+/* This is how we define the location of the CFA. We use to handle it
+ as REG + OFFSET all the time, but now it can be more complex.
+ It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
+ Instead of passing around REG and OFFSET, we pass a copy
+ of this structure. */
+typedef struct cfa_loc GTY(())
+{
+ HOST_WIDE_INT offset;
+ HOST_WIDE_INT base_offset;
+ unsigned int reg;
+ int indirect; /* 1 if CFA is accessed via a dereference. */
+} dw_cfa_location;
+
+/* All call frame descriptions (FDE's) in the GCC generated DWARF
+ refer to a single Common Information Entry (CIE), defined at
+ the beginning of the .debug_frame section. This use of a single
+ CIE obviates the need to keep track of multiple CIE's
+ in the DWARF generation routines below. */
+
+typedef struct dw_fde_struct GTY(())
+{
+ tree decl;
+ const char *dw_fde_begin;
+ const char *dw_fde_current_label;
+ const char *dw_fde_end;
+ const char *dw_fde_hot_section_label;
+ const char *dw_fde_hot_section_end_label;
+ const char *dw_fde_unlikely_section_label;
+ const char *dw_fde_unlikely_section_end_label;
+ bool dw_fde_switched_sections;
+ dw_cfi_ref dw_fde_cfi;
+ unsigned funcdef_number;
+ unsigned all_throwers_are_sibcalls : 1;
+ unsigned nothrow : 1;
+ unsigned uses_eh_lsda : 1;
+}
+dw_fde_node;
+
+/* Maximum size (in bytes) of an artificially generated label. */
+#define MAX_ARTIFICIAL_LABEL_BYTES 30
+
+/* The size of addresses as they appear in the Dwarf 2 data.
+ Some architectures use word addresses to refer to code locations,
+ but Dwarf 2 info always uses byte addresses. On such machines,
+ Dwarf 2 addresses need to be larger than the architecture's
+ pointers. */
+#ifndef DWARF2_ADDR_SIZE
+#define DWARF2_ADDR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
+/* The size in bytes of a DWARF field indicating an offset or length
+ relative to a debug info section, specified to be 4 bytes in the
+ DWARF-2 specification. The SGI/MIPS ABI defines it to be the same
+ as PTR_SIZE. */
+
+#ifndef DWARF_OFFSET_SIZE
+#define DWARF_OFFSET_SIZE 4
+#endif
+
+/* According to the (draft) DWARF 3 specification, the initial length
+ should either be 4 or 12 bytes. When it's 12 bytes, the first 4
+ bytes are 0xffffffff, followed by the length stored in the next 8
+ bytes.
+
+ However, the SGI/MIPS ABI uses an initial length which is equal to
+ DWARF_OFFSET_SIZE. It is defined (elsewhere) accordingly. */
+
+#ifndef DWARF_INITIAL_LENGTH_SIZE
+#define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12)
+#endif
+
+#define DWARF_VERSION 2
+
+/* Round SIZE up to the nearest BOUNDARY. */
+#define DWARF_ROUND(SIZE,BOUNDARY) \
+ ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
+
+/* Offsets recorded in opcodes are a multiple of this alignment factor. */
+#ifndef DWARF_CIE_DATA_ALIGNMENT
+#ifdef STACK_GROWS_DOWNWARD
+#define DWARF_CIE_DATA_ALIGNMENT (-((int) UNITS_PER_WORD))
+#else
+#define DWARF_CIE_DATA_ALIGNMENT ((int) UNITS_PER_WORD)
+#endif
+#endif
+
+/* CIE identifier. */
+#if HOST_BITS_PER_WIDE_INT >= 64
+#define DWARF_CIE_ID \
+ (unsigned HOST_WIDE_INT) (DWARF_OFFSET_SIZE == 4 ? DW_CIE_ID : DW64_CIE_ID)
+#else
+#define DWARF_CIE_ID DW_CIE_ID
+#endif
+
+/* A pointer to the base of a table that contains frame description
+ information for each routine. */
+static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
+
+/* Number of elements currently allocated for fde_table. */
+static GTY(()) unsigned fde_table_allocated;
+
+/* Number of elements in fde_table currently in use. */
+static GTY(()) unsigned fde_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ fde_table. */
+#define FDE_TABLE_INCREMENT 256
+
+/* A list of call frame insns for the CIE. */
+static GTY(()) dw_cfi_ref cie_cfi_head;
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
+ attribute that accelerates the lookup of the FDE associated
+ with the subprogram. This variable holds the table index of the FDE
+ associated with the current function (body) definition. */
+static unsigned current_funcdef_fde;
+#endif
+
+struct indirect_string_node GTY(())
+{
+ const char *str;
+ unsigned int refcount;
+ unsigned int form;
+ /* APPLE LOCAL radar 6275985 debug inlined section */
+ bool is_fn_name;
+ char *label;
+};
+
+static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
+
+static GTY(()) int dw2_string_counter;
+static GTY(()) unsigned long dwarf2out_cfi_label_num;
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+/* Forward declarations for functions defined in this file. */
+
+static char *stripattributes (const char *);
+static const char *dwarf_cfi_name (unsigned);
+static dw_cfi_ref new_cfi (void);
+static void add_cfi (dw_cfi_ref *, dw_cfi_ref);
+static void add_fde_cfi (const char *, dw_cfi_ref);
+static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *);
+static void lookup_cfa (dw_cfa_location *);
+static void reg_save (const char *, unsigned, unsigned, HOST_WIDE_INT);
+static void initial_return_save (rtx);
+static HOST_WIDE_INT stack_adjust_offset (rtx);
+static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
+static void output_call_frame_info (int);
+static void dwarf2out_stack_adjust (rtx, bool);
+static void flush_queued_reg_saves (void);
+static bool clobbers_queued_reg_save (rtx);
+static void dwarf2out_frame_debug_expr (rtx, const char *);
+
+/* Support for complex CFA locations. */
+static void output_cfa_loc (dw_cfi_ref);
+static void get_cfa_from_loc_descr (dw_cfa_location *,
+ struct dw_loc_descr_struct *);
+static struct dw_loc_descr_struct *build_cfa_loc
+ (dw_cfa_location *, HOST_WIDE_INT);
+static void def_cfa_1 (const char *, dw_cfa_location *);
+
+/* How to start an assembler comment. */
+#ifndef ASM_COMMENT_START
+#define ASM_COMMENT_START ";#"
+#endif
+
+/* Data and reference forms for relocatable data. */
+#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
+#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
+
+#ifndef DEBUG_FRAME_SECTION
+#define DEBUG_FRAME_SECTION ".debug_frame"
+#endif
+
+#ifndef FUNC_BEGIN_LABEL
+#define FUNC_BEGIN_LABEL "LFB"
+#endif
+
+#ifndef FUNC_END_LABEL
+#define FUNC_END_LABEL "LFE"
+#endif
+
+#ifndef FRAME_BEGIN_LABEL
+#define FRAME_BEGIN_LABEL "Lframe"
+#endif
+#define CIE_AFTER_SIZE_LABEL "LSCIE"
+#define CIE_END_LABEL "LECIE"
+#define FDE_LABEL "LSFDE"
+#define FDE_AFTER_SIZE_LABEL "LASFDE"
+#define FDE_END_LABEL "LEFDE"
+#define LINE_NUMBER_BEGIN_LABEL "LSLT"
+#define LINE_NUMBER_END_LABEL "LELT"
+#define LN_PROLOG_AS_LABEL "LASLTP"
+#define LN_PROLOG_END_LABEL "LELTP"
+#define DIE_LABEL_PREFIX "DW"
+
+/* The DWARF 2 CFA column which tracks the return address. Normally this
+ is the column for PC, or the first column after all of the hard
+ registers. */
+#ifndef DWARF_FRAME_RETURN_COLUMN
+#ifdef PC_REGNUM
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM)
+#else
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGISTERS
+#endif
+#endif
+
+/* The mapping from gcc register number to DWARF 2 CFA column number. By
+ default, we just provide columns for all registers. */
+#ifndef DWARF_FRAME_REGNUM
+#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
+#endif
+
+/* APPLE LOCAL begin differentiate between arm & thumb. */
+#define DW_ISA_UNKNOWN 0
+#define DW_ISA_ARM_thumb 1
+#define DW_ISA_ARM_arm 2
+#define DW_ISA_USE_STMT_LIST -1
+/* APPLE LOCAL end differentiate between arm & thumb. */
+
+/* Hook used by __throw. */
+
+rtx
+expand_builtin_dwarf_sp_column (void)
+{
+ unsigned int dwarf_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
+ return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1));
+}
+
+/* Return a pointer to a copy of the section string name S with all
+ attributes stripped off, and an asterisk prepended (for assemble_name). */
+
+static inline char *
+stripattributes (const char *s)
+{
+ char *stripped = XNEWVEC (char, strlen (s) + 2);
+ char *p = stripped;
+
+ *p++ = '*';
+
+ while (*s && *s != ',')
+ *p++ = *s++;
+
+ *p = '\0';
+ return stripped;
+}
+
+/* Generate code to initialize the register size table. */
+
+void
+expand_builtin_init_dwarf_reg_sizes (tree address)
+{
+ unsigned int i;
+ enum machine_mode mode = TYPE_MODE (char_type_node);
+ rtx addr = expand_normal (address);
+ rtx mem = gen_rtx_MEM (BLKmode, addr);
+ bool wrote_return_column = false;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ int rnum = DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), 1);
+
+ if (rnum < DWARF_FRAME_REGISTERS)
+ {
+ HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
+ enum machine_mode save_mode = reg_raw_mode[i];
+ HOST_WIDE_INT size;
+
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
+ save_mode = choose_hard_reg_mode (i, 1, true);
+ if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
+ {
+ if (save_mode == VOIDmode)
+ continue;
+ wrote_return_column = true;
+ }
+ size = GET_MODE_SIZE (save_mode);
+ if (offset < 0)
+ continue;
+
+ emit_move_insn (adjust_address (mem, mode, offset),
+ gen_int_mode (size, mode));
+ }
+ }
+
+#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
+ gcc_assert (wrote_return_column);
+ i = DWARF_ALT_FRAME_RETURN_COLUMN;
+ wrote_return_column = false;
+#else
+ i = DWARF_FRAME_RETURN_COLUMN;
+#endif
+
+ if (! wrote_return_column)
+ {
+ enum machine_mode save_mode = Pmode;
+ HOST_WIDE_INT offset = i * GET_MODE_SIZE (mode);
+ HOST_WIDE_INT size = GET_MODE_SIZE (save_mode);
+ emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
+ }
+}
+
+/* Convert a DWARF call frame info. operation to its string name */
+
+static const char *
+dwarf_cfi_name (unsigned int cfi_opc)
+{
+ switch (cfi_opc)
+ {
+ case DW_CFA_advance_loc:
+ return "DW_CFA_advance_loc";
+ case DW_CFA_offset:
+ return "DW_CFA_offset";
+ case DW_CFA_restore:
+ return "DW_CFA_restore";
+ case DW_CFA_nop:
+ return "DW_CFA_nop";
+ case DW_CFA_set_loc:
+ return "DW_CFA_set_loc";
+ case DW_CFA_advance_loc1:
+ return "DW_CFA_advance_loc1";
+ case DW_CFA_advance_loc2:
+ return "DW_CFA_advance_loc2";
+ case DW_CFA_advance_loc4:
+ return "DW_CFA_advance_loc4";
+ case DW_CFA_offset_extended:
+ return "DW_CFA_offset_extended";
+ case DW_CFA_restore_extended:
+ return "DW_CFA_restore_extended";
+ case DW_CFA_undefined:
+ return "DW_CFA_undefined";
+ case DW_CFA_same_value:
+ return "DW_CFA_same_value";
+ case DW_CFA_register:
+ return "DW_CFA_register";
+ case DW_CFA_remember_state:
+ return "DW_CFA_remember_state";
+ case DW_CFA_restore_state:
+ return "DW_CFA_restore_state";
+ case DW_CFA_def_cfa:
+ return "DW_CFA_def_cfa";
+ case DW_CFA_def_cfa_register:
+ return "DW_CFA_def_cfa_register";
+ case DW_CFA_def_cfa_offset:
+ return "DW_CFA_def_cfa_offset";
+
+ /* DWARF 3 */
+ case DW_CFA_def_cfa_expression:
+ return "DW_CFA_def_cfa_expression";
+ case DW_CFA_expression:
+ return "DW_CFA_expression";
+ case DW_CFA_offset_extended_sf:
+ return "DW_CFA_offset_extended_sf";
+ case DW_CFA_def_cfa_sf:
+ return "DW_CFA_def_cfa_sf";
+ case DW_CFA_def_cfa_offset_sf:
+ return "DW_CFA_def_cfa_offset_sf";
+
+ /* SGI/MIPS specific */
+ case DW_CFA_MIPS_advance_loc8:
+ return "DW_CFA_MIPS_advance_loc8";
+
+ /* GNU extensions */
+ 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>";
+ }
+}
+
+/* Return a pointer to a newly allocated Call Frame Instruction. */
+
+static inline dw_cfi_ref
+new_cfi (void)
+{
+ dw_cfi_ref cfi = ggc_alloc (sizeof (dw_cfi_node));
+
+ cfi->dw_cfi_next = NULL;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
+ cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
+
+ return cfi;
+}
+
+/* Add a Call Frame Instruction to list of instructions. */
+
+static inline void
+add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi)
+{
+ dw_cfi_ref *p;
+
+ /* Find the end of the chain. */
+ for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
+ ;
+
+ *p = cfi;
+}
+
+/* Generate a new label for the CFI info to refer to. */
+
+char *
+dwarf2out_cfi_label (void)
+{
+ static char label[20];
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+ return label;
+}
+
+/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
+ or to the CIE if LABEL is NULL. */
+
+static void
+add_fde_cfi (const char *label, dw_cfi_ref cfi)
+{
+ if (label)
+ {
+ dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+
+ if (*label == 0)
+ label = dwarf2out_cfi_label ();
+
+ if (fde->dw_fde_current_label == NULL
+ || strcmp (label, fde->dw_fde_current_label) != 0)
+ {
+ dw_cfi_ref xcfi;
+
+ label = xstrdup (label);
+
+ /* Set the location counter to the new label. */
+ xcfi = new_cfi ();
+ /* If we have a current label, advance from there, otherwise
+ set the location directly using set_loc. */
+ xcfi->dw_cfi_opc = fde->dw_fde_current_label
+ ? DW_CFA_advance_loc4
+ : DW_CFA_set_loc;
+ xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+ add_cfi (&fde->dw_fde_cfi, xcfi);
+
+ fde->dw_fde_current_label = label;
+ }
+
+ add_cfi (&fde->dw_fde_cfi, cfi);
+ }
+
+ else
+ add_cfi (&cie_cfi_head, cfi);
+}
+
+/* Subroutine of lookup_cfa. */
+
+static void
+lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc)
+{
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_def_cfa_offset:
+ loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ loc->offset
+ = cfi->dw_cfi_oprnd1.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
+ break;
+ case DW_CFA_def_cfa_register:
+ loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+ break;
+ case DW_CFA_def_cfa:
+ loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+ loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
+ break;
+ case DW_CFA_def_cfa_sf:
+ loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+ loc->offset
+ = cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
+ break;
+ case DW_CFA_def_cfa_expression:
+ get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Find the previous value for the CFA. */
+
+static void
+lookup_cfa (dw_cfa_location *loc)
+{
+ dw_cfi_ref cfi;
+
+ loc->reg = INVALID_REGNUM;
+ loc->offset = 0;
+ loc->indirect = 0;
+ loc->base_offset = 0;
+
+ for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, loc);
+
+ if (fde_table_in_use)
+ {
+ dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+ for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, loc);
+ }
+}
+
+/* The current rule for calculating the DWARF2 canonical frame address. */
+static dw_cfa_location cfa;
+
+/* The register used for saving registers to the stack, and its offset
+ from the CFA. */
+static dw_cfa_location cfa_store;
+
+/* The running total of the size of arguments pushed onto the stack. */
+static HOST_WIDE_INT args_size;
+
+/* The last args_size we actually output. */
+static HOST_WIDE_INT old_args_size;
+
+/* Entry point to update the canonical frame address (CFA).
+ LABEL is passed to add_fde_cfi. The value of CFA is now to be
+ calculated from REG+OFFSET. */
+
+void
+dwarf2out_def_cfa (const char *label, unsigned int reg, HOST_WIDE_INT offset)
+{
+ dw_cfa_location loc;
+ loc.indirect = 0;
+ loc.base_offset = 0;
+ loc.reg = reg;
+ loc.offset = offset;
+ def_cfa_1 (label, &loc);
+}
+
+/* Determine if two dw_cfa_location structures define the same data. */
+
+static bool
+cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
+{
+ return (loc1->reg == loc2->reg
+ && loc1->offset == loc2->offset
+ && loc1->indirect == loc2->indirect
+ && (loc1->indirect == 0
+ || loc1->base_offset == loc2->base_offset));
+}
+
+/* This routine does the actual work. The CFA is now calculated from
+ the dw_cfa_location structure. */
+
+static void
+def_cfa_1 (const char *label, dw_cfa_location *loc_p)
+{
+ dw_cfi_ref cfi;
+ dw_cfa_location old_cfa, loc;
+
+ cfa = *loc_p;
+ loc = *loc_p;
+
+ if (cfa_store.reg == loc.reg && loc.indirect == 0)
+ cfa_store.offset = loc.offset;
+
+ loc.reg = DWARF_FRAME_REGNUM (loc.reg);
+ lookup_cfa (&old_cfa);
+
+ /* If nothing changed, no need to issue any call frame instructions. */
+ if (cfa_equal_p (&loc, &old_cfa))
+ return;
+
+ cfi = new_cfi ();
+
+ if (loc.reg == old_cfa.reg && !loc.indirect)
+ {
+ /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
+ the CFA register did not change but the offset did. */
+ if (loc.offset < 0)
+ {
+ HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
+ gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
+
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = f_offset;
+ }
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
+ }
+ }
+
+#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
+ else if (loc.offset == old_cfa.offset
+ && old_cfa.reg != INVALID_REGNUM
+ && !loc.indirect)
+ {
+ /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
+ indicating the CFA register has changed to <register> but the
+ offset has not changed. */
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ }
+#endif
+
+ else if (loc.indirect == 0)
+ {
+ /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
+ indicating the CFA register has changed to <register> with
+ the specified offset. */
+ if (loc.offset < 0)
+ {
+ HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
+ gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
+
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = f_offset;
+ }
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
+ }
+ }
+ else
+ {
+ /* Construct a DW_CFA_def_cfa_expression instruction to
+ calculate the CFA using a full location expression since no
+ register-offset pair is available. */
+ struct dw_loc_descr_struct *loc_list;
+
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
+ loc_list = build_cfa_loc (&loc, 0);
+ cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
+ }
+
+ add_fde_cfi (label, cfi);
+}
+
+/* Add the CFI for saving a register. REG is the CFA column number.
+ LABEL is passed to add_fde_cfi.
+ If SREG is -1, the register is saved at OFFSET from the CFA;
+ otherwise it is saved in SREG. */
+
+static void
+reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
+{
+ dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+ if (sreg == INVALID_REGNUM)
+ {
+ if (reg & ~0x3f)
+ /* The register number won't fit in 6 bits, so we have to use
+ the long form. */
+ cfi->dw_cfi_opc = DW_CFA_offset_extended;
+ else
+ cfi->dw_cfi_opc = DW_CFA_offset;
+
+#ifdef ENABLE_CHECKING
+ {
+ /* If we get an offset that is not a multiple of
+ DWARF_CIE_DATA_ALIGNMENT, there is either a bug in the
+ definition of DWARF_CIE_DATA_ALIGNMENT, or a bug in the machine
+ description. */
+ HOST_WIDE_INT check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
+
+ gcc_assert (check_offset * DWARF_CIE_DATA_ALIGNMENT == offset);
+ }
+#endif
+ offset /= DWARF_CIE_DATA_ALIGNMENT;
+ if (offset < 0)
+ cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
+
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
+ }
+ else if (sreg == reg)
+ cfi->dw_cfi_opc = DW_CFA_same_value;
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_register;
+ cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
+ }
+
+ add_fde_cfi (label, cfi);
+}
+
+/* Add the CFI for saving a register window. LABEL is passed to reg_save.
+ This CFI tells the unwinder that it needs to restore the window registers
+ from the previous frame's window save area.
+
+ ??? Perhaps we should note in the CIE where windows are saved (instead of
+ assuming 0(cfa)) and what registers are in the window. */
+
+void
+dwarf2out_window_save (const char *label)
+{
+ dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
+ add_fde_cfi (label, cfi);
+}
+
+/* Add a CFI to update the running total of the size of arguments
+ pushed onto the stack. */
+
+void
+dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
+{
+ dw_cfi_ref cfi;
+
+ if (size == old_args_size)
+ return;
+
+ old_args_size = size;
+
+ cfi = new_cfi ();
+ cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+ add_fde_cfi (label, cfi);
+}
+
+/* Entry point for saving a register to the stack. REG is the GCC register
+ number. LABEL and OFFSET are passed to reg_save. */
+
+void
+dwarf2out_reg_save (const char *label, unsigned int reg, HOST_WIDE_INT offset)
+{
+ reg_save (label, DWARF_FRAME_REGNUM (reg), INVALID_REGNUM, offset);
+}
+
+/* Entry point for saving the return address in the stack.
+ LABEL and OFFSET are passed to reg_save. */
+
+void
+dwarf2out_return_save (const char *label, HOST_WIDE_INT offset)
+{
+ reg_save (label, DWARF_FRAME_RETURN_COLUMN, INVALID_REGNUM, offset);
+}
+
+/* Entry point for saving the return address in a register.
+ LABEL and SREG are passed to reg_save. */
+
+void
+dwarf2out_return_reg (const char *label, unsigned int sreg)
+{
+ reg_save (label, DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM (sreg), 0);
+}
+
+/* Record the initial position of the return address. RTL is
+ INCOMING_RETURN_ADDR_RTX. */
+
+static void
+initial_return_save (rtx rtl)
+{
+ unsigned int reg = INVALID_REGNUM;
+ HOST_WIDE_INT offset = 0;
+
+ switch (GET_CODE (rtl))
+ {
+ case REG:
+ /* RA is in a register. */
+ reg = DWARF_FRAME_REGNUM (REGNO (rtl));
+ break;
+
+ case MEM:
+ /* RA is on the stack. */
+ rtl = XEXP (rtl, 0);
+ switch (GET_CODE (rtl))
+ {
+ case REG:
+ gcc_assert (REGNO (rtl) == STACK_POINTER_REGNUM);
+ offset = 0;
+ break;
+
+ case PLUS:
+ gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
+ offset = INTVAL (XEXP (rtl, 1));
+ break;
+
+ case MINUS:
+ gcc_assert (REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM);
+ offset = -INTVAL (XEXP (rtl, 1));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ break;
+
+ case PLUS:
+ /* The return address is at some offset from any value we can
+ actually load. For instance, on the SPARC it is in %i7+8. Just
+ ignore the offset for now; it doesn't matter for unwinding frames. */
+ gcc_assert (GET_CODE (XEXP (rtl, 1)) == CONST_INT);
+ initial_return_save (XEXP (rtl, 0));
+ return;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (reg != DWARF_FRAME_RETURN_COLUMN)
+ reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
+}
+
+/* Given a SET, calculate the amount of stack adjustment it
+ contains. */
+
+static HOST_WIDE_INT
+stack_adjust_offset (rtx pattern)
+{
+ rtx src = SET_SRC (pattern);
+ rtx dest = SET_DEST (pattern);
+ HOST_WIDE_INT offset = 0;
+ enum rtx_code code;
+
+ if (dest == stack_pointer_rtx)
+ {
+ /* (set (reg sp) (plus (reg sp) (const_int))) */
+ code = GET_CODE (src);
+ if (! (code == PLUS || code == MINUS)
+ || XEXP (src, 0) != stack_pointer_rtx
+ || GET_CODE (XEXP (src, 1)) != CONST_INT)
+ return 0;
+
+ offset = INTVAL (XEXP (src, 1));
+ if (code == PLUS)
+ offset = -offset;
+ }
+ else if (MEM_P (dest))
+ {
+ /* (set (mem (pre_dec (reg sp))) (foo)) */
+ src = XEXP (dest, 0);
+ code = GET_CODE (src);
+
+ switch (code)
+ {
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ if (XEXP (src, 0) == stack_pointer_rtx)
+ {
+ rtx val = XEXP (XEXP (src, 1), 1);
+ /* We handle only adjustments by constant amount. */
+ gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS
+ && GET_CODE (val) == CONST_INT);
+ offset = -INTVAL (val);
+ break;
+ }
+ return 0;
+
+ case PRE_DEC:
+ case POST_DEC:
+ if (XEXP (src, 0) == stack_pointer_rtx)
+ {
+ offset = GET_MODE_SIZE (GET_MODE (dest));
+ break;
+ }
+ return 0;
+
+ case PRE_INC:
+ case POST_INC:
+ if (XEXP (src, 0) == stack_pointer_rtx)
+ {
+ offset = -GET_MODE_SIZE (GET_MODE (dest));
+ break;
+ }
+ return 0;
+
+ default:
+ return 0;
+ }
+ }
+ else
+ return 0;
+
+ return offset;
+}
+
+/* Check INSN to see if it looks like a push or a stack adjustment, and
+ make a note of it if it does. EH uses this information to find out how
+ much extra space it needs to pop off the stack. */
+
+static void
+dwarf2out_stack_adjust (rtx insn, bool after_p)
+{
+ HOST_WIDE_INT offset;
+ const char *label;
+ int i;
+
+ /* Don't handle epilogues at all. Certainly it would be wrong to do so
+ with this function. Proper support would require all frame-related
+ insns to be marked, and to be able to handle saving state around
+ epilogues textually in the middle of the function. */
+ if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
+ return;
+
+ /* If only calls can throw, and we have a frame pointer,
+ save up adjustments until we see the CALL_INSN. */
+ if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
+ {
+ if (CALL_P (insn) && !after_p)
+ {
+ /* Extract the size of the args from the CALL rtx itself. */
+ insn = PATTERN (insn);
+ if (GET_CODE (insn) == PARALLEL)
+ insn = XVECEXP (insn, 0, 0);
+ if (GET_CODE (insn) == SET)
+ insn = SET_SRC (insn);
+ gcc_assert (GET_CODE (insn) == CALL);
+ dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
+ }
+ return;
+ }
+
+ if (CALL_P (insn) && !after_p)
+ {
+ if (!flag_asynchronous_unwind_tables)
+ dwarf2out_args_size ("", args_size);
+ return;
+ }
+ else if (BARRIER_P (insn))
+ {
+ /* When we see a BARRIER, we know to reset args_size to 0. Usually
+ the compiler will have already emitted a stack adjustment, but
+ doesn't bother for calls to noreturn functions. */
+#ifdef STACK_GROWS_DOWNWARD
+ offset = -args_size;
+#else
+ offset = args_size;
+#endif
+ }
+ else if (GET_CODE (PATTERN (insn)) == SET)
+ offset = stack_adjust_offset (PATTERN (insn));
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL
+ || GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ /* There may be stack adjustments inside compound insns. Search
+ for them. */
+ for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
+ offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i));
+ }
+ else
+ return;
+
+ if (offset == 0)
+ return;
+
+ if (cfa.reg == STACK_POINTER_REGNUM)
+ cfa.offset += offset;
+
+#ifndef STACK_GROWS_DOWNWARD
+ offset = -offset;
+#endif
+
+ args_size += offset;
+ if (args_size < 0)
+ args_size = 0;
+
+ label = dwarf2out_cfi_label ();
+ def_cfa_1 (label, &cfa);
+ if (flag_asynchronous_unwind_tables)
+ dwarf2out_args_size (label, args_size);
+}
+
+#endif
+
+/* We delay emitting a register save until either (a) we reach the end
+ of the prologue or (b) the register is clobbered. This clusters
+ register saves so that there are fewer pc advances. */
+
+struct queued_reg_save GTY(())
+{
+ struct queued_reg_save *next;
+ rtx reg;
+ HOST_WIDE_INT cfa_offset;
+ rtx saved_reg;
+};
+
+static GTY(()) struct queued_reg_save *queued_reg_saves;
+
+/* The caller's ORIG_REG is saved in SAVED_IN_REG. */
+struct reg_saved_in_data GTY(()) {
+ rtx orig_reg;
+ rtx saved_in_reg;
+};
+
+/* A list of registers saved in other registers.
+ The list intentionally has a small maximum capacity of 4; if your
+ port needs more than that, you might consider implementing a
+ more efficient data structure. */
+static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4];
+static GTY(()) size_t num_regs_saved_in_regs;
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+static const char *last_reg_save_label;
+
+/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
+ SREG, or if SREG is NULL then it is saved at OFFSET to the CFA. */
+
+static void
+queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
+{
+ struct queued_reg_save *q;
+
+ /* Duplicates waste space, but it's also necessary to remove them
+ for correctness, since the queue gets output in reverse
+ order. */
+ for (q = queued_reg_saves; q != NULL; q = q->next)
+ if (REGNO (q->reg) == REGNO (reg))
+ break;
+
+ if (q == NULL)
+ {
+ q = ggc_alloc (sizeof (*q));
+ q->next = queued_reg_saves;
+ queued_reg_saves = q;
+ }
+
+ q->reg = reg;
+ q->cfa_offset = offset;
+ q->saved_reg = sreg;
+
+ last_reg_save_label = label;
+}
+
+/* Output all the entries in QUEUED_REG_SAVES. */
+
+static void
+flush_queued_reg_saves (void)
+{
+ struct queued_reg_save *q;
+
+ for (q = queued_reg_saves; q; q = q->next)
+ {
+ size_t i;
+ unsigned int reg, sreg;
+
+ for (i = 0; i < num_regs_saved_in_regs; i++)
+ if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
+ break;
+ if (q->saved_reg && i == num_regs_saved_in_regs)
+ {
+ gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
+ num_regs_saved_in_regs++;
+ }
+ if (i != num_regs_saved_in_regs)
+ {
+ regs_saved_in_regs[i].orig_reg = q->reg;
+ regs_saved_in_regs[i].saved_in_reg = q->saved_reg;
+ }
+
+ reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
+ if (q->saved_reg)
+ sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
+ else
+ sreg = INVALID_REGNUM;
+ reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
+ }
+
+ queued_reg_saves = NULL;
+ last_reg_save_label = NULL;
+}
+
+/* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved
+ location for? Or, does it clobber a register which we've previously
+ said that some other register is saved in, and for which we now
+ have a new location for? */
+
+static bool
+clobbers_queued_reg_save (rtx insn)
+{
+ struct queued_reg_save *q;
+
+ for (q = queued_reg_saves; q; q = q->next)
+ {
+ size_t i;
+ if (modified_in_p (q->reg, insn))
+ return true;
+ for (i = 0; i < num_regs_saved_in_regs; i++)
+ if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg)
+ && modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn))
+ return true;
+ }
+
+ return false;
+}
+
+/* Entry point for saving the first register into the second. */
+
+void
+dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg)
+{
+ size_t i;
+ unsigned int regno, sregno;
+
+ for (i = 0; i < num_regs_saved_in_regs; i++)
+ if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg))
+ break;
+ if (i == num_regs_saved_in_regs)
+ {
+ gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
+ num_regs_saved_in_regs++;
+ }
+ regs_saved_in_regs[i].orig_reg = reg;
+ regs_saved_in_regs[i].saved_in_reg = sreg;
+
+ regno = DWARF_FRAME_REGNUM (REGNO (reg));
+ sregno = DWARF_FRAME_REGNUM (REGNO (sreg));
+ reg_save (label, regno, sregno, 0);
+}
+
+/* What register, if any, is currently saved in REG? */
+
+static rtx
+reg_saved_in (rtx reg)
+{
+ unsigned int regn = REGNO (reg);
+ size_t i;
+ struct queued_reg_save *q;
+
+ for (q = queued_reg_saves; q; q = q->next)
+ if (q->saved_reg && regn == REGNO (q->saved_reg))
+ return q->reg;
+
+ for (i = 0; i < num_regs_saved_in_regs; i++)
+ if (regs_saved_in_regs[i].saved_in_reg
+ && regn == REGNO (regs_saved_in_regs[i].saved_in_reg))
+ return regs_saved_in_regs[i].orig_reg;
+
+ return NULL_RTX;
+}
+
+
+/* A temporary register holding an integral value used in adjusting SP
+ or setting up the store_reg. The "offset" field holds the integer
+ value, not an offset. */
+static dw_cfa_location cfa_temp;
+
+/* Record call frame debugging information for an expression EXPR,
+ which either sets SP or FP (adjusting how we calculate the frame
+ address) or saves a register to the stack or another register.
+ LABEL indicates the address of EXPR.
+
+ This function encodes a state machine mapping rtxes to actions on
+ cfa, cfa_store, and cfa_temp.reg. We describe these rules so
+ users need not read the source code.
+
+ The High-Level Picture
+
+ Changes in the register we use to calculate the CFA: Currently we
+ assume that if you copy the CFA register into another register, we
+ should take the other one as the new CFA register; this seems to
+ work pretty well. If it's wrong for some target, it's simple
+ enough not to set RTX_FRAME_RELATED_P on the insn in question.
+
+ Changes in the register we use for saving registers to the stack:
+ This is usually SP, but not always. Again, we deduce that if you
+ copy SP into another register (and SP is not the CFA register),
+ then the new register is the one we will be using for register
+ saves. This also seems to work.
+
+ Register saves: There's not much guesswork about this one; if
+ RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a
+ register save, and the register used to calculate the destination
+ had better be the one we think we're using for this purpose.
+ It's also assumed that a copy from a call-saved register to another
+ register is saving that register if RTX_FRAME_RELATED_P is set on
+ that instruction. If the copy is from a call-saved register to
+ the *same* register, that means that the register is now the same
+ value as in the caller.
+
+ Except: If the register being saved is the CFA register, and the
+ offset is nonzero, we are saving the CFA, so we assume we have to
+ use DW_CFA_def_cfa_expression. If the offset is 0, we assume that
+ the intent is to save the value of SP from the previous frame.
+
+ In addition, if a register has previously been saved to a different
+ register,
+
+ Invariants / Summaries of Rules
+
+ cfa current rule for calculating the CFA. It usually
+ consists of a register and an offset.
+ cfa_store register used by prologue code to save things to the stack
+ cfa_store.offset is the offset from the value of
+ 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. 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. 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
+ and cfa_temp.offset.
+
+ Rule 5: Create a new register cfa_store used to save items to the
+ stack.
+
+ Rules 10-14: Save a register to the stack. Define offset as the
+ difference of the original location and cfa_store's
+ location (or cfa_temp's location if cfa_temp is used).
+
+ The Rules
+
+ "{a,b}" indicates a choice of a xor b.
+ "<reg>:cfa.reg" indicates that <reg> must equal cfa.reg.
+
+ Rule 1:
+ (set <reg1> <reg2>:cfa.reg)
+ effects: cfa.reg = <reg1>
+ cfa.offset unchanged
+ cfa_temp.reg = <reg1>
+ cfa_temp.offset = cfa.offset
+
+ Rule 2:
+ (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,losum} <reg>:cfa.reg <const_int>))
+ effects: cfa.reg = fp
+ cfa_offset += +/- <const_int>
+
+ Rule 4:
+ (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))
+ constraints: <reg1> != fp
+ <reg1> != sp
+ effects: cfa_store.reg = <reg1>
+ cfa_store.offset = cfa.offset - cfa_temp.offset
+
+ Rule 6:
+ (set <reg> <const_int>)
+ effects: cfa_temp.reg = <reg>
+ cfa_temp.offset = <const_int>
+
+ Rule 7:
+ (set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
+ effects: cfa_temp.reg = <reg1>
+ cfa_temp.offset |= <const_int>
+
+ Rule 8:
+ (set <reg> (high <exp>))
+ effects: none
+
+ Rule 9:
+ (set <reg> (lo_sum <exp> <const_int>))
+ effects: cfa_temp.reg = <reg>
+ cfa_temp.offset = <const_int>
+
+ Rule 10:
+ (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
+ cfa.reg = sp
+ 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
+ cfa.reg = sp
+ cfa.base_offset = -cfa_store.offset
+
+ Rule 12:
+ (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,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)
+
+ Rule 15:
+ (set <reg> {unspec, unspec_volatile})
+ effects: target-dependent */
+
+static void
+dwarf2out_frame_debug_expr (rtx expr, const char *label)
+{
+ rtx src, dest;
+ HOST_WIDE_INT offset;
+
+ /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
+ the PARALLEL independently. The first element is always processed if
+ it is a SET. This is for backward compatibility. Other elements
+ are processed only if they are SETs and the RTX_FRAME_RELATED_P
+ flag is set in them. */
+ if (GET_CODE (expr) == PARALLEL || GET_CODE (expr) == SEQUENCE)
+ {
+ int par_index;
+ int limit = XVECLEN (expr, 0);
+
+ for (par_index = 0; par_index < limit; par_index++)
+ if (GET_CODE (XVECEXP (expr, 0, par_index)) == SET
+ && (RTX_FRAME_RELATED_P (XVECEXP (expr, 0, par_index))
+ || par_index == 0))
+ dwarf2out_frame_debug_expr (XVECEXP (expr, 0, par_index), label);
+
+ return;
+ }
+
+ gcc_assert (GET_CODE (expr) == SET);
+
+ src = SET_SRC (expr);
+ dest = SET_DEST (expr);
+
+ if (REG_P (src))
+ {
+ rtx rsi = reg_saved_in (src);
+ if (rsi)
+ src = rsi;
+ }
+
+ switch (GET_CODE (dest))
+ {
+ case REG:
+ switch (GET_CODE (src))
+ {
+ /* Setting FP from SP. */
+ case REG:
+ if (cfa.reg == (unsigned) REGNO (src))
+ {
+ /* Rule 1 */
+ /* Update the CFA rule wrt SP or FP. Make sure src is
+ relative to the current CFA register.
+
+ We used to require that dest be either SP or FP, but the
+ ARM copies SP to a temporary register, and from there to
+ 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;
+ }
+ else
+ {
+ /* Saving a register in a register. */
+ gcc_assert (!fixed_regs [REGNO (dest)]
+ /* For the SPARC and its register window. */
+ || (DWARF_FRAME_REGNUM (REGNO (src))
+ == DWARF_FRAME_RETURN_COLUMN));
+ queue_reg_save (label, src, dest, 0);
+ }
+ break;
+
+ case PLUS:
+ case MINUS:
+ case LO_SUM:
+ if (dest == stack_pointer_rtx)
+ {
+ /* Rule 2 */
+ /* Adjusting SP. */
+ switch (GET_CODE (XEXP (src, 1)))
+ {
+ case CONST_INT:
+ offset = INTVAL (XEXP (src, 1));
+ break;
+ case REG:
+ gcc_assert ((unsigned) REGNO (XEXP (src, 1))
+ == cfa_temp.reg);
+ offset = cfa_temp.offset;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (XEXP (src, 0) == hard_frame_pointer_rtx)
+ {
+ /* Restoring SP from FP in the epilogue. */
+ gcc_assert (cfa.reg == (unsigned) HARD_FRAME_POINTER_REGNUM);
+ 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
+ gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
+
+ if (GET_CODE (src) != MINUS)
+ offset = -offset;
+ if (cfa.reg == STACK_POINTER_REGNUM)
+ cfa.offset += offset;
+ if (cfa_store.reg == STACK_POINTER_REGNUM)
+ cfa_store.offset += offset;
+ }
+ else if (dest == hard_frame_pointer_rtx)
+ {
+ /* Rule 3 */
+ /* Either setting the FP from an offset of the SP,
+ or adjusting the FP */
+ gcc_assert (frame_pointer_needed);
+
+ gcc_assert (REG_P (XEXP (src, 0))
+ && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg
+ && GET_CODE (XEXP (src, 1)) == CONST_INT);
+ offset = INTVAL (XEXP (src, 1));
+ if (GET_CODE (src) != MINUS)
+ offset = -offset;
+ cfa.offset += offset;
+ cfa.reg = HARD_FRAME_POINTER_REGNUM;
+ }
+ else
+ {
+ gcc_assert (GET_CODE (src) != MINUS);
+
+ /* Rule 4 */
+ if (REG_P (XEXP (src, 0))
+ && REGNO (XEXP (src, 0)) == cfa.reg
+ && GET_CODE (XEXP (src, 1)) == CONST_INT)
+ {
+ /* Setting a temporary CFA register that will be copied
+ into the FP later on. */
+ 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 if (REG_P (XEXP (src, 0))
+ && 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. */
+ gcc_assert (cfa.reg == STACK_POINTER_REGNUM);
+ 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
+ gcc_unreachable ();
+ }
+ break;
+
+ /* Rule 6 */
+ case CONST_INT:
+ cfa_temp.reg = REGNO (dest);
+ cfa_temp.offset = INTVAL (src);
+ break;
+
+ /* Rule 7 */
+ case IOR:
+ gcc_assert (REG_P (XEXP (src, 0))
+ && (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg
+ && GET_CODE (XEXP (src, 1)) == CONST_INT);
+
+ if ((unsigned) REGNO (dest) != cfa_temp.reg)
+ cfa_temp.reg = REGNO (dest);
+ cfa_temp.offset |= INTVAL (XEXP (src, 1));
+ break;
+
+ /* 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 15 */
+ case UNSPEC:
+ case UNSPEC_VOLATILE:
+ gcc_assert (targetm.dwarf_handle_frame_unspec);
+ targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
+ return;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ def_cfa_1 (label, &cfa);
+ break;
+
+ case MEM:
+ gcc_assert (REG_P (src));
+
+ /* Saving a register to the stack. Make sure dest is relative to the
+ CFA register. */
+ switch (GET_CODE (XEXP (dest, 0)))
+ {
+ /* Rule 10 */
+ /* With a push. */
+ case PRE_MODIFY:
+ /* We can't handle variable size modifications. */
+ gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
+ == CONST_INT);
+ offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
+
+ gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
+ && cfa_store.reg == STACK_POINTER_REGNUM);
+
+ cfa_store.offset += offset;
+ if (cfa.reg == STACK_POINTER_REGNUM)
+ cfa.offset = cfa_store.offset;
+
+ offset = -cfa_store.offset;
+ break;
+
+ /* Rule 11 */
+ case PRE_INC:
+ case PRE_DEC:
+ offset = GET_MODE_SIZE (GET_MODE (dest));
+ if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
+ offset = -offset;
+
+ gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
+ && cfa_store.reg == STACK_POINTER_REGNUM);
+
+ cfa_store.offset += offset;
+ if (cfa.reg == STACK_POINTER_REGNUM)
+ cfa.offset = cfa_store.offset;
+
+ offset = -cfa_store.offset;
+ break;
+
+ /* Rule 12 */
+ /* With an offset. */
+ case PLUS:
+ case MINUS:
+ case LO_SUM:
+ {
+ int regno;
+
+ gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT
+ && REG_P (XEXP (XEXP (dest, 0), 0)));
+ offset = INTVAL (XEXP (XEXP (dest, 0), 1));
+ if (GET_CODE (XEXP (dest, 0)) == MINUS)
+ offset = -offset;
+
+ regno = REGNO (XEXP (XEXP (dest, 0), 0));
+
+ if (cfa_store.reg == (unsigned) regno)
+ offset -= cfa_store.offset;
+ else
+ {
+ gcc_assert (cfa_temp.reg == (unsigned) regno);
+ offset -= cfa_temp.offset;
+ }
+ }
+ break;
+
+ /* Rule 13 */
+ /* Without an offset. */
+ case REG:
+ {
+ int regno = REGNO (XEXP (dest, 0));
+
+ if (cfa_store.reg == (unsigned) regno)
+ offset = -cfa_store.offset;
+ else
+ {
+ gcc_assert (cfa_temp.reg == (unsigned) regno);
+ offset = -cfa_temp.offset;
+ }
+ }
+ break;
+
+ /* Rule 14 */
+ case POST_INC:
+ gcc_assert (cfa_temp.reg
+ == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)));
+ offset = -cfa_temp.offset;
+ cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (REGNO (src) != STACK_POINTER_REGNUM
+ && REGNO (src) != HARD_FRAME_POINTER_REGNUM
+ && (unsigned) REGNO (src) == cfa.reg)
+ {
+ /* We're storing the current CFA reg into the stack. */
+
+ if (cfa.offset == 0)
+ {
+ /* If the source register is exactly the CFA, assume
+ we're saving SP like any other register; this happens
+ on the ARM. */
+ def_cfa_1 (label, &cfa);
+ queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset);
+ break;
+ }
+ else
+ {
+ /* Otherwise, we'll need to look in the stack to
+ calculate the CFA. */
+ rtx x = XEXP (dest, 0);
+
+ if (!REG_P (x))
+ x = XEXP (x, 0);
+ gcc_assert (REG_P (x));
+
+ cfa.reg = REGNO (x);
+ cfa.base_offset = offset;
+ cfa.indirect = 1;
+ def_cfa_1 (label, &cfa);
+ break;
+ }
+ }
+
+ def_cfa_1 (label, &cfa);
+ queue_reg_save (label, src, NULL_RTX, offset);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Record call frame debugging information for INSN, which either
+ sets SP or FP (adjusting how we calculate the frame address) or saves a
+ register to the stack. If INSN is NULL_RTX, initialize our state.
+
+ If AFTER_P is false, we're being called before the insn is emitted,
+ otherwise after. Call instructions get invoked twice. */
+
+void
+dwarf2out_frame_debug (rtx insn, bool after_p)
+{
+ const char *label;
+ rtx src;
+
+ if (insn == NULL_RTX)
+ {
+ size_t i;
+
+ /* Flush any queued register saves. */
+ flush_queued_reg_saves ();
+
+ /* Set up state for generating call frame debug info. */
+ lookup_cfa (&cfa);
+ gcc_assert (cfa.reg
+ == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
+
+ cfa.reg = STACK_POINTER_REGNUM;
+ cfa_store = cfa;
+ cfa_temp.reg = -1;
+ cfa_temp.offset = 0;
+
+ for (i = 0; i < num_regs_saved_in_regs; i++)
+ {
+ regs_saved_in_regs[i].orig_reg = NULL_RTX;
+ regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
+ }
+ num_regs_saved_in_regs = 0;
+ return;
+ }
+
+ if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
+ flush_queued_reg_saves ();
+
+ if (! RTX_FRAME_RELATED_P (insn))
+ {
+ if (!ACCUMULATE_OUTGOING_ARGS)
+ dwarf2out_stack_adjust (insn, after_p);
+ return;
+ }
+
+ label = dwarf2out_cfi_label ();
+ src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
+ if (src)
+ insn = XEXP (src, 0);
+ else
+ insn = PATTERN (insn);
+
+ dwarf2out_frame_debug_expr (insn, label);
+}
+
+#endif
+
+/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */
+static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc
+ (enum dwarf_call_frame_info cfi);
+
+static enum dw_cfi_oprnd_type
+dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
+{
+ switch (cfi)
+ {
+ case DW_CFA_nop:
+ case DW_CFA_GNU_window_save:
+ return dw_cfi_oprnd_unused;
+
+ case DW_CFA_set_loc:
+ case DW_CFA_advance_loc1:
+ case DW_CFA_advance_loc2:
+ case DW_CFA_advance_loc4:
+ case DW_CFA_MIPS_advance_loc8:
+ return dw_cfi_oprnd_addr;
+
+ case DW_CFA_offset:
+ case DW_CFA_offset_extended:
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_register:
+ return dw_cfi_oprnd_reg_num;
+
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_GNU_args_size:
+ case DW_CFA_def_cfa_offset_sf:
+ return dw_cfi_oprnd_offset;
+
+ case DW_CFA_def_cfa_expression:
+ case DW_CFA_expression:
+ return dw_cfi_oprnd_loc;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */
+static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc
+ (enum dwarf_call_frame_info cfi);
+
+static enum dw_cfi_oprnd_type
+dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
+{
+ switch (cfi)
+ {
+ case DW_CFA_def_cfa:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_offset:
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_offset_extended:
+ return dw_cfi_oprnd_offset;
+
+ case DW_CFA_register:
+ return dw_cfi_oprnd_reg_num;
+
+ default:
+ return dw_cfi_oprnd_unused;
+ }
+}
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+/* Switch to eh_frame_section. If we don't have an eh_frame_section,
+ switch to the data section instead, and write out a synthetic label
+ for collect2. */
+
+static void
+switch_to_eh_frame_section (void)
+{
+ tree label;
+
+#ifdef EH_FRAME_SECTION_NAME
+ if (eh_frame_section == 0)
+ {
+ int flags;
+
+ if (EH_TABLES_CAN_BE_READ_ONLY)
+ {
+ int fde_encoding;
+ int per_encoding;
+ int lsda_encoding;
+
+ fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*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);
+ flags = ((! flag_pic
+ || ((fde_encoding & 0x70) != DW_EH_PE_absptr
+ && (fde_encoding & 0x70) != DW_EH_PE_aligned
+ && (per_encoding & 0x70) != DW_EH_PE_absptr
+ && (per_encoding & 0x70) != DW_EH_PE_aligned
+ && (lsda_encoding & 0x70) != DW_EH_PE_absptr
+ && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
+ ? 0 : SECTION_WRITE);
+ }
+ else
+ flags = SECTION_WRITE;
+ eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
+ }
+#endif
+
+ if (eh_frame_section)
+ switch_to_section (eh_frame_section);
+ else
+ {
+ /* We have no special eh_frame section. Put the information in
+ the data section and emit special labels to guide collect2. */
+ switch_to_section (data_section);
+/* APPLE LOCAL begin mainline 2006-11-01 5125268 */ \
+ label = get_file_function_name ("F");
+/* APPLE LOCAL end mainline 2006-11-01 5125268 */ \
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ targetm.asm_out.globalize_label (asm_out_file,
+ IDENTIFIER_POINTER (label));
+ ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+ }
+}
+
+/* Output a Call Frame Information opcode and its operand(s). */
+
+static void
+output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
+{
+ unsigned long r;
+ if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
+ dw2_asm_output_data (1, (cfi->dw_cfi_opc
+ | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
+ "DW_CFA_advance_loc " HOST_WIDE_INT_PRINT_HEX,
+ cfi->dw_cfi_oprnd1.dw_cfi_offset);
+ else if (cfi->dw_cfi_opc == DW_CFA_offset)
+ {
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
+ "DW_CFA_offset, column 0x%lx", r);
+ dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
+ }
+ else if (cfi->dw_cfi_opc == DW_CFA_restore)
+ {
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
+ "DW_CFA_restore, column 0x%lx", r);
+ }
+ else
+ {
+ dw2_asm_output_data (1, cfi->dw_cfi_opc,
+ "%s", dwarf_cfi_name (cfi->dw_cfi_opc));
+
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_set_loc:
+ if (for_eh)
+ dw2_asm_output_encoded_addr_rtx (
+ ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
+ gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
+ false, NULL);
+ else
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_advance_loc1:
+ dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label, NULL);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_advance_loc2:
+ dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label, NULL);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_advance_loc4:
+ dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label, NULL);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_MIPS_advance_loc8:
+ dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label, NULL);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_offset_extended:
+ case DW_CFA_def_cfa:
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data_uleb128 (r, NULL);
+ dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
+ break;
+
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data_uleb128 (r, NULL);
+ dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
+ break;
+
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data_uleb128 (r, NULL);
+ break;
+
+ case DW_CFA_register:
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data_uleb128 (r, NULL);
+ r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, for_eh);
+ dw2_asm_output_data_uleb128 (r, NULL);
+ break;
+
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_GNU_args_size:
+ dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
+ break;
+
+ case DW_CFA_def_cfa_offset_sf:
+ dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
+ break;
+
+ case DW_CFA_GNU_window_save:
+ break;
+
+ case DW_CFA_def_cfa_expression:
+ case DW_CFA_expression:
+ output_cfa_loc (cfi);
+ break;
+
+ case DW_CFA_GNU_negative_offset_extended:
+ /* Obsoleted by DW_CFA_offset_extended_sf. */
+ gcc_unreachable ();
+
+ default:
+ break;
+ }
+ }
+}
+
+/* Output the call frame information used to record information
+ that relates to calculating the frame pointer, and records the
+ location of saved registers. */
+
+static void
+output_call_frame_info (int for_eh)
+{
+ unsigned int i;
+ dw_fde_ref fde;
+ dw_cfi_ref cfi;
+ char l1[20], l2[20], section_start_label[20];
+ bool any_lsda_needed = false;
+ char augmentation[6];
+ int augmentation_size;
+ int fde_encoding = DW_EH_PE_absptr;
+ int per_encoding = DW_EH_PE_absptr;
+ int lsda_encoding = DW_EH_PE_absptr;
+ int return_reg;
+
+ /* Don't emit a CIE if there won't be any FDEs. */
+ if (fde_table_in_use == 0)
+ return;
+
+ /* If we make FDEs linkonce, we may have to emit an empty label for
+ an FDE that wouldn't otherwise be emitted. We want to avoid
+ having an FDE kept around when the function it refers to is
+ discarded. Example where this matters: a primary function
+ template in C++ requires EH information, but an explicit
+ specialization doesn't. */
+ if (TARGET_USES_WEAK_UNWIND_INFO
+ && ! flag_asynchronous_unwind_tables
+/* APPLE LOCAL begin for-fsf-4_4 5480287 */ \
+ && flag_exceptions
+/* APPLE LOCAL end for-fsf-4_4 5480287 */ \
+ && for_eh)
+ for (i = 0; i < fde_table_in_use; i++)
+ if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
+ && !fde_table[i].uses_eh_lsda
+ && ! DECL_WEAK (fde_table[i].decl))
+ targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
+ for_eh, /* empty */ 1);
+
+ /* If we don't have any functions we'll want to unwind out of, don't
+ emit any EH unwind information. Note that if exceptions aren't
+ enabled, we won't have collected nothrow information, and if we
+ asked for asynchronous tables, we always want this info. */
+ if (for_eh)
+ {
+ bool any_eh_needed = !flag_exceptions || flag_asynchronous_unwind_tables;
+
+ for (i = 0; i < fde_table_in_use; i++)
+ if (fde_table[i].uses_eh_lsda)
+ any_eh_needed = any_lsda_needed = true;
+ else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
+ any_eh_needed = true;
+ else if (! fde_table[i].nothrow
+ && ! fde_table[i].all_throwers_are_sibcalls)
+ any_eh_needed = true;
+
+ if (! any_eh_needed)
+ return;
+ }
+
+ /* We're going to be generating comments, so turn on app. */
+ if (flag_debug_asm)
+ app_enable ();
+
+ if (for_eh)
+ switch_to_eh_frame_section ();
+ else
+ {
+ if (!debug_frame_section)
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ switch_to_section (debug_frame_section);
+ }
+
+ ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
+ ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
+
+ /* Output the CIE. */
+ ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
+ ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+ "Length of Common Information Entry");
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+ /* Now that the CIE pointer is PC-relative for EH,
+ use 0 to identify the CIE. */
+ dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
+ (for_eh ? 0 : DWARF_CIE_ID),
+ "CIE Identifier Tag");
+
+ dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
+
+ augmentation[0] = 0;
+ augmentation_size = 0;
+ if (for_eh)
+ {
+ char *p;
+
+ /* 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. */
+ gcc_assert (size_of_uleb128 (augmentation_size) == 1);
+ }
+ }
+
+ dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
+ dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
+ dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
+ "CIE Data Alignment Factor");
+
+ return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
+ if (DW_CIE_VERSION == 1)
+ dw2_asm_output_data (1, return_reg, "CIE RA Column");
+ else
+ dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column");
+
+ if (augmentation[0])
+ {
+ dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
+ if (eh_personality_libfunc)
+ {
+ dw2_asm_output_data (1, per_encoding, "Personality (%s)",
+ eh_data_format_name (per_encoding));
+ dw2_asm_output_encoded_addr_rtx (per_encoding,
+ eh_personality_libfunc,
+ true, NULL);
+ }
+
+ if (any_lsda_needed)
+ dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
+ eh_data_format_name (lsda_encoding));
+
+ if (fde_encoding != DW_EH_PE_absptr)
+ dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
+ eh_data_format_name (fde_encoding));
+ }
+
+ for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
+ output_cfi (cfi, NULL, for_eh);
+
+ /* Pad the CIE out to an address sized boundary. */
+ ASM_OUTPUT_ALIGN (asm_out_file,
+ floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE));
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+
+ /* 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 that don't need it. */
+ if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
+ && (fde->nothrow || fde->all_throwers_are_sibcalls)
+ && ! (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
+ && !fde->uses_eh_lsda)
+ continue;
+
+ targetm.asm_out.unwind_label (asm_out_file, fde->decl, for_eh, /* empty */ 0);
+ targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, for_eh + i * 2);
+ ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
+ ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+ "FDE Length");
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+ if (for_eh)
+ dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
+ else
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
+ debug_frame_section, "FDE CIE offset");
+
+ if (for_eh)
+ {
+ rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin);
+ SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
+ dw2_asm_output_encoded_addr_rtx (fde_encoding,
+ sym_ref,
+ false,
+ "FDE initial location");
+ if (fde->dw_fde_switched_sections)
+ {
+ rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
+ fde->dw_fde_unlikely_section_label);
+ rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
+ fde->dw_fde_hot_section_label);
+ SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
+ SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3, false,
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_hot_section_end_label,
+ fde->dw_fde_hot_section_label,
+ "FDE address range");
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2, false,
+ "FDE initial location");
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_unlikely_section_end_label,
+ fde->dw_fde_unlikely_section_label,
+ "FDE address range");
+ }
+ else
+ dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
+ }
+ else
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
+ "FDE initial location");
+ if (fde->dw_fde_switched_sections)
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ fde->dw_fde_hot_section_label,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_hot_section_end_label,
+ fde->dw_fde_hot_section_label,
+ "FDE address range");
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+ fde->dw_fde_unlikely_section_label,
+ "FDE initial location");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_unlikely_section_end_label,
+ fde->dw_fde_unlikely_section_label,
+ "FDE address range");
+ }
+ else
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ fde->dw_fde_end, fde->dw_fde_begin,
+ "FDE address range");
+ }
+
+ if (augmentation[0])
+ {
+ if (any_lsda_needed)
+ {
+ int size = size_of_encoded_value (lsda_encoding);
+
+ if (lsda_encoding == DW_EH_PE_aligned)
+ {
+ int offset = ( 4 /* Length */
+ + 4 /* CIE offset */
+ + 2 * size_of_encoded_value (fde_encoding)
+ + 1 /* Augmentation size */ );
+ int pad = -offset & (PTR_SIZE - 1);
+
+ size += pad;
+ gcc_assert (size_of_uleb128 (size) == 1);
+ }
+
+ dw2_asm_output_data_uleb128 (size, "Augmentation size");
+
+ if (fde->uses_eh_lsda)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
+ fde->funcdef_number);
+ dw2_asm_output_encoded_addr_rtx (
+ lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
+ false, "Language Specific Data Area");
+ }
+ else
+ {
+ if (lsda_encoding == DW_EH_PE_aligned)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ dw2_asm_output_data
+ (size_of_encoded_value (lsda_encoding), 0,
+ "Language Specific Data Area (none)");
+ }
+ }
+ else
+ dw2_asm_output_data_uleb128 (0, "Augmentation size");
+ }
+
+ /* 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, for_eh);
+
+ /* Pad the FDE out to an address sized boundary. */
+ ASM_OUTPUT_ALIGN (asm_out_file,
+ floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+ }
+
+ if (for_eh && targetm.terminate_dw2_eh_frame_info)
+ dw2_asm_output_data (4, 0, "End of Table");
+#ifdef MIPS_DEBUGGING_INFO
+ /* Work around Irix 6 assembler bug whereby labels at the end of a section
+ get a value of 0. Putting .align 0 after the label fixes it. */
+ ASM_OUTPUT_ALIGN (asm_out_file, 0);
+#endif
+
+ /* Turn off app to make assembly quicker. */
+ if (flag_debug_asm)
+ app_disable ();
+}
+
+/* Output a marker (i.e. a label) for the beginning of a function, before
+ the prologue. */
+
+void
+dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file ATTRIBUTE_UNUSED)
+{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char * dup_label;
+ dw_fde_ref fde;
+
+ current_function_func_begin_label = NULL;
+
+#ifdef TARGET_UNWIND_INFO
+ /* ??? 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
+
+ switch_to_section (function_section (current_function_decl));
+ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
+ current_function_funcdef_no);
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
+ current_function_funcdef_no);
+ dup_label = xstrdup (label);
+ current_function_func_begin_label = dup_label;
+
+#ifdef TARGET_UNWIND_INFO
+ /* 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_table_allocated += FDE_TABLE_INCREMENT;
+ fde_table = ggc_realloc (fde_table,
+ fde_table_allocated * sizeof (dw_fde_node));
+ memset (fde_table + fde_table_in_use, 0,
+ FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
+ }
+
+ /* Record the FDE associated with this function. */
+ current_funcdef_fde = fde_table_in_use;
+
+ /* Add the new FDE at the end of the fde_table. */
+ fde = &fde_table[fde_table_in_use++];
+ fde->decl = current_function_decl;
+ fde->dw_fde_begin = dup_label;
+ fde->dw_fde_current_label = dup_label;
+ fde->dw_fde_hot_section_label = NULL;
+ fde->dw_fde_hot_section_end_label = NULL;
+ fde->dw_fde_unlikely_section_label = NULL;
+ fde->dw_fde_unlikely_section_end_label = NULL;
+ fde->dw_fde_switched_sections = false;
+ fde->dw_fde_end = NULL;
+ fde->dw_fde_cfi = NULL;
+ fde->funcdef_number = current_function_funcdef_no;
+ fde->nothrow = TREE_NOTHROW (current_function_decl);
+ fde->uses_eh_lsda = cfun->uses_eh_lsda;
+ fde->all_throwers_are_sibcalls = cfun->all_throwers_are_sibcalls;
+
+ args_size = old_args_size = 0;
+
+ /* 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
+ for a function definition. This gets called *after* the epilogue code has
+ been generated. */
+
+void
+dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file ATTRIBUTE_UNUSED)
+{
+ dw_fde_ref fde;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ /* Output a label to mark the endpoint of the code generated for this
+ function. */
+ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+ fde = &fde_table[fde_table_in_use - 1];
+ fde->dw_fde_end = xstrdup (label);
+}
+
+void
+dwarf2out_frame_init (void)
+{
+ /* Allocate the initial hunk of the fde_table. */
+ fde_table = ggc_alloc_cleared (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
+ fde_table_allocated = FDE_TABLE_INCREMENT;
+ fde_table_in_use = 0;
+
+ /* Generate the CFA instructions common to all FDE's. Do it now for the
+ sake of lookup_cfa. */
+
+ /* On entry, the Canonical Frame Address is at SP. */
+ dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
+
+#ifdef DWARF2_UNWIND_INFO
+ if (DWARF2_UNWIND_INFO)
+ initial_return_save (INCOMING_RETURN_ADDR_RTX);
+#endif
+}
+
+void
+dwarf2out_frame_finish (void)
+{
+ /* Output call frame information. */
+ if (DWARF2_FRAME_INFO)
+ output_call_frame_info (0);
+
+#ifndef TARGET_UNWIND_INFO
+ /* Output another copy for the unwinder. */
+ if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
+ output_call_frame_info (1);
+#endif
+}
+#endif
+
+/* And now, the subset of the debugging information support code necessary
+ for emitting location expressions. */
+
+/* Data about a single source file. */
+struct dwarf_file_data GTY(())
+{
+ const char * filename;
+ int emitted_number;
+};
+
+/* We need some way to distinguish DW_OP_addr with a direct symbol
+ relocation from DW_OP_addr with a dtp-relative symbol relocation. */
+#define INTERNAL_DW_OP_tls_addr (0x100 + DW_OP_addr)
+
+
+typedef struct dw_val_struct *dw_val_ref;
+typedef struct die_struct *dw_die_ref;
+typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
+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
+ implementation are listed below. */
+
+enum dw_val_class
+{
+ dw_val_class_addr,
+ dw_val_class_offset,
+ dw_val_class_loc,
+ dw_val_class_loc_list,
+ dw_val_class_range_list,
+ dw_val_class_const,
+ dw_val_class_unsigned_const,
+ dw_val_class_long_long,
+ dw_val_class_vec,
+ dw_val_class_flag,
+ dw_val_class_die_ref,
+ dw_val_class_fde_ref,
+ dw_val_class_lbl_id,
+ dw_val_class_lineptr,
+ dw_val_class_str,
+ dw_val_class_macptr,
+ dw_val_class_file
+};
+
+/* Describe a double word constant value. */
+/* ??? Every instance of long_long in the code really means CONST_DOUBLE. */
+
+typedef struct dw_long_long_struct GTY(())
+{
+ unsigned long hi;
+ unsigned long low;
+}
+dw_long_long_const;
+
+/* Describe a floating point constant value, or a vector constant value. */
+
+typedef struct dw_vec_struct GTY(())
+{
+ unsigned char * GTY((length ("%h.length"))) array;
+ unsigned length;
+ unsigned elt_size;
+}
+dw_vec_const;
+
+/* The dw_val_node describes an attribute's value, as it is
+ represented internally. */
+
+typedef struct dw_val_struct GTY(())
+{
+ enum dw_val_class val_class;
+ union dw_val_struct_union
+ {
+ rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
+ unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
+ dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
+ dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
+ HOST_WIDE_INT GTY ((default)) val_int;
+ unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
+ dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
+ dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
+ struct dw_val_die_union
+ {
+ dw_die_ref die;
+ int external;
+ } GTY ((tag ("dw_val_class_die_ref"))) val_die_ref;
+ unsigned GTY ((tag ("dw_val_class_fde_ref"))) val_fde_index;
+ struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str;
+ char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
+ unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
+ struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
+ }
+ GTY ((desc ("%1.val_class"))) v;
+}
+dw_val_node;
+
+/* Locations in memory are described using a sequence of stack machine
+ operations. */
+
+typedef struct dw_loc_descr_struct GTY(())
+{
+ dw_loc_descr_ref dw_loc_next;
+ enum dwarf_location_atom dw_loc_opc;
+ dw_val_node dw_loc_oprnd1;
+ dw_val_node dw_loc_oprnd2;
+ int dw_loc_addr;
+}
+dw_loc_descr_node;
+
+/* 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 GTY(())
+{
+ 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;
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+static const char *dwarf_stack_op_name (unsigned);
+static dw_loc_descr_ref new_loc_descr (enum dwarf_location_atom,
+ unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
+static void add_loc_descr (dw_loc_descr_ref *, dw_loc_descr_ref);
+static unsigned long size_of_loc_descr (dw_loc_descr_ref);
+static unsigned long size_of_locs (dw_loc_descr_ref);
+static void output_loc_operands (dw_loc_descr_ref);
+static void output_loc_sequence (dw_loc_descr_ref);
+
+/* Convert a DWARF stack opcode into its string name. */
+
+static const char *
+dwarf_stack_op_name (unsigned int op)
+{
+ switch (op)
+ {
+ case DW_OP_addr:
+ case INTERNAL_DW_OP_tls_addr:
+ return "DW_OP_addr";
+ case DW_OP_deref:
+ return "DW_OP_deref";
+ case DW_OP_const1u:
+ return "DW_OP_const1u";
+ case DW_OP_const1s:
+ return "DW_OP_const1s";
+ case DW_OP_const2u:
+ return "DW_OP_const2u";
+ case DW_OP_const2s:
+ return "DW_OP_const2s";
+ case DW_OP_const4u:
+ return "DW_OP_const4u";
+ case DW_OP_const4s:
+ return "DW_OP_const4s";
+ case DW_OP_const8u:
+ return "DW_OP_const8u";
+ case DW_OP_const8s:
+ return "DW_OP_const8s";
+ case DW_OP_constu:
+ return "DW_OP_constu";
+ case DW_OP_consts:
+ return "DW_OP_consts";
+ case DW_OP_dup:
+ return "DW_OP_dup";
+ case DW_OP_drop:
+ return "DW_OP_drop";
+ case DW_OP_over:
+ return "DW_OP_over";
+ case DW_OP_pick:
+ return "DW_OP_pick";
+ case DW_OP_swap:
+ return "DW_OP_swap";
+ case DW_OP_rot:
+ return "DW_OP_rot";
+ case DW_OP_xderef:
+ return "DW_OP_xderef";
+ case DW_OP_abs:
+ return "DW_OP_abs";
+ case DW_OP_and:
+ return "DW_OP_and";
+ case DW_OP_div:
+ return "DW_OP_div";
+ case DW_OP_minus:
+ return "DW_OP_minus";
+ case DW_OP_mod:
+ return "DW_OP_mod";
+ case DW_OP_mul:
+ return "DW_OP_mul";
+ case DW_OP_neg:
+ return "DW_OP_neg";
+ case DW_OP_not:
+ return "DW_OP_not";
+ case DW_OP_or:
+ return "DW_OP_or";
+ case DW_OP_plus:
+ return "DW_OP_plus";
+ case DW_OP_plus_uconst:
+ return "DW_OP_plus_uconst";
+ case DW_OP_shl:
+ return "DW_OP_shl";
+ case DW_OP_shr:
+ return "DW_OP_shr";
+ case DW_OP_shra:
+ return "DW_OP_shra";
+ case DW_OP_xor:
+ return "DW_OP_xor";
+ case DW_OP_bra:
+ return "DW_OP_bra";
+ case DW_OP_eq:
+ return "DW_OP_eq";
+ case DW_OP_ge:
+ return "DW_OP_ge";
+ case DW_OP_gt:
+ return "DW_OP_gt";
+ case DW_OP_le:
+ return "DW_OP_le";
+ case DW_OP_lt:
+ return "DW_OP_lt";
+ case DW_OP_ne:
+ return "DW_OP_ne";
+ case DW_OP_skip:
+ return "DW_OP_skip";
+ case DW_OP_lit0:
+ return "DW_OP_lit0";
+ case DW_OP_lit1:
+ return "DW_OP_lit1";
+ case DW_OP_lit2:
+ return "DW_OP_lit2";
+ case DW_OP_lit3:
+ return "DW_OP_lit3";
+ case DW_OP_lit4:
+ return "DW_OP_lit4";
+ case DW_OP_lit5:
+ return "DW_OP_lit5";
+ case DW_OP_lit6:
+ return "DW_OP_lit6";
+ case DW_OP_lit7:
+ return "DW_OP_lit7";
+ case DW_OP_lit8:
+ return "DW_OP_lit8";
+ case DW_OP_lit9:
+ return "DW_OP_lit9";
+ case DW_OP_lit10:
+ return "DW_OP_lit10";
+ case DW_OP_lit11:
+ return "DW_OP_lit11";
+ case DW_OP_lit12:
+ return "DW_OP_lit12";
+ case DW_OP_lit13:
+ return "DW_OP_lit13";
+ case DW_OP_lit14:
+ return "DW_OP_lit14";
+ case DW_OP_lit15:
+ return "DW_OP_lit15";
+ case DW_OP_lit16:
+ return "DW_OP_lit16";
+ case DW_OP_lit17:
+ return "DW_OP_lit17";
+ case DW_OP_lit18:
+ return "DW_OP_lit18";
+ case DW_OP_lit19:
+ return "DW_OP_lit19";
+ case DW_OP_lit20:
+ return "DW_OP_lit20";
+ case DW_OP_lit21:
+ return "DW_OP_lit21";
+ case DW_OP_lit22:
+ return "DW_OP_lit22";
+ case DW_OP_lit23:
+ return "DW_OP_lit23";
+ case DW_OP_lit24:
+ return "DW_OP_lit24";
+ case DW_OP_lit25:
+ return "DW_OP_lit25";
+ case DW_OP_lit26:
+ return "DW_OP_lit26";
+ case DW_OP_lit27:
+ return "DW_OP_lit27";
+ case DW_OP_lit28:
+ return "DW_OP_lit28";
+ case DW_OP_lit29:
+ return "DW_OP_lit29";
+ case DW_OP_lit30:
+ return "DW_OP_lit30";
+ case DW_OP_lit31:
+ return "DW_OP_lit31";
+ case DW_OP_reg0:
+ return "DW_OP_reg0";
+ case DW_OP_reg1:
+ return "DW_OP_reg1";
+ case DW_OP_reg2:
+ return "DW_OP_reg2";
+ case DW_OP_reg3:
+ return "DW_OP_reg3";
+ case DW_OP_reg4:
+ return "DW_OP_reg4";
+ case DW_OP_reg5:
+ return "DW_OP_reg5";
+ case DW_OP_reg6:
+ return "DW_OP_reg6";
+ case DW_OP_reg7:
+ return "DW_OP_reg7";
+ case DW_OP_reg8:
+ return "DW_OP_reg8";
+ case DW_OP_reg9:
+ return "DW_OP_reg9";
+ case DW_OP_reg10:
+ return "DW_OP_reg10";
+ case DW_OP_reg11:
+ return "DW_OP_reg11";
+ case DW_OP_reg12:
+ return "DW_OP_reg12";
+ case DW_OP_reg13:
+ return "DW_OP_reg13";
+ case DW_OP_reg14:
+ return "DW_OP_reg14";
+ case DW_OP_reg15:
+ return "DW_OP_reg15";
+ case DW_OP_reg16:
+ return "DW_OP_reg16";
+ case DW_OP_reg17:
+ return "DW_OP_reg17";
+ case DW_OP_reg18:
+ return "DW_OP_reg18";
+ case DW_OP_reg19:
+ return "DW_OP_reg19";
+ case DW_OP_reg20:
+ return "DW_OP_reg20";
+ case DW_OP_reg21:
+ return "DW_OP_reg21";
+ case DW_OP_reg22:
+ return "DW_OP_reg22";
+ case DW_OP_reg23:
+ return "DW_OP_reg23";
+ case DW_OP_reg24:
+ return "DW_OP_reg24";
+ case DW_OP_reg25:
+ return "DW_OP_reg25";
+ case DW_OP_reg26:
+ return "DW_OP_reg26";
+ case DW_OP_reg27:
+ return "DW_OP_reg27";
+ case DW_OP_reg28:
+ return "DW_OP_reg28";
+ case DW_OP_reg29:
+ return "DW_OP_reg29";
+ case DW_OP_reg30:
+ return "DW_OP_reg30";
+ case DW_OP_reg31:
+ return "DW_OP_reg31";
+ case DW_OP_breg0:
+ return "DW_OP_breg0";
+ case DW_OP_breg1:
+ return "DW_OP_breg1";
+ case DW_OP_breg2:
+ return "DW_OP_breg2";
+ case DW_OP_breg3:
+ return "DW_OP_breg3";
+ case DW_OP_breg4:
+ return "DW_OP_breg4";
+ case DW_OP_breg5:
+ return "DW_OP_breg5";
+ case DW_OP_breg6:
+ return "DW_OP_breg6";
+ case DW_OP_breg7:
+ return "DW_OP_breg7";
+ case DW_OP_breg8:
+ return "DW_OP_breg8";
+ case DW_OP_breg9:
+ return "DW_OP_breg9";
+ case DW_OP_breg10:
+ return "DW_OP_breg10";
+ case DW_OP_breg11:
+ return "DW_OP_breg11";
+ case DW_OP_breg12:
+ return "DW_OP_breg12";
+ case DW_OP_breg13:
+ return "DW_OP_breg13";
+ case DW_OP_breg14:
+ return "DW_OP_breg14";
+ case DW_OP_breg15:
+ return "DW_OP_breg15";
+ case DW_OP_breg16:
+ return "DW_OP_breg16";
+ case DW_OP_breg17:
+ return "DW_OP_breg17";
+ case DW_OP_breg18:
+ return "DW_OP_breg18";
+ case DW_OP_breg19:
+ return "DW_OP_breg19";
+ case DW_OP_breg20:
+ return "DW_OP_breg20";
+ case DW_OP_breg21:
+ return "DW_OP_breg21";
+ case DW_OP_breg22:
+ return "DW_OP_breg22";
+ case DW_OP_breg23:
+ return "DW_OP_breg23";
+ case DW_OP_breg24:
+ return "DW_OP_breg24";
+ case DW_OP_breg25:
+ return "DW_OP_breg25";
+ case DW_OP_breg26:
+ return "DW_OP_breg26";
+ case DW_OP_breg27:
+ return "DW_OP_breg27";
+ case DW_OP_breg28:
+ return "DW_OP_breg28";
+ case DW_OP_breg29:
+ return "DW_OP_breg29";
+ case DW_OP_breg30:
+ return "DW_OP_breg30";
+ case DW_OP_breg31:
+ return "DW_OP_breg31";
+ case DW_OP_regx:
+ return "DW_OP_regx";
+ case DW_OP_fbreg:
+ return "DW_OP_fbreg";
+ case DW_OP_bregx:
+ return "DW_OP_bregx";
+ case DW_OP_piece:
+ return "DW_OP_piece";
+ /* APPLE LOCAL begin 6186914 */
+ case DW_OP_bit_piece:
+ return "DW_OP_bit_piece";
+ /* APPLE LOCAL end 6186914 */
+ case DW_OP_deref_size:
+ return "DW_OP_deref_size";
+ case DW_OP_xderef_size:
+ return "DW_OP_xderef_size";
+ case DW_OP_nop:
+ return "DW_OP_nop";
+ case DW_OP_push_object_address:
+ return "DW_OP_push_object_address";
+ case DW_OP_call2:
+ return "DW_OP_call2";
+ case DW_OP_call4:
+ return "DW_OP_call4";
+ case DW_OP_call_ref:
+ return "DW_OP_call_ref";
+ case DW_OP_GNU_push_tls_address:
+ return "DW_OP_GNU_push_tls_address";
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ case DW_OP_APPLE_uninit:
+ return "DW_OP_APPLE_uninit";
+ /* APPLE LOCAL end track initialization status 4964532 */
+ default:
+ return "OP_<unknown>";
+ }
+}
+
+/* Return a pointer to a newly allocated location description. Location
+ descriptions are simple expression terms that can be strung
+ together to form more complicated location (address) descriptions. */
+
+static inline dw_loc_descr_ref
+new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1,
+ unsigned HOST_WIDE_INT oprnd2)
+{
+ dw_loc_descr_ref descr = ggc_alloc_cleared (sizeof (dw_loc_descr_node));
+
+ descr->dw_loc_opc = op;
+ descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
+ descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
+ descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
+ descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
+
+ return descr;
+}
+
+/* Add a location description term to a location description expression. */
+
+static inline void
+add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
+{
+ dw_loc_descr_ref *d;
+
+ /* Find the end of the chain. */
+ for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
+ ;
+
+ *d = descr;
+}
+
+/* Return the size of a location descriptor. */
+
+static unsigned long
+size_of_loc_descr (dw_loc_descr_ref loc)
+{
+ unsigned long size = 1;
+
+ switch (loc->dw_loc_opc)
+ {
+ case DW_OP_addr:
+ case INTERNAL_DW_OP_tls_addr:
+ size += DWARF2_ADDR_SIZE;
+ break;
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ size += 1;
+ break;
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ size += 2;
+ break;
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ size += 4;
+ break;
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ size += 8;
+ break;
+ case DW_OP_constu:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_consts:
+ size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
+ break;
+ case DW_OP_pick:
+ size += 1;
+ break;
+ case DW_OP_plus_uconst:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ size += 2;
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
+ break;
+ case DW_OP_regx:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_fbreg:
+ size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
+ break;
+ case DW_OP_bregx:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
+ break;
+ case DW_OP_piece:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ /* APPLE LOCAL begin 6186914 */
+ case DW_OP_bit_piece:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ size += size_of_uleb128 (loc->dw_loc_oprnd2.v.val_unsigned);
+ break;
+ /* APPLE LOCAL end 6186914 */
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ size += 1;
+ break;
+ case DW_OP_call2:
+ size += 2;
+ break;
+ case DW_OP_call4:
+ size += 4;
+ break;
+ case DW_OP_call_ref:
+ size += DWARF2_ADDR_SIZE;
+ break;
+ default:
+ break;
+ }
+
+ return size;
+}
+
+/* Return the size of a series of location descriptors. */
+
+static unsigned long
+size_of_locs (dw_loc_descr_ref loc)
+{
+ dw_loc_descr_ref l;
+ unsigned long size;
+
+ /* If there are no skip or bra opcodes, don't fill in the dw_loc_addr
+ field, to avoid writing to a PCH file. */
+ for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
+ {
+ if (l->dw_loc_opc == DW_OP_skip || l->dw_loc_opc == DW_OP_bra)
+ break;
+ size += size_of_loc_descr (l);
+ }
+ if (! l)
+ return size;
+
+ for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
+ {
+ l->dw_loc_addr = size;
+ size += size_of_loc_descr (l);
+ }
+
+ return size;
+}
+
+/* Output location description stack opcode's operands (if any). */
+
+static void
+output_loc_operands (dw_loc_descr_ref loc)
+{
+ dw_val_ref val1 = &loc->dw_loc_oprnd1;
+ dw_val_ref val2 = &loc->dw_loc_oprnd2;
+
+ switch (loc->dw_loc_opc)
+ {
+#ifdef DWARF2_DEBUGGING_INFO
+ case DW_OP_addr:
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
+ break;
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ dw2_asm_output_data (2, val1->v.val_int, NULL);
+ break;
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ dw2_asm_output_data (4, val1->v.val_int, NULL);
+ break;
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ gcc_assert (HOST_BITS_PER_LONG >= 64);
+ dw2_asm_output_data (8, val1->v.val_int, NULL);
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ {
+ int offset;
+
+ gcc_assert (val1->val_class == dw_val_class_loc);
+ offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
+
+ dw2_asm_output_data (2, offset, NULL);
+ }
+ break;
+#else
+ case DW_OP_addr:
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ case DW_OP_skip:
+ case DW_OP_bra:
+ /* We currently don't make any attempt to make sure these are
+ aligned properly like we do for the main unwind info, so
+ don't support emitting things larger than a byte if we're
+ only doing unwinding. */
+ gcc_unreachable ();
+#endif
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ dw2_asm_output_data (1, val1->v.val_int, NULL);
+ break;
+ case DW_OP_constu:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ break;
+ case DW_OP_consts:
+ dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
+ break;
+ case DW_OP_pick:
+ dw2_asm_output_data (1, val1->v.val_int, NULL);
+ break;
+ case DW_OP_plus_uconst:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
+ break;
+ case DW_OP_regx:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ break;
+ case DW_OP_fbreg:
+ dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
+ break;
+ case DW_OP_bregx:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
+ break;
+ case DW_OP_piece:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ break;
+ /* APPLE LOCAL begin 6186914 */
+ case DW_OP_bit_piece:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ dw2_asm_output_data_uleb128 (val2->v.val_unsigned, NULL);
+ break;
+ /* APPLE LOCAL end 6186914 */
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ dw2_asm_output_data (1, val1->v.val_int, NULL);
+ break;
+
+ case INTERNAL_DW_OP_tls_addr:
+ if (targetm.asm_out.output_dwarf_dtprel)
+ {
+ targetm.asm_out.output_dwarf_dtprel (asm_out_file,
+ DWARF2_ADDR_SIZE,
+ val1->v.val_addr);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ gcc_unreachable ();
+ break;
+
+ default:
+ /* Other codes have no operands. */
+ break;
+ }
+}
+
+/* Output a sequence of location operations. */
+
+static void
+output_loc_sequence (dw_loc_descr_ref loc)
+{
+ for (; loc != NULL; loc = loc->dw_loc_next)
+ {
+ /* Output the opcode. */
+ dw2_asm_output_data (1, loc->dw_loc_opc,
+ "%s", dwarf_stack_op_name (loc->dw_loc_opc));
+
+ /* Output the operand(s) (if any). */
+ output_loc_operands (loc);
+ }
+}
+
+/* This routine will generate the correct assembly data for a location
+ description based on a cfi entry with a complex address. */
+
+static void
+output_cfa_loc (dw_cfi_ref cfi)
+{
+ dw_loc_descr_ref loc;
+ unsigned long size;
+
+ /* Output the size of the block. */
+ loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
+ size = size_of_locs (loc);
+ dw2_asm_output_data_uleb128 (size, NULL);
+
+ /* Now output the operations themselves. */
+ output_loc_sequence (loc);
+}
+
+/* This function builds a dwarf location descriptor sequence from a
+ dw_cfa_location, adding the given OFFSET to the result of the
+ expression. */
+
+static struct dw_loc_descr_struct *
+build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
+{
+ struct dw_loc_descr_struct *head, *tmp;
+
+ offset += cfa->offset;
+
+ if (cfa->indirect)
+ {
+ if (cfa->base_offset)
+ {
+ if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
+ else
+ head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
+ }
+ else if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
+ else
+ head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
+
+ head->dw_loc_oprnd1.val_class = dw_val_class_const;
+ tmp = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (&head, tmp);
+ if (offset != 0)
+ {
+ tmp = new_loc_descr (DW_OP_plus_uconst, offset, 0);
+ add_loc_descr (&head, tmp);
+ }
+ }
+ else
+ {
+ if (offset == 0)
+ if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
+ else
+ head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
+ else if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_breg0 + cfa->reg, offset, 0);
+ else
+ head = new_loc_descr (DW_OP_bregx, cfa->reg, offset);
+ }
+
+ return head;
+}
+
+/* This function fills in aa dw_cfa_location structure from a dwarf location
+ descriptor sequence. */
+
+static void
+get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_struct *loc)
+{
+ struct dw_loc_descr_struct *ptr;
+ cfa->offset = 0;
+ cfa->base_offset = 0;
+ cfa->indirect = 0;
+ cfa->reg = -1;
+
+ for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next)
+ {
+ enum dwarf_location_atom op = ptr->dw_loc_opc;
+
+ switch (op)
+ {
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ cfa->reg = op - DW_OP_reg0;
+ break;
+ case DW_OP_regx:
+ cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ cfa->reg = op - DW_OP_breg0;
+ cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
+ break;
+ case DW_OP_bregx:
+ cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
+ cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int;
+ break;
+ case DW_OP_deref:
+ cfa->indirect = 1;
+ break;
+ case DW_OP_plus_uconst:
+ cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
+ break;
+ default:
+ internal_error ("DW_LOC_OP %s not implemented",
+ dwarf_stack_op_name (ptr->dw_loc_opc));
+ }
+ }
+}
+#endif /* .debug_frame support */
+
+/* And now, the support for symbolic debugging information. */
+#ifdef DWARF2_DEBUGGING_INFO
+
+/* .debug_str support. */
+static int output_indirect_string (void **, void *);
+
+static void dwarf2out_init (const char *);
+static void dwarf2out_finish (const char *);
+static void dwarf2out_define (unsigned int, const char *);
+static void dwarf2out_undef (unsigned int, const char *);
+static void dwarf2out_start_source_file (unsigned, const char *);
+static void dwarf2out_end_source_file (unsigned);
+static void dwarf2out_begin_block (unsigned, unsigned);
+static void dwarf2out_end_block (unsigned, unsigned);
+static bool dwarf2out_ignore_block (tree);
+static void dwarf2out_global_decl (tree);
+static void dwarf2out_type_decl (tree, int);
+static void dwarf2out_imported_module_or_decl (tree, tree);
+static void dwarf2out_abstract_function (tree);
+static void dwarf2out_var_location (rtx);
+static void dwarf2out_begin_function (tree);
+/* APPLE LOCAL opt diary */
+static void dwarf2out_od_entry (enum debug_od_msg, expanded_location);
+static void dwarf2out_switch_text_section (void);
+
+/* The debug hooks structure. */
+
+const struct gcc_debug_hooks dwarf2_debug_hooks =
+{
+ dwarf2out_init,
+ dwarf2out_finish,
+ dwarf2out_define,
+ dwarf2out_undef,
+ dwarf2out_start_source_file,
+ dwarf2out_end_source_file,
+ dwarf2out_begin_block,
+ dwarf2out_end_block,
+ dwarf2out_ignore_block,
+ dwarf2out_source_line,
+ dwarf2out_begin_prologue,
+ debug_nothing_int_charstar, /* end_prologue */
+ dwarf2out_end_epilogue,
+ dwarf2out_begin_function,
+ debug_nothing_int, /* end_function */
+ dwarf2out_decl, /* function_decl */
+ dwarf2out_global_decl,
+ dwarf2out_type_decl, /* type_decl */
+ dwarf2out_imported_module_or_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 */
+ debug_nothing_int, /* handle_pch */
+ dwarf2out_var_location,
+ /* APPLE LOCAL opt diary */
+ dwarf2out_od_entry, /* Optimization Diary Entry */
+ dwarf2out_switch_text_section,
+ 1 /* start_end_main_source_file */
+};
+#endif
+
+/* 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. */
+
+/* An internal representation of the DWARF output is built, and then
+ walked to generate the DWARF debugging info. The walk of the internal
+ representation is done after the entire program has been compiled.
+ The types below are used to describe the internal representation. */
+
+/* Various DIE's use offsets relative to the beginning of the
+ .debug_info section to refer to each other. */
+
+typedef long int dw_offset;
+
+/* Define typedefs here to avoid circular dependencies. */
+
+typedef struct dw_attr_struct *dw_attr_ref;
+typedef struct dw_line_info_struct *dw_line_info_ref;
+typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
+typedef struct pubname_struct *pubname_ref;
+typedef struct dw_ranges_struct *dw_ranges_ref;
+/* APPLE LOCAL radar 6275985 debug inlined section */
+typedef struct inlined_entry_struct *inlined_ref;
+
+/* Each entry in the line_info_table maintains the file and
+ line number associated with the label generated for that
+ entry. The label gives the PC value associated with
+ the line number entry. */
+
+typedef struct dw_line_info_struct GTY(())
+{
+ unsigned long dw_file_num;
+ unsigned long dw_line_num;
+}
+dw_line_info_entry;
+
+/* Line information for functions in separate sections; each one gets its
+ own sequence. */
+typedef struct dw_separate_line_info_struct GTY(())
+{
+ unsigned long dw_file_num;
+ unsigned long dw_line_num;
+ unsigned long function;
+}
+dw_separate_line_info_entry;
+
+/* Each DIE attribute has a field specifying the attribute kind,
+ a link to the next attribute in the chain, and an attribute value.
+ Attributes are typically linked below the DIE they modify. */
+
+typedef struct dw_attr_struct GTY(())
+{
+ enum dwarf_attribute dw_attr;
+ dw_val_node dw_attr_val;
+}
+dw_attr_node;
+
+DEF_VEC_O(dw_attr_node);
+DEF_VEC_ALLOC_O(dw_attr_node,gc);
+
+/* The Debugging Information Entry (DIE) structure. DIEs form a tree.
+ The children of each node form a circular list linked by
+ die_sib. die_child points to the node *before* the "first" child node. */
+
+typedef struct die_struct GTY(())
+{
+ enum dwarf_tag die_tag;
+ char *die_symbol;
+ VEC(dw_attr_node,gc) * die_attr;
+ dw_die_ref die_parent;
+ dw_die_ref die_child;
+ dw_die_ref die_sib;
+ dw_die_ref die_definition; /* ref from a specification to its definition */
+ dw_offset die_offset;
+ unsigned long die_abbrev;
+ int die_mark;
+ /* Die is used and must not be pruned as unused. */
+ int die_perennial_p;
+ unsigned int decl_id;
+ /* APPLE LOCAL begin radar 6476836 */
+ /* Mark inlined subroutine dies that are part of "eliminated" types. */
+ bool dead;
+ /* APPLE LOCAL end radar 6476836 */
+}
+die_node;
+
+/* Evaluate 'expr' while 'c' is set to each child of DIE in order. */
+#define FOR_EACH_CHILD(die, c, expr) do { \
+ c = die->die_child; \
+ if (c) do { \
+ c = c->die_sib; \
+ expr; \
+ } while (c != die->die_child); \
+} while (0)
+
+/* The pubname structure */
+
+typedef struct pubname_struct GTY(())
+{
+ dw_die_ref die;
+ char *name;
+}
+pubname_entry;
+
+/* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+DEF_VEC_O(pubname_entry);
+DEF_VEC_ALLOC_O(pubname_entry, gc);
+/* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+/* APPLE LOCAL begin radar 6275985 debug inlined section */
+DEF_VEC_O(dw_die_ref);
+DEF_VEC_ALLOC_O(dw_die_ref, gc);
+
+typedef struct inlined_entry_struct GTY (())
+{
+ dw_die_ref origin_die;
+ VEC(dw_die_ref,gc) *inlined_instances;
+}
+inlined_entry;
+
+DEF_VEC_O(inlined_entry);
+DEF_VEC_ALLOC_O(inlined_entry, gc);
+/* APPLE LOCAL end radar 6275985 debug inlined section */
+
+struct dw_ranges_struct GTY(())
+{
+ int block_num;
+};
+
+/* The limbo die list structure. */
+typedef struct limbo_die_struct GTY(())
+{
+ dw_die_ref die;
+ tree created_for;
+ struct limbo_die_struct *next;
+}
+limbo_die_node;
+
+/* How to start an assembler comment. */
+#ifndef ASM_COMMENT_START
+#define ASM_COMMENT_START ";#"
+#endif
+
+/* Define a macro which returns nonzero for a TYPE_DECL which was
+ implicitly generated for a tagged type.
+
+ Note that unlike the gcc front end (which generates a NULL named
+ TYPE_DECL node for each complete tagged type, each array type, and
+ each function type node created) the g++ front end generates a
+ _named_ TYPE_DECL node for each tagged type node created.
+ These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
+ generate a DW_TAG_typedef DIE for them. */
+
+#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))) \
+ /* This is necessary for stub decls that \
+ appear in nested inline functions. */ \
+ || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \
+ && (decl_ultimate_origin (decl) \
+ == TYPE_STUB_DECL (TREE_TYPE (decl)))))))
+
+/* Information concerning the compilation unit's programming
+ language, and compiler version. */
+
+/* Fixed size portion of the DWARF compilation unit header. */
+#define DWARF_COMPILE_UNIT_HEADER_SIZE \
+ (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
+
+/* Fixed size portion of public names info. */
+#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
+
+/* APPLE LOCAL begin radar 6275985 debug inlined section */
+/* Fixed size portion of inlined section info. */
+#define DWARF_INLINED_HEADER_SIZE (3)
+/* APPLE LOCAL end radar 6275985 debug inlined section */
+
+/* Fixed size portion of the address range info. */
+#define DWARF_ARANGES_HEADER_SIZE \
+ (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
+ DWARF2_ADDR_SIZE * 2) \
+ - DWARF_INITIAL_LENGTH_SIZE)
+
+/* Size of padding portion in the address range info. It must be
+ aligned to twice the pointer size. */
+#define DWARF_ARANGES_PAD_SIZE \
+ (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
+ DWARF2_ADDR_SIZE * 2) \
+ - (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4))
+
+/* Use assembler line directives if available. */
+#ifndef DWARF2_ASM_LINE_DEBUG_INFO
+#ifdef HAVE_AS_DWARF2_DEBUG_LINE
+#define DWARF2_ASM_LINE_DEBUG_INFO 1
+#else
+#define DWARF2_ASM_LINE_DEBUG_INFO 0
+#endif
+#endif
+
+/* Minimum line offset in a special line info. opcode.
+ This value was chosen to give a reasonable range of values. */
+#define DWARF_LINE_BASE -10
+
+/* First special line opcode - leave room for the standard opcodes. */
+#define DWARF_LINE_OPCODE_BASE 10
+
+/* Range of line offsets in a special line info. opcode. */
+#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1)
+
+/* Flag that indicates the initial value of the is_stmt_start flag.
+ In the present implementation, we do not mark any lines as
+ the beginning of a source statement, because that information
+ is not made available by the GCC front-end. */
+#define DWARF_LINE_DEFAULT_IS_STMT_START 1
+
+#ifdef DWARF2_DEBUGGING_INFO
+/* This location is used by calc_die_sizes() to keep track
+ the offset of each DIE within the .debug_info section. */
+static unsigned long next_die_offset;
+#endif
+
+/* Record the root of the DIE's built for the current compilation unit. */
+static GTY(()) dw_die_ref comp_unit_die;
+
+/* A list of DIEs with a NULL parent waiting to be relocated. */
+static GTY(()) limbo_die_node *limbo_die_list;
+
+/* Filenames referenced by this compilation unit. */
+static GTY((param_is (struct dwarf_file_data))) htab_t file_table;
+
+/* A hash table of references to DIE's that describe declarations.
+ The key is a DECL_UID() which is a unique number identifying each decl. */
+static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
+
+/* Node of the variable location list. */
+struct var_loc_node GTY ((chain_next ("%h.next")))
+{
+ rtx GTY (()) var_loc_note;
+ const char * GTY (()) label;
+ const char * GTY (()) section_label;
+ struct var_loc_node * GTY (()) next;
+};
+
+/* Variable location list. */
+struct var_loc_list_def GTY (())
+{
+ struct var_loc_node * GTY (()) first;
+
+ /* Do not mark the last element of the chained list because
+ it is marked through the chain. */
+ struct var_loc_node * GTY ((skip ("%h"))) last;
+
+ /* DECL_UID of the variable decl. */
+ unsigned int decl_id;
+};
+typedef struct var_loc_list_def var_loc_list;
+
+
+/* Table of decl location linked lists. */
+static GTY ((param_is (var_loc_list))) htab_t decl_loc_table;
+
+/* A pointer to the base of a list of references to DIE's that
+ are uniquely identified by their tag, presence/absence of
+ children DIE's, and list of attribute/value pairs. */
+static GTY((length ("abbrev_die_table_allocated")))
+ dw_die_ref *abbrev_die_table;
+
+/* Number of elements currently allocated for abbrev_die_table. */
+static GTY(()) unsigned abbrev_die_table_allocated;
+
+/* Number of elements in type_die_table currently in use. */
+static GTY(()) unsigned abbrev_die_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ abbrev_die_table. */
+#define ABBREV_DIE_TABLE_INCREMENT 256
+
+/* A pointer to the base of a table that contains line information
+ for each source code line in .text in the compilation unit. */
+static GTY((length ("line_info_table_allocated")))
+ dw_line_info_ref line_info_table;
+
+/* Number of elements currently allocated for line_info_table. */
+static GTY(()) unsigned line_info_table_allocated;
+
+/* Number of elements in line_info_table currently in use. */
+static GTY(()) unsigned line_info_table_in_use;
+
+/* True if the compilation unit places functions in more than one section. */
+static GTY(()) bool have_multiple_function_sections = false;
+
+/* A pointer to the base of a table that contains line information
+ for each source code line outside of .text in the compilation unit. */
+static GTY ((length ("separate_line_info_table_allocated")))
+ dw_separate_line_info_ref separate_line_info_table;
+
+/* Number of elements currently allocated for separate_line_info_table. */
+static GTY(()) unsigned separate_line_info_table_allocated;
+
+/* Number of elements in separate_line_info_table currently in use. */
+static GTY(()) unsigned separate_line_info_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ line_info_table. */
+#define LINE_INFO_TABLE_INCREMENT 1024
+
+/* A pointer to the base of a table that contains a list of publicly
+ accessible names. */
+/* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+static GTY (()) VEC (pubname_entry, gc) * pubname_table;
+
+/* A pointer to the base of a table that contains a list of publicy
+ accessible types. */
+
+static GTY (()) VEC (pubname_entry, gc) * pubtype_table;
+/* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+/* APPLE LOCAL radar 6275985 debug inlined section */
+static GTY (()) VEC (inlined_entry, gc) * debug_inlined_table;
+
+/* Array of dies for which we should generate .debug_arange info. */
+static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table;
+
+/* Number of elements currently allocated for arange_table. */
+static GTY(()) unsigned arange_table_allocated;
+
+/* Number of elements in arange_table currently in use. */
+static GTY(()) unsigned arange_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ arange_table. */
+#define ARANGE_TABLE_INCREMENT 64
+
+/* Array of dies for which we should generate .debug_ranges info. */
+static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table;
+
+/* Number of elements currently allocated for ranges_table. */
+static GTY(()) unsigned ranges_table_allocated;
+
+/* Number of elements in ranges_table currently in use. */
+static GTY(()) unsigned ranges_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ ranges_table. */
+#define RANGES_TABLE_INCREMENT 64
+
+/* Whether we have location lists that need outputting */
+static GTY(()) bool have_location_lists;
+
+/* Unique label counter. */
+static GTY(()) unsigned int loclabel_num;
+
+#ifdef DWARF2_DEBUGGING_INFO
+/* Record whether the function being analyzed contains inlined functions. */
+static int current_function_has_inlines;
+#endif
+#if 0 && defined (MIPS_DEBUGGING_INFO)
+static int comp_unit_has_inlines;
+#endif
+
+/* The last file entry emitted by maybe_emit_file(). */
+static GTY(()) struct dwarf_file_data * last_emitted_file;
+
+/* Number of internal labels generated by gen_internal_sym(). */
+static GTY(()) int label_num;
+
+/* Cached result of previous call to lookup_filename. */
+static GTY(()) struct dwarf_file_data * file_table_last_lookup;
+
+#ifdef DWARF2_DEBUGGING_INFO
+
+/* Offset from the "steady-state frame pointer" to the frame base,
+ within the current function. */
+static HOST_WIDE_INT frame_pointer_fb_offset;
+
+/* APPLE LOCAL begin ARM prefer SP to FP */
+/* Which register was used to calculate the frame_pointer_fb_offset. */
+static rtx frame_pointer_fb_offset_from;
+/* APPLE LOCAL end ARM prefer SP to FP */
+
+/* Forward declarations for functions defined in this file. */
+
+static int is_pseudo_reg (rtx);
+static tree type_main_variant (tree);
+static int is_tagged_type (tree);
+static const char *dwarf_tag_name (unsigned);
+static const char *dwarf_attr_name (unsigned);
+static const char *dwarf_form_name (unsigned);
+static tree decl_ultimate_origin (tree);
+static tree block_ultimate_origin (tree);
+static tree decl_class_context (tree);
+static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
+static inline enum dw_val_class AT_class (dw_attr_ref);
+static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
+static inline unsigned AT_flag (dw_attr_ref);
+static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
+static inline HOST_WIDE_INT AT_int (dw_attr_ref);
+static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT);
+static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
+static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
+ unsigned long);
+static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
+ unsigned int, unsigned char *);
+static hashval_t debug_str_do_hash (const void *);
+static int debug_str_eq (const void *, const void *);
+static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
+static inline const char *AT_string (dw_attr_ref);
+static int AT_string_form (dw_attr_ref);
+static void add_AT_die_ref (dw_die_ref, enum dwarf_attribute, dw_die_ref);
+static void add_AT_specification (dw_die_ref, dw_die_ref);
+static inline dw_die_ref AT_ref (dw_attr_ref);
+static inline int AT_ref_external (dw_attr_ref);
+static inline void set_AT_ref_external (dw_attr_ref, int);
+static void add_AT_fde_ref (dw_die_ref, enum dwarf_attribute, unsigned);
+static void add_AT_loc (dw_die_ref, enum dwarf_attribute, dw_loc_descr_ref);
+static inline dw_loc_descr_ref AT_loc (dw_attr_ref);
+static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
+ dw_loc_list_ref);
+static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
+static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
+static inline rtx AT_addr (dw_attr_ref);
+static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
+ unsigned HOST_WIDE_INT);
+static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
+ unsigned long);
+static inline const char *AT_lbl (dw_attr_ref);
+static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
+static const char *get_AT_low_pc (dw_die_ref);
+static const char *get_AT_hi_pc (dw_die_ref);
+static const char *get_AT_string (dw_die_ref, enum dwarf_attribute);
+static int get_AT_flag (dw_die_ref, enum dwarf_attribute);
+static unsigned get_AT_unsigned (dw_die_ref, enum dwarf_attribute);
+static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
+static bool is_c_family (void);
+static bool is_cxx (void);
+/* APPLE LOCAL begin radar 6113240 */
+static bool is_objc (void);
+static bool is_objcxx (void);
+/* APPLE LOCAL end radar 6113240 */
+static bool is_java (void);
+static bool is_fortran (void);
+static bool is_ada (void);
+static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
+static void add_child_die (dw_die_ref, dw_die_ref);
+static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
+static dw_die_ref lookup_type_die (tree);
+static void equate_type_number_to_die (tree, dw_die_ref);
+static hashval_t decl_die_table_hash (const void *);
+static int decl_die_table_eq (const void *, const void *);
+static dw_die_ref lookup_decl_die (tree);
+static hashval_t decl_loc_table_hash (const void *);
+static int decl_loc_table_eq (const void *, const void *);
+static var_loc_list *lookup_decl_loc (tree);
+static void equate_decl_number_to_die (tree, dw_die_ref);
+static void add_var_loc_to_decl (tree, struct var_loc_node *);
+static void print_spaces (FILE *);
+static void print_die (dw_die_ref, FILE *);
+static void print_dwarf_line_table (FILE *);
+static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
+static dw_die_ref pop_compile_unit (dw_die_ref);
+static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
+static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *);
+static void die_checksum (dw_die_ref, struct md5_ctx *, int *);
+static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
+static int same_dw_val_p (dw_val_node *, dw_val_node *, int *);
+static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
+static int same_die_p (dw_die_ref, dw_die_ref, int *);
+static int same_die_p_wrap (dw_die_ref, dw_die_ref);
+static void compute_section_prefix (dw_die_ref);
+static int is_type_die (dw_die_ref);
+static int is_comdat_die (dw_die_ref);
+static int is_symbol_die (dw_die_ref);
+static void assign_symbol_names (dw_die_ref);
+static void break_out_includes (dw_die_ref);
+static hashval_t htab_cu_hash (const void *);
+static int htab_cu_eq (const void *, const void *);
+static void htab_cu_del (void *);
+static int check_duplicate_cu (dw_die_ref, htab_t, unsigned *);
+static void record_comdat_symbol_number (dw_die_ref, htab_t, unsigned);
+static void add_sibling_attributes (dw_die_ref);
+static void build_abbrev_table (dw_die_ref);
+static void output_location_lists (dw_die_ref);
+static int constant_size (long unsigned);
+static unsigned long size_of_die (dw_die_ref);
+static void calc_die_sizes (dw_die_ref);
+static void mark_dies (dw_die_ref);
+static void unmark_dies (dw_die_ref);
+static void unmark_all_dies (dw_die_ref);
+/* APPLE LOCAL pubtypes, approved for 4.3 4535968 */
+static unsigned long size_of_pubnames (VEC (pubname_entry,gc) *);
+/* APPLE LOCAL radar 6275985 debug inlined section */
+static unsigned long size_of_inlined (VEC (inlined_entry,gc) *);
+static unsigned long size_of_aranges (void);
+static enum dwarf_form value_format (dw_attr_ref);
+static void output_value_format (dw_attr_ref);
+static void output_abbrev_section (void);
+static void output_die_symbol (dw_die_ref);
+static void output_die (dw_die_ref);
+static void output_compilation_unit_header (void);
+static void output_comp_unit (dw_die_ref, int);
+static const char *dwarf2_name (tree, int);
+static void add_pubname (tree, dw_die_ref);
+/* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+static void add_pubtype (tree, dw_die_ref);
+static void output_pubnames (VEC (pubname_entry,gc) *);
+/* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+/* APPLE LOCAL begin radar 6275985 debug inlined section */
+static void add_inlined_section_entry (dw_die_ref);
+static void output_debug_inlined_section (VEC (inlined_entry,gc) *);
+/* APPLE LOCAL end radar 6275985 debug inlined section */
+static void add_arange (tree, dw_die_ref);
+static void output_aranges (void);
+static unsigned int add_ranges (tree);
+static void output_ranges (void);
+static void output_line_info (void);
+static void output_file_names (void);
+static dw_die_ref base_type_die (tree);
+static tree root_type (tree);
+static int is_base_type (tree);
+static bool is_subrange_type (tree);
+static dw_die_ref subrange_type_die (tree, dw_die_ref);
+static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
+static int type_is_enum (tree);
+static unsigned int dbx_reg_number (rtx);
+static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref reg_loc_descriptor (rtx, enum var_init_status);
+static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int,
+ enum var_init_status);
+static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
+ enum var_init_status);
+static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
+static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
+ enum var_init_status);
+static int is_based_loc (rtx);
+static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
+ enum var_init_status);
+static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
+ enum var_init_status);
+static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status);
+/* APPLE LOCAL end track initialization status 4964532 */
+static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree);
+static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
+static tree field_type (tree);
+static unsigned int simple_type_align_in_bits (tree);
+static unsigned int simple_decl_align_in_bits (tree);
+static unsigned HOST_WIDE_INT simple_type_size_in_bits (tree);
+static HOST_WIDE_INT field_byte_offset (tree);
+static void add_AT_location_description (dw_die_ref, enum dwarf_attribute,
+ dw_loc_descr_ref);
+static void add_data_member_location_attribute (dw_die_ref, tree);
+static void add_const_value_attribute (dw_die_ref, rtx);
+static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+static void insert_float (rtx, unsigned char *);
+static rtx rtl_for_decl_location (tree);
+static void add_location_or_const_value_attribute (dw_die_ref, tree,
+ enum dwarf_attribute);
+static void tree_add_const_value_attribute (dw_die_ref, tree);
+static void add_name_attribute (dw_die_ref, const char *);
+static void add_comp_dir_attribute (dw_die_ref);
+static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
+static void add_subscript_info (dw_die_ref, tree);
+static void add_byte_size_attribute (dw_die_ref, tree);
+static void add_bit_offset_attribute (dw_die_ref, tree);
+static void add_bit_size_attribute (dw_die_ref, tree);
+static void add_prototyped_attribute (dw_die_ref, tree);
+static void add_abstract_origin_attribute (dw_die_ref, tree);
+static void add_pure_or_virtual_attribute (dw_die_ref, tree);
+static void add_src_coords_attributes (dw_die_ref, tree);
+static void add_name_and_src_coords_attributes (dw_die_ref, tree);
+static void push_decl_scope (tree);
+static void pop_decl_scope (void);
+static dw_die_ref scope_die_for (tree, dw_die_ref);
+static inline int local_scope_p (dw_die_ref);
+static inline int class_or_namespace_scope_p (dw_die_ref);
+static void add_type_attribute (dw_die_ref, tree, int, int, dw_die_ref);
+static void add_calling_convention_attribute (dw_die_ref, tree);
+static const char *type_tag (tree);
+static tree member_declared_type (tree);
+#if 0
+static const char *decl_start_label (tree);
+#endif
+static void gen_array_type_die (tree, dw_die_ref);
+#if 0
+static void gen_entry_point_die (tree, dw_die_ref);
+#endif
+static void gen_inlined_enumeration_type_die (tree, dw_die_ref);
+static void gen_inlined_structure_type_die (tree, dw_die_ref);
+static void gen_inlined_union_type_die (tree, dw_die_ref);
+static dw_die_ref gen_enumeration_type_die (tree, dw_die_ref);
+static dw_die_ref gen_formal_parameter_die (tree, dw_die_ref);
+static void gen_unspecified_parameters_die (tree, dw_die_ref);
+static void gen_formal_types_die (tree, dw_die_ref);
+static void gen_subprogram_die (tree, dw_die_ref);
+static void gen_variable_die (tree, dw_die_ref);
+static void gen_label_die (tree, dw_die_ref);
+static void gen_lexical_block_die (tree, dw_die_ref, int);
+static void gen_inlined_subroutine_die (tree, dw_die_ref, int);
+static void gen_field_die (tree, dw_die_ref);
+static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
+static dw_die_ref gen_compile_unit_die (const char *);
+static void gen_inheritance_die (tree, tree, dw_die_ref);
+static void gen_member_die (tree, dw_die_ref);
+static void gen_struct_or_union_type_die (tree, dw_die_ref);
+static void gen_subroutine_type_die (tree, dw_die_ref);
+static void gen_typedef_die (tree, dw_die_ref);
+static void gen_type_die (tree, dw_die_ref);
+static void gen_tagged_type_instantiation_die (tree, dw_die_ref);
+static void gen_block_die (tree, dw_die_ref, int);
+static void decls_for_scope (tree, dw_die_ref, int);
+static int is_redundant_typedef (tree);
+static void gen_namespace_die (tree);
+static void gen_decl_die (tree, dw_die_ref);
+static dw_die_ref force_decl_die (tree);
+static dw_die_ref force_type_die (tree);
+static dw_die_ref setup_namespace_context (tree, dw_die_ref);
+static void declare_in_namespace (tree, dw_die_ref);
+static struct dwarf_file_data * lookup_filename (const char *);
+static void retry_incomplete_types (void);
+static void gen_type_die_for_member (tree, tree, dw_die_ref);
+static void splice_child_die (dw_die_ref, dw_die_ref);
+static int file_info_cmp (const void *, const void *);
+static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
+ const char *, const char *, unsigned);
+static void add_loc_descr_to_loc_list (dw_loc_list_ref *, dw_loc_descr_ref,
+ const char *, const char *,
+ const char *);
+static void output_loc_list (dw_loc_list_ref);
+static char *gen_internal_sym (const char *);
+
+static void prune_unmark_dies (dw_die_ref);
+static void prune_unused_types_mark (dw_die_ref, int);
+static void prune_unused_types_walk (dw_die_ref);
+static void prune_unused_types_walk_attribs (dw_die_ref);
+static void prune_unused_types_prune (dw_die_ref);
+static void prune_unused_types (void);
+static int maybe_emit_file (struct dwarf_file_data *fd);
+
+/* Section names used to hold DWARF debugging information. */
+#ifndef DEBUG_INFO_SECTION
+#define DEBUG_INFO_SECTION ".debug_info"
+#endif
+#ifndef DEBUG_ABBREV_SECTION
+#define DEBUG_ABBREV_SECTION ".debug_abbrev"
+#endif
+#ifndef DEBUG_ARANGES_SECTION
+#define DEBUG_ARANGES_SECTION ".debug_aranges"
+#endif
+#ifndef DEBUG_MACINFO_SECTION
+#define DEBUG_MACINFO_SECTION ".debug_macinfo"
+#endif
+#ifndef DEBUG_LINE_SECTION
+#define DEBUG_LINE_SECTION ".debug_line"
+#endif
+#ifndef DEBUG_LOC_SECTION
+#define DEBUG_LOC_SECTION ".debug_loc"
+#endif
+#ifndef DEBUG_PUBNAMES_SECTION
+#define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
+#endif
+#ifndef DEBUG_STR_SECTION
+#define DEBUG_STR_SECTION ".debug_str"
+#endif
+#ifndef DEBUG_RANGES_SECTION
+#define DEBUG_RANGES_SECTION ".debug_ranges"
+#endif
+
+/* Standard ELF section names for compiled code and data. */
+#ifndef TEXT_SECTION_NAME
+#define TEXT_SECTION_NAME ".text"
+#endif
+
+/* Section flags for .debug_str section. */
+#define DEBUG_STR_SECTION_FLAGS \
+ (HAVE_GAS_SHF_MERGE && flag_merge_constants \
+ ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \
+ : SECTION_DEBUG)
+
+/* Labels we insert at beginning sections we can reference instead of
+ the section names themselves. */
+
+#ifndef TEXT_SECTION_LABEL
+#define TEXT_SECTION_LABEL "Ltext"
+#endif
+#ifndef COLD_TEXT_SECTION_LABEL
+#define COLD_TEXT_SECTION_LABEL "Ltext_cold"
+#endif
+#ifndef DEBUG_LINE_SECTION_LABEL
+#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
+#endif
+#ifndef DEBUG_INFO_SECTION_LABEL
+#define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
+#endif
+#ifndef DEBUG_ABBREV_SECTION_LABEL
+#define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev"
+#endif
+#ifndef DEBUG_LOC_SECTION_LABEL
+#define DEBUG_LOC_SECTION_LABEL "Ldebug_loc"
+#endif
+#ifndef DEBUG_RANGES_SECTION_LABEL
+#define DEBUG_RANGES_SECTION_LABEL "Ldebug_ranges"
+#endif
+#ifndef DEBUG_MACINFO_SECTION_LABEL
+#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
+#endif
+
+/* 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 DWARF2_DEBUGGING_INFO is in effect.
+ If necessary, these may be overridden from within the tm.h file, but
+ typically, overriding these defaults is unnecessary. */
+
+static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
+
+#ifndef TEXT_END_LABEL
+#define TEXT_END_LABEL "Letext"
+#endif
+#ifndef COLD_END_LABEL
+#define COLD_END_LABEL "Letext_cold"
+#endif
+#ifndef BLOCK_BEGIN_LABEL
+#define BLOCK_BEGIN_LABEL "LBB"
+#endif
+#ifndef BLOCK_END_LABEL
+#define BLOCK_END_LABEL "LBE"
+#endif
+#ifndef LINE_CODE_LABEL
+#define LINE_CODE_LABEL "LM"
+#endif
+#ifndef SEPARATE_LINE_CODE_LABEL
+#define SEPARATE_LINE_CODE_LABEL "LSM"
+#endif
+
+/* We allow a language front-end to designate a function that is to be
+ called to "demangle" any name before it is put into a DIE. */
+
+static const char *(*demangle_name_func) (const char *);
+
+void
+dwarf2out_set_demangle_name_func (const char *(*func) (const char *))
+{
+ demangle_name_func = func;
+}
+
+/* Test if rtl node points to a pseudo register. */
+
+static inline int
+is_pseudo_reg (rtx rtl)
+{
+ return ((REG_P (rtl) && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
+ || (GET_CODE (rtl) == SUBREG
+ && REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
+}
+
+/* Return a reference to a type, with its const and volatile qualifiers
+ removed. */
+
+static inline tree
+type_main_variant (tree type)
+{
+ type = TYPE_MAIN_VARIANT (type);
+
+ /* ??? There really should be only one main variant among any group of
+ variants of a given type (and all of the MAIN_VARIANT values for all
+ members of the group should point to that one type) but sometimes the C
+ front-end messes this up for array types, so we work around that bug
+ here. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ while (type != TYPE_MAIN_VARIANT (type))
+ type = TYPE_MAIN_VARIANT (type);
+
+ return type;
+}
+
+/* Return nonzero if the given type node represents a tagged type. */
+
+static inline int
+is_tagged_type (tree type)
+{
+ enum tree_code code = TREE_CODE (type);
+
+ return (code == RECORD_TYPE || code == UNION_TYPE
+ || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
+}
+
+/* Convert a DIE tag into its string name. */
+
+static const char *
+dwarf_tag_name (unsigned int tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_padding:
+ return "DW_TAG_padding";
+ case DW_TAG_array_type:
+ return "DW_TAG_array_type";
+ case DW_TAG_class_type:
+ return "DW_TAG_class_type";
+ case DW_TAG_entry_point:
+ return "DW_TAG_entry_point";
+ case DW_TAG_enumeration_type:
+ return "DW_TAG_enumeration_type";
+ case DW_TAG_formal_parameter:
+ return "DW_TAG_formal_parameter";
+ case DW_TAG_imported_declaration:
+ return "DW_TAG_imported_declaration";
+ case DW_TAG_label:
+ return "DW_TAG_label";
+ case DW_TAG_lexical_block:
+ return "DW_TAG_lexical_block";
+ case DW_TAG_member:
+ return "DW_TAG_member";
+ case DW_TAG_pointer_type:
+ return "DW_TAG_pointer_type";
+ case DW_TAG_reference_type:
+ return "DW_TAG_reference_type";
+ case DW_TAG_compile_unit:
+ return "DW_TAG_compile_unit";
+ case DW_TAG_string_type:
+ return "DW_TAG_string_type";
+ case DW_TAG_structure_type:
+ return "DW_TAG_structure_type";
+ case DW_TAG_subroutine_type:
+ return "DW_TAG_subroutine_type";
+ case DW_TAG_typedef:
+ return "DW_TAG_typedef";
+ case DW_TAG_union_type:
+ return "DW_TAG_union_type";
+ case DW_TAG_unspecified_parameters:
+ return "DW_TAG_unspecified_parameters";
+ case DW_TAG_variant:
+ return "DW_TAG_variant";
+ case DW_TAG_common_block:
+ return "DW_TAG_common_block";
+ case DW_TAG_common_inclusion:
+ return "DW_TAG_common_inclusion";
+ case DW_TAG_inheritance:
+ return "DW_TAG_inheritance";
+ case DW_TAG_inlined_subroutine:
+ return "DW_TAG_inlined_subroutine";
+ case DW_TAG_module:
+ return "DW_TAG_module";
+ case DW_TAG_ptr_to_member_type:
+ return "DW_TAG_ptr_to_member_type";
+ case DW_TAG_set_type:
+ return "DW_TAG_set_type";
+ case DW_TAG_subrange_type:
+ return "DW_TAG_subrange_type";
+ case DW_TAG_with_stmt:
+ return "DW_TAG_with_stmt";
+ case DW_TAG_access_declaration:
+ return "DW_TAG_access_declaration";
+ case DW_TAG_base_type:
+ return "DW_TAG_base_type";
+ case DW_TAG_catch_block:
+ return "DW_TAG_catch_block";
+ case DW_TAG_const_type:
+ return "DW_TAG_const_type";
+ case DW_TAG_constant:
+ return "DW_TAG_constant";
+ case DW_TAG_enumerator:
+ return "DW_TAG_enumerator";
+ case DW_TAG_file_type:
+ return "DW_TAG_file_type";
+ case DW_TAG_friend:
+ return "DW_TAG_friend";
+ case DW_TAG_namelist:
+ return "DW_TAG_namelist";
+ case DW_TAG_namelist_item:
+ return "DW_TAG_namelist_item";
+ case DW_TAG_namespace:
+ return "DW_TAG_namespace";
+ case DW_TAG_packed_type:
+ return "DW_TAG_packed_type";
+ case DW_TAG_subprogram:
+ return "DW_TAG_subprogram";
+ case DW_TAG_template_type_param:
+ return "DW_TAG_template_type_param";
+ case DW_TAG_template_value_param:
+ return "DW_TAG_template_value_param";
+ case DW_TAG_thrown_type:
+ return "DW_TAG_thrown_type";
+ case DW_TAG_try_block:
+ return "DW_TAG_try_block";
+ case DW_TAG_variant_part:
+ return "DW_TAG_variant_part";
+ case DW_TAG_variable:
+ return "DW_TAG_variable";
+ case DW_TAG_volatile_type:
+ return "DW_TAG_volatile_type";
+ case DW_TAG_imported_module:
+ return "DW_TAG_imported_module";
+ case DW_TAG_MIPS_loop:
+ return "DW_TAG_MIPS_loop";
+ case DW_TAG_format_label:
+ return "DW_TAG_format_label";
+ case DW_TAG_function_template:
+ return "DW_TAG_function_template";
+ case DW_TAG_class_template:
+ return "DW_TAG_class_template";
+ case DW_TAG_GNU_BINCL:
+ return "DW_TAG_GNU_BINCL";
+ case DW_TAG_GNU_EINCL:
+ return "DW_TAG_GNU_EINCL";
+ /* APPLE LOCAL begin opt diary */
+ case DW_TAG_GNU_OD_entry:
+ return "DW_TAG_GNU_OD_entry";
+ /* APPLE LOCAL end opt diary */
+ default:
+ return "DW_TAG_<unknown>";
+ }
+}
+
+/* Convert a DWARF attribute code into its string name. */
+
+static const char *
+dwarf_attr_name (unsigned int attr)
+{
+ switch (attr)
+ {
+ case DW_AT_sibling:
+ return "DW_AT_sibling";
+ case DW_AT_location:
+ return "DW_AT_location";
+ case DW_AT_name:
+ return "DW_AT_name";
+ case DW_AT_ordering:
+ return "DW_AT_ordering";
+ case DW_AT_subscr_data:
+ return "DW_AT_subscr_data";
+ case DW_AT_byte_size:
+ return "DW_AT_byte_size";
+ case DW_AT_bit_offset:
+ return "DW_AT_bit_offset";
+ case DW_AT_bit_size:
+ return "DW_AT_bit_size";
+ case DW_AT_element_list:
+ return "DW_AT_element_list";
+ case DW_AT_stmt_list:
+ return "DW_AT_stmt_list";
+ case DW_AT_low_pc:
+ return "DW_AT_low_pc";
+ case DW_AT_high_pc:
+ return "DW_AT_high_pc";
+ case DW_AT_language:
+ return "DW_AT_language";
+ case DW_AT_member:
+ return "DW_AT_member";
+ case DW_AT_discr:
+ return "DW_AT_discr";
+ case DW_AT_discr_value:
+ return "DW_AT_discr_value";
+ case DW_AT_visibility:
+ return "DW_AT_visibility";
+ case DW_AT_import:
+ return "DW_AT_import";
+ case DW_AT_string_length:
+ return "DW_AT_string_length";
+ case DW_AT_common_reference:
+ return "DW_AT_common_reference";
+ case DW_AT_comp_dir:
+ return "DW_AT_comp_dir";
+ case DW_AT_const_value:
+ return "DW_AT_const_value";
+ case DW_AT_containing_type:
+ return "DW_AT_containing_type";
+ case DW_AT_default_value:
+ return "DW_AT_default_value";
+ case DW_AT_inline:
+ return "DW_AT_inline";
+ case DW_AT_is_optional:
+ return "DW_AT_is_optional";
+ case DW_AT_lower_bound:
+ return "DW_AT_lower_bound";
+ case DW_AT_producer:
+ return "DW_AT_producer";
+ case DW_AT_prototyped:
+ return "DW_AT_prototyped";
+ case DW_AT_return_addr:
+ return "DW_AT_return_addr";
+ case DW_AT_start_scope:
+ return "DW_AT_start_scope";
+ case DW_AT_stride_size:
+ return "DW_AT_stride_size";
+ case DW_AT_upper_bound:
+ return "DW_AT_upper_bound";
+ case DW_AT_abstract_origin:
+ return "DW_AT_abstract_origin";
+ case DW_AT_accessibility:
+ return "DW_AT_accessibility";
+ case DW_AT_address_class:
+ return "DW_AT_address_class";
+ case DW_AT_artificial:
+ return "DW_AT_artificial";
+ case DW_AT_base_types:
+ return "DW_AT_base_types";
+ case DW_AT_calling_convention:
+ return "DW_AT_calling_convention";
+ case DW_AT_count:
+ return "DW_AT_count";
+ case DW_AT_data_member_location:
+ return "DW_AT_data_member_location";
+ case DW_AT_decl_column:
+ return "DW_AT_decl_column";
+ case DW_AT_decl_file:
+ return "DW_AT_decl_file";
+ case DW_AT_decl_line:
+ return "DW_AT_decl_line";
+ case DW_AT_declaration:
+ return "DW_AT_declaration";
+ case DW_AT_discr_list:
+ return "DW_AT_discr_list";
+ case DW_AT_encoding:
+ return "DW_AT_encoding";
+ case DW_AT_external:
+ return "DW_AT_external";
+ case DW_AT_frame_base:
+ return "DW_AT_frame_base";
+ case DW_AT_friend:
+ return "DW_AT_friend";
+ case DW_AT_identifier_case:
+ return "DW_AT_identifier_case";
+ case DW_AT_macro_info:
+ return "DW_AT_macro_info";
+ case DW_AT_namelist_items:
+ return "DW_AT_namelist_items";
+ case DW_AT_priority:
+ return "DW_AT_priority";
+ case DW_AT_segment:
+ return "DW_AT_segment";
+ case DW_AT_specification:
+ return "DW_AT_specification";
+ case DW_AT_static_link:
+ return "DW_AT_static_link";
+ case DW_AT_type:
+ return "DW_AT_type";
+ case DW_AT_use_location:
+ return "DW_AT_use_location";
+ case DW_AT_variable_parameter:
+ return "DW_AT_variable_parameter";
+ case DW_AT_virtuality:
+ return "DW_AT_virtuality";
+ case DW_AT_vtable_elem_location:
+ return "DW_AT_vtable_elem_location";
+
+ case DW_AT_allocated:
+ return "DW_AT_allocated";
+ case DW_AT_associated:
+ return "DW_AT_associated";
+ case DW_AT_data_location:
+ return "DW_AT_data_location";
+ case DW_AT_stride:
+ return "DW_AT_stride";
+ case DW_AT_entry_pc:
+ return "DW_AT_entry_pc";
+ case DW_AT_use_UTF8:
+ return "DW_AT_use_UTF8";
+ case DW_AT_extension:
+ return "DW_AT_extension";
+ case DW_AT_ranges:
+ return "DW_AT_ranges";
+ case DW_AT_trampoline:
+ return "DW_AT_trampoline";
+ case DW_AT_call_column:
+ return "DW_AT_call_column";
+ case DW_AT_call_file:
+ return "DW_AT_call_file";
+ case DW_AT_call_line:
+ return "DW_AT_call_line";
+
+ case DW_AT_MIPS_fde:
+ return "DW_AT_MIPS_fde";
+ case DW_AT_MIPS_loop_begin:
+ return "DW_AT_MIPS_loop_begin";
+ case DW_AT_MIPS_tail_loop_begin:
+ return "DW_AT_MIPS_tail_loop_begin";
+ case DW_AT_MIPS_epilog_begin:
+ return "DW_AT_MIPS_epilog_begin";
+ case DW_AT_MIPS_loop_unroll_factor:
+ return "DW_AT_MIPS_loop_unroll_factor";
+ case DW_AT_MIPS_software_pipeline_depth:
+ return "DW_AT_MIPS_software_pipeline_depth";
+ case DW_AT_MIPS_linkage_name:
+ return "DW_AT_MIPS_linkage_name";
+ case DW_AT_MIPS_stride:
+ return "DW_AT_MIPS_stride";
+ case DW_AT_MIPS_abstract_name:
+ return "DW_AT_MIPS_abstract_name";
+ case DW_AT_MIPS_clone_origin:
+ return "DW_AT_MIPS_clone_origin";
+ case DW_AT_MIPS_has_inlines:
+ return "DW_AT_MIPS_has_inlines";
+
+ case DW_AT_sf_names:
+ return "DW_AT_sf_names";
+ case DW_AT_src_info:
+ return "DW_AT_src_info";
+ case DW_AT_mac_info:
+ return "DW_AT_mac_info";
+ case DW_AT_src_coords:
+ return "DW_AT_src_coords";
+ case DW_AT_body_begin:
+ return "DW_AT_body_begin";
+ case DW_AT_body_end:
+ return "DW_AT_body_end";
+ case DW_AT_GNU_vector:
+ return "DW_AT_GNU_vector";
+ /* APPLE LOCAL begin opt diary */
+ case DW_AT_GNU_OD_msg:
+ return "DW_AT_GNU_OD_msg";
+ case DW_AT_GNU_OD_category:
+ return "DW_AT_GNU_OD_category";
+ case DW_AT_GNU_OD_version:
+ return "DW_AT_GNU_OD_version";
+ /* APPLE LOCAL end opt diary */
+
+ case DW_AT_VMS_rtnbeg_pd_address:
+ return "DW_AT_VMS_rtnbeg_pd_address";
+
+ /* APPLE LOCAL begin radar 2338865 optimization notification */
+ case DW_AT_APPLE_flags:
+ return "DW_AT_APPLE_flags";
+ case DW_AT_APPLE_optimized:
+ return "DW_AT_APPLE_optimized";
+ /* APPLE LOCAL end radar 2338865 optimization notification */
+ /* APPLE LOCAL begin differentiate between arm & thumb. */
+ case DW_AT_APPLE_isa:
+ return "DW_AT_APPLE_isa";
+ /* APPLE LOCAL end differentiate between arm & thumb. */
+
+ /* APPLE LOCAL begin radar 5811943 - Fix type of pointers to Blocks */
+ case DW_AT_APPLE_block:
+ return "DW_AT_APPLE_block";
+ /* APPLE LOCAL end radar 5811943 - Fix type of pointers to Blocks */
+ /* APPLE LOCAL begin radar 6386976 */
+ case DW_AT_APPLE_major_runtime_vers:
+ return "DW_AT_APPLE_major_runtime_vers";
+ case DW_AT_APPLE_runtime_class:
+ return "DW_AT_APPLE_runtime_class";
+ /* APPLE LOCAL end radar 6386976 */
+ default:
+ return "DW_AT_<unknown>";
+ }
+}
+
+/* Convert a DWARF value form code into its string name. */
+
+static const char *
+dwarf_form_name (unsigned int form)
+{
+ switch (form)
+ {
+ case DW_FORM_addr:
+ return "DW_FORM_addr";
+ case DW_FORM_block2:
+ return "DW_FORM_block2";
+ case DW_FORM_block4:
+ return "DW_FORM_block4";
+ case DW_FORM_data2:
+ return "DW_FORM_data2";
+ case DW_FORM_data4:
+ return "DW_FORM_data4";
+ case DW_FORM_data8:
+ return "DW_FORM_data8";
+ case DW_FORM_string:
+ return "DW_FORM_string";
+ case DW_FORM_block:
+ return "DW_FORM_block";
+ case DW_FORM_block1:
+ return "DW_FORM_block1";
+ case DW_FORM_data1:
+ return "DW_FORM_data1";
+ case DW_FORM_flag:
+ return "DW_FORM_flag";
+ case DW_FORM_sdata:
+ return "DW_FORM_sdata";
+ case DW_FORM_strp:
+ return "DW_FORM_strp";
+ case DW_FORM_udata:
+ return "DW_FORM_udata";
+ case DW_FORM_ref_addr:
+ return "DW_FORM_ref_addr";
+ case DW_FORM_ref1:
+ return "DW_FORM_ref1";
+ case DW_FORM_ref2:
+ return "DW_FORM_ref2";
+ case DW_FORM_ref4:
+ return "DW_FORM_ref4";
+ case DW_FORM_ref8:
+ return "DW_FORM_ref8";
+ case DW_FORM_ref_udata:
+ return "DW_FORM_ref_udata";
+ case DW_FORM_indirect:
+ return "DW_FORM_indirect";
+ default:
+ return "DW_FORM_<unknown>";
+ }
+}
+
+/* Determine the "ultimate origin" of a decl. The decl may be an inlined
+ instance of an inlined instance of a decl which is local to an inline
+ function, so we have to trace all of the way back through the origin chain
+ to find out what sort of node actually served as the original seed for the
+ given block. */
+
+static tree
+decl_ultimate_origin (tree decl)
+{
+ if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
+ return NULL_TREE;
+
+ /* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
+ nodes in the function to point to themselves; ignore that if
+ we're trying to output the abstract instance of this function. */
+ if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
+ return NULL_TREE;
+
+ /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
+ most distant ancestor, this should never happen. */
+ gcc_assert (!DECL_FROM_INLINE (DECL_ORIGIN (decl)));
+
+ return DECL_ABSTRACT_ORIGIN (decl);
+}
+
+/* Determine the "ultimate origin" of a block. The block may be an inlined
+ instance of an inlined instance of a block which is local to an inline
+ function, so we have to trace all of the way back through the origin chain
+ to find out what sort of node actually served as the original seed for the
+ given block. */
+
+static tree
+block_ultimate_origin (tree block)
+{
+ tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+
+ /* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
+ nodes in the function to point to themselves; ignore that if
+ we're trying to output the abstract instance of this function. */
+ if (BLOCK_ABSTRACT (block) && immediate_origin == block)
+ return NULL_TREE;
+
+ if (immediate_origin == NULL_TREE)
+ return NULL_TREE;
+ else
+ {
+ tree ret_val;
+ tree lookahead = immediate_origin;
+
+ do
+ {
+ ret_val = lookahead;
+ lookahead = (TREE_CODE (ret_val) == BLOCK
+ ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
+ }
+ while (lookahead != NULL && lookahead != ret_val);
+
+ /* The block's abstract origin chain may not be the *ultimate* origin of
+ the block. It could lead to a DECL that has an abstract origin set.
+ If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
+ will give us if it has one). Note that DECL's abstract origins are
+ supposed to be the most distant ancestor (or so decl_ultimate_origin
+ claims), so we don't need to loop following the DECL origins. */
+ if (DECL_P (ret_val))
+ return DECL_ORIGIN (ret_val);
+
+ return ret_val;
+ }
+}
+
+/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
+ of a virtual function may refer to a base class, so we check the 'this'
+ parameter. */
+
+static tree
+decl_class_context (tree decl)
+{
+ tree context = NULL_TREE;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
+ context = DECL_CONTEXT (decl);
+ else
+ context = TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+
+ if (context && !TYPE_P (context))
+ context = NULL_TREE;
+
+ return context;
+}
+
+/* Add an attribute/value pair to a DIE. */
+
+static inline void
+add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
+{
+ /* Maybe this should be an assert? */
+ if (die == NULL)
+ return;
+
+ if (die->die_attr == NULL)
+ die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
+ VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
+}
+
+static inline enum dw_val_class
+AT_class (dw_attr_ref a)
+{
+ return a->dw_attr_val.val_class;
+}
+
+/* Add a flag value attribute to a DIE. */
+
+static inline void
+add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_flag;
+ attr.dw_attr_val.v.val_flag = flag;
+ add_dwarf_attr (die, &attr);
+}
+
+static inline unsigned
+AT_flag (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_flag);
+ return a->dw_attr_val.v.val_flag;
+}
+
+/* Add a signed integer attribute value to a DIE. */
+
+static inline void
+add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_const;
+ attr.dw_attr_val.v.val_int = int_val;
+ add_dwarf_attr (die, &attr);
+}
+
+static inline HOST_WIDE_INT
+AT_int (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_const);
+ return a->dw_attr_val.v.val_int;
+}
+
+/* Add an unsigned integer attribute value to a DIE. */
+
+static inline void
+add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned HOST_WIDE_INT unsigned_val)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
+ attr.dw_attr_val.v.val_unsigned = unsigned_val;
+ add_dwarf_attr (die, &attr);
+}
+
+static inline unsigned HOST_WIDE_INT
+AT_unsigned (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
+ return a->dw_attr_val.v.val_unsigned;
+}
+
+/* Add an unsigned double integer attribute value to a DIE. */
+
+static inline void
+add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
+ long unsigned int val_hi, long unsigned int val_low)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_long_long;
+ attr.dw_attr_val.v.val_long_long.hi = val_hi;
+ attr.dw_attr_val.v.val_long_long.low = val_low;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add a floating point attribute value to a DIE and return it. */
+
+static inline void
+add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned int length, unsigned int elt_size, unsigned char *array)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_vec;
+ attr.dw_attr_val.v.val_vec.length = length;
+ attr.dw_attr_val.v.val_vec.elt_size = elt_size;
+ attr.dw_attr_val.v.val_vec.array = array;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Hash and equality functions for debug_str_hash. */
+
+static hashval_t
+debug_str_do_hash (const void *x)
+{
+ return htab_hash_string (((const struct indirect_string_node *)x)->str);
+}
+
+static int
+debug_str_eq (const void *x1, const void *x2)
+{
+ return strcmp ((((const struct indirect_string_node *)x1)->str),
+ (const char *)x2) == 0;
+}
+
+/* Add a string attribute value to a DIE. */
+
+static inline void
+add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
+{
+ dw_attr_node attr;
+ struct indirect_string_node *node;
+ void **slot;
+
+ if (! debug_str_hash)
+ debug_str_hash = htab_create_ggc (10, debug_str_do_hash,
+ debug_str_eq, NULL);
+
+ slot = htab_find_slot_with_hash (debug_str_hash, str,
+ htab_hash_string (str), INSERT);
+ if (*slot == NULL)
+ *slot = ggc_alloc_cleared (sizeof (struct indirect_string_node));
+ node = (struct indirect_string_node *) *slot;
+ node->str = ggc_strdup (str);
+ node->refcount++;
+
+ /* APPLE LOCAL begin radar 6275985 debug inlined section */
+#ifdef DEBUG_INLINED_SECTION
+ /* Force the names of functions (which may be inlined) to be in the
+ debug string section (i.e. string pointers). */
+ if (die
+ && die->die_tag == DW_TAG_subprogram
+ && ((attr_kind == DW_AT_name)
+ || (attr_kind == DW_AT_MIPS_linkage_name)))
+ node->is_fn_name = true;
+#endif
+ /* APPLE LOCAL end radar 6275985 debug inlined section */
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_str;
+ attr.dw_attr_val.v.val_str = node;
+ add_dwarf_attr (die, &attr);
+}
+
+static inline const char *
+AT_string (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_str);
+ return a->dw_attr_val.v.val_str->str;
+}
+
+/* Find out whether a string should be output inline in DIE
+ or out-of-line in .debug_str section. */
+
+static int
+AT_string_form (dw_attr_ref a)
+{
+ struct indirect_string_node *node;
+ unsigned int len;
+ char label[32];
+
+ gcc_assert (a && AT_class (a) == dw_val_class_str);
+
+ node = a->dw_attr_val.v.val_str;
+ if (node->form)
+ return node->form;
+
+ len = strlen (node->str) + 1;
+
+ /* APPLE LOCAL begin radar 6275985 debug inlined section */
+ /* Ths sentence below is false. If the string is a function name we
+ always want it to go into the debug_str section. */
+ /* If the string is shorter or equal to the size of the reference, it is
+ always better to put it inline. */
+ if ((len <= DWARF_OFFSET_SIZE || node->refcount == 0)
+ && !node->is_fn_name)
+ return node->form = DW_FORM_string;
+
+ /* If we cannot expect the linker to merge strings in .debug_str
+ section, only put it into .debug_str if it is worth even in this
+ single module. */
+ if ((debug_str_section->common.flags & SECTION_MERGE) == 0
+ && (len - DWARF_OFFSET_SIZE) * node->refcount <= len
+ && !node->is_fn_name)
+ return node->form = DW_FORM_string;
+ /* APPLE LOCAL end radar 6275985 debug inlined section */
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
+ node->label = xstrdup (label);
+
+ return node->form = DW_FORM_strp;
+}
+
+/* Add a DIE reference attribute value to a DIE. */
+
+static inline void
+add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_die_ref;
+ attr.dw_attr_val.v.val_die_ref.die = targ_die;
+ attr.dw_attr_val.v.val_die_ref.external = 0;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add an AT_specification attribute to a DIE, and also make the back
+ pointer from the specification to the definition. */
+
+static inline void
+add_AT_specification (dw_die_ref die, dw_die_ref targ_die)
+{
+ add_AT_die_ref (die, DW_AT_specification, targ_die);
+ gcc_assert (!targ_die->die_definition);
+ targ_die->die_definition = die;
+}
+
+static inline dw_die_ref
+AT_ref (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
+ return a->dw_attr_val.v.val_die_ref.die;
+}
+
+static inline int
+AT_ref_external (dw_attr_ref a)
+{
+ if (a && AT_class (a) == dw_val_class_die_ref)
+ return a->dw_attr_val.v.val_die_ref.external;
+
+ return 0;
+}
+
+static inline void
+set_AT_ref_external (dw_attr_ref a, int i)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_die_ref);
+ a->dw_attr_val.v.val_die_ref.external = i;
+}
+
+/* Add an FDE reference attribute value to a DIE. */
+
+static inline void
+add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_fde_ref;
+ attr.dw_attr_val.v.val_fde_index = targ_fde;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add a location description attribute value to a DIE. */
+
+static inline void
+add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loc;
+ attr.dw_attr_val.v.val_loc = loc;
+ add_dwarf_attr (die, &attr);
+}
+
+static inline dw_loc_descr_ref
+AT_loc (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_loc);
+ return a->dw_attr_val.v.val_loc;
+}
+
+static inline void
+add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loc_list;
+ attr.dw_attr_val.v.val_loc_list = loc_list;
+ add_dwarf_attr (die, &attr);
+ have_location_lists = true;
+}
+
+static inline dw_loc_list_ref
+AT_loc_list (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
+ return a->dw_attr_val.v.val_loc_list;
+}
+
+/* Add an address constant attribute value to a DIE. */
+
+static inline void
+add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_addr;
+ attr.dw_attr_val.v.val_addr = addr;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Get the RTX from to an address DIE attribute. */
+
+static inline rtx
+AT_addr (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_addr);
+ return a->dw_attr_val.v.val_addr;
+}
+
+/* Add a file attribute value to a DIE. */
+
+static inline void
+add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
+ struct dwarf_file_data *fd)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_file;
+ attr.dw_attr_val.v.val_file = fd;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Get the dwarf_file_data from a file DIE attribute. */
+
+static inline struct dwarf_file_data *
+AT_file (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_file);
+ return a->dw_attr_val.v.val_file;
+}
+
+/* Add a label identifier attribute value to a DIE. */
+
+static inline void
+add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add a section offset attribute value to a DIE, an offset into the
+ debug_line section. */
+
+static inline void
+add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *label)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_lineptr;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add a section offset attribute value to a DIE, an offset into the
+ debug_macinfo section. */
+
+static inline void
+add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *label)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_macptr;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add an offset attribute value to a DIE. */
+
+static inline void
+add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned HOST_WIDE_INT offset)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_offset;
+ attr.dw_attr_val.v.val_offset = offset;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add an range_list attribute value to a DIE. */
+
+static void
+add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
+ long unsigned int offset)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_range_list;
+ attr.dw_attr_val.v.val_offset = offset;
+ add_dwarf_attr (die, &attr);
+}
+
+static inline const char *
+AT_lbl (dw_attr_ref a)
+{
+ gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
+ || AT_class (a) == dw_val_class_lineptr
+ || AT_class (a) == dw_val_class_macptr));
+ return a->dw_attr_val.v.val_lbl_id;
+}
+
+/* APPLE LOCAL begin radar 6275985 debug inlined section */
+
+/* Get the attribute of type attr_kind, if the die has it.
+ This differs from get_AT in that it does NOT search any
+ abstract origin or specification dies; it ONLY looks directly
+ at the die that was passed in. */
+
+static dw_attr_ref
+has_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a;
+ unsigned ix;
+
+ if (! die)
+ return NULL;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ return a;
+
+ return NULL;
+}
+/* APPLE LOCAL end radar 6275985 debug inlined section */
+/* Get the attribute of type attr_kind. */
+
+static dw_attr_ref
+get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a;
+ unsigned ix;
+ dw_die_ref spec = NULL;
+
+ if (! die)
+ return NULL;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ return a;
+ else if (a->dw_attr == DW_AT_specification
+ || a->dw_attr == DW_AT_abstract_origin)
+ spec = AT_ref (a);
+
+ if (spec)
+ return get_AT (spec, attr_kind);
+
+ return NULL;
+}
+
+/* Return the "low pc" attribute value, typically associated with a subprogram
+ DIE. Return null if the "low pc" attribute is either not present, or if it
+ cannot be represented as an assembler label identifier. */
+
+static inline const char *
+get_AT_low_pc (dw_die_ref die)
+{
+ dw_attr_ref a = get_AT (die, DW_AT_low_pc);
+
+ return a ? AT_lbl (a) : NULL;
+}
+
+/* Return the "high pc" attribute value, typically associated with a subprogram
+ DIE. Return null if the "high pc" attribute is either not present, or if it
+ cannot be represented as an assembler label identifier. */
+
+static inline const char *
+get_AT_hi_pc (dw_die_ref die)
+{
+ dw_attr_ref a = get_AT (die, DW_AT_high_pc);
+
+ return a ? AT_lbl (a) : NULL;
+}
+
+/* Return the value of the string attribute designated by ATTR_KIND, or
+ NULL if it is not present. */
+
+static inline const char *
+get_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a = get_AT (die, attr_kind);
+
+ return a ? AT_string (a) : NULL;
+}
+
+/* Return the value of the flag attribute designated by ATTR_KIND, or -1
+ if it is not present. */
+
+static inline int
+get_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a = get_AT (die, attr_kind);
+
+ return a ? AT_flag (a) : 0;
+}
+
+/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
+ if it is not present. */
+
+static inline unsigned
+get_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a = get_AT (die, attr_kind);
+
+ return a ? AT_unsigned (a) : 0;
+}
+
+static inline dw_die_ref
+get_AT_ref (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a = get_AT (die, attr_kind);
+
+ return a ? AT_ref (a) : NULL;
+}
+
+static inline struct dwarf_file_data *
+get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a = get_AT (die, attr_kind);
+
+ return a ? AT_file (a) : NULL;
+}
+
+/* Return TRUE if the language is C or C++. */
+
+static inline bool
+is_c_family (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return (lang == DW_LANG_C || lang == DW_LANG_C89 || lang == DW_LANG_ObjC
+ || lang == DW_LANG_C99
+ || lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus);
+}
+
+/* Return TRUE if the language is C++. */
+
+static inline bool
+is_cxx (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
+}
+
+/* APPLE LOCAL begin radar 6113240 */
+/* Return TRUE if the language is ObjC. */
+
+static inline bool
+is_objc (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return lang == DW_LANG_ObjC;
+}
+
+/* Return TRUE if the language is ObjC++. */
+
+static inline bool
+is_objcxx (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return lang == DW_LANG_ObjC_plus_plus;
+}
+
+/* APPLE LOCAL end radar 6113240 */
+/* Return TRUE if the language is Fortran. */
+
+static inline bool
+is_fortran (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return (lang == DW_LANG_Fortran77
+ || lang == DW_LANG_Fortran90
+ || lang == DW_LANG_Fortran95);
+}
+
+/* Return TRUE if the language is Java. */
+
+static inline bool
+is_java (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return lang == DW_LANG_Java;
+}
+
+/* Return TRUE if the language is Ada. */
+
+static inline bool
+is_ada (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
+}
+
+/* Remove the specified attribute if present. */
+
+static void
+remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a;
+ unsigned ix;
+
+ if (! die)
+ return;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ {
+ if (AT_class (a) == dw_val_class_str)
+ if (a->dw_attr_val.v.val_str->refcount)
+ a->dw_attr_val.v.val_str->refcount--;
+
+ /* VEC_ordered_remove should help reduce the number of abbrevs
+ that are needed. */
+ VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
+ return;
+ }
+}
+
+/* Remove CHILD from its parent. PREV must have the property that
+ PREV->DIE_SIB == CHILD. Does not alter CHILD. */
+
+static void
+remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
+{
+ gcc_assert (child->die_parent == prev->die_parent);
+ gcc_assert (prev->die_sib == child);
+ if (prev == child)
+ {
+ gcc_assert (child->die_parent->die_child == child);
+ prev = NULL;
+ }
+ else
+ prev->die_sib = child->die_sib;
+ if (child->die_parent->die_child == child)
+ child->die_parent->die_child = prev;
+}
+
+/* Remove child DIE whose die_tag is TAG. Do nothing if no child
+ matches TAG. */
+
+static void
+remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
+{
+ dw_die_ref c;
+
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == tag)
+ {
+ remove_child_with_prev (c, prev);
+ /* Might have removed every child. */
+ if (c == c->die_sib)
+ return;
+ c = c->die_sib;
+ }
+ } while (c != die->die_child);
+}
+
+/* Add a CHILD_DIE as the last child of DIE. */
+
+static void
+add_child_die (dw_die_ref die, dw_die_ref child_die)
+{
+ /* FIXME this should probably be an assert. */
+ if (! die || ! child_die)
+ return;
+ gcc_assert (die != child_die);
+
+ child_die->die_parent = die;
+ if (die->die_child)
+ {
+ child_die->die_sib = die->die_child->die_sib;
+ die->die_child->die_sib = child_die;
+ }
+ else
+ child_die->die_sib = child_die;
+ die->die_child = child_die;
+}
+
+/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
+ is the specification, to the end of PARENT's list of children.
+ This is done by removing and re-adding it. */
+
+static void
+splice_child_die (dw_die_ref parent, dw_die_ref child)
+{
+ dw_die_ref p;
+
+ /* We want the declaration DIE from inside the class, not the
+ specification DIE at toplevel. */
+ if (child->die_parent != parent)
+ {
+ dw_die_ref tmp = get_AT_ref (child, DW_AT_specification);
+
+ if (tmp)
+ child = tmp;
+ }
+
+ gcc_assert (child->die_parent == parent
+ || (child->die_parent
+ == get_AT_ref (parent, DW_AT_specification)));
+
+ for (p = child->die_parent->die_child; ; p = p->die_sib)
+ if (p->die_sib == child)
+ {
+ remove_child_with_prev (child, p);
+ break;
+ }
+
+ add_child_die (parent, child);
+}
+
+/* Return a pointer to a newly created DIE node. */
+
+static inline dw_die_ref
+new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
+{
+ dw_die_ref die = ggc_alloc_cleared (sizeof (die_node));
+
+ die->die_tag = tag_value;
+
+ if (parent_die != NULL)
+ add_child_die (parent_die, die);
+ else
+ {
+ limbo_die_node *limbo_node;
+
+ limbo_node = ggc_alloc_cleared (sizeof (limbo_die_node));
+ limbo_node->die = die;
+ limbo_node->created_for = t;
+ limbo_node->next = limbo_die_list;
+ limbo_die_list = limbo_node;
+ }
+
+ return die;
+}
+
+/* Return the DIE associated with the given type specifier. */
+
+static inline dw_die_ref
+lookup_type_die (tree type)
+{
+ return TYPE_SYMTAB_DIE (type);
+}
+
+/* Equate a DIE to a given type specifier. */
+
+static inline void
+equate_type_number_to_die (tree type, dw_die_ref type_die)
+{
+ TYPE_SYMTAB_DIE (type) = type_die;
+}
+
+/* Returns a hash value for X (which really is a die_struct). */
+
+static hashval_t
+decl_die_table_hash (const void *x)
+{
+ return (hashval_t) ((const dw_die_ref) x)->decl_id;
+}
+
+/* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y. */
+
+static int
+decl_die_table_eq (const void *x, const void *y)
+{
+ return (((const dw_die_ref) x)->decl_id == DECL_UID ((const tree) y));
+}
+
+/* Return the DIE associated with a given declaration. */
+
+static inline dw_die_ref
+lookup_decl_die (tree decl)
+{
+ return htab_find_with_hash (decl_die_table, decl, DECL_UID (decl));
+}
+
+/* Returns a hash value for X (which really is a var_loc_list). */
+
+static hashval_t
+decl_loc_table_hash (const void *x)
+{
+ return (hashval_t) ((const var_loc_list *) x)->decl_id;
+}
+
+/* Return nonzero if decl_id of var_loc_list X is the same as
+ UID of decl *Y. */
+
+static int
+decl_loc_table_eq (const void *x, const void *y)
+{
+ return (((const var_loc_list *) x)->decl_id == DECL_UID ((const tree) y));
+}
+
+/* Return the var_loc list associated with a given declaration. */
+
+static inline var_loc_list *
+lookup_decl_loc (tree decl)
+{
+ return htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
+}
+
+/* Equate a DIE to a particular declaration. */
+
+static void
+equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
+{
+ unsigned int decl_id = DECL_UID (decl);
+ void **slot;
+
+ slot = htab_find_slot_with_hash (decl_die_table, decl, decl_id, INSERT);
+ *slot = decl_die;
+ decl_die->decl_id = decl_id;
+}
+
+/* Add a variable location node to the linked list for DECL. */
+
+static void
+add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
+{
+ unsigned int decl_id = DECL_UID (decl);
+ var_loc_list *temp;
+ void **slot;
+
+ slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
+ if (*slot == NULL)
+ {
+ temp = ggc_alloc_cleared (sizeof (var_loc_list));
+ temp->decl_id = decl_id;
+ *slot = temp;
+ }
+ else
+ temp = *slot;
+
+ if (temp->last)
+ {
+ /* If the current location is the same as the end of the list,
+ we have nothing to do. */
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
+ NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
+ || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
+ != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note))
+ && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
+ == STATUS_UNINITIALIZED)
+ || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)
+ == STATUS_UNINITIALIZED))))
+ /* APPLE LOCAL end track initialization status 4964532 */
+ {
+ /* Add LOC to the end of list and update LAST. */
+ temp->last->next = loc;
+ temp->last = loc;
+ }
+ }
+ /* Do not add empty location to the beginning of the list. */
+ else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
+ {
+ temp->first = loc;
+ temp->last = loc;
+ }
+}
+
+/* Keep track of the number of spaces used to indent the
+ output of the debugging routines that print the structure of
+ the DIE internal representation. */
+static int print_indent;
+
+/* Indent the line the number of spaces given by print_indent. */
+
+static inline void
+print_spaces (FILE *outfile)
+{
+ fprintf (outfile, "%*s", print_indent, "");
+}
+
+/* Print the information associated with a given DIE, and its children.
+ This routine is a debugging aid only. */
+
+static void
+print_die (dw_die_ref die, FILE *outfile)
+{
+ dw_attr_ref a;
+ dw_die_ref c;
+ unsigned ix;
+
+ print_spaces (outfile);
+ fprintf (outfile, "DIE %4lu: %s\n",
+ die->die_offset, dwarf_tag_name (die->die_tag));
+ print_spaces (outfile);
+ fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
+ fprintf (outfile, " offset: %lu\n", die->die_offset);
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ {
+ print_spaces (outfile);
+ fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
+
+ switch (AT_class (a))
+ {
+ case dw_val_class_addr:
+ fprintf (outfile, "address");
+ break;
+ case dw_val_class_offset:
+ fprintf (outfile, "offset");
+ break;
+ case dw_val_class_loc:
+ fprintf (outfile, "location descriptor");
+ break;
+ case dw_val_class_loc_list:
+ fprintf (outfile, "location list -> label:%s",
+ AT_loc_list (a)->ll_symbol);
+ break;
+ case dw_val_class_range_list:
+ fprintf (outfile, "range list");
+ break;
+ case dw_val_class_const:
+ fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
+ break;
+ case dw_val_class_unsigned_const:
+ fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
+ break;
+ case dw_val_class_long_long:
+ fprintf (outfile, "constant (%lu,%lu)",
+ a->dw_attr_val.v.val_long_long.hi,
+ a->dw_attr_val.v.val_long_long.low);
+ break;
+ case dw_val_class_vec:
+ fprintf (outfile, "floating-point or vector constant");
+ break;
+ case dw_val_class_flag:
+ fprintf (outfile, "%u", AT_flag (a));
+ break;
+ case dw_val_class_die_ref:
+ if (AT_ref (a) != NULL)
+ {
+ if (AT_ref (a)->die_symbol)
+ fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol);
+ else
+ fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset);
+ }
+ else
+ fprintf (outfile, "die -> <null>");
+ break;
+ case dw_val_class_lbl_id:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ fprintf (outfile, "label: %s", AT_lbl (a));
+ break;
+ case dw_val_class_str:
+ if (AT_string (a) != NULL)
+ fprintf (outfile, "\"%s\"", AT_string (a));
+ else
+ fprintf (outfile, "<null>");
+ break;
+ case dw_val_class_file:
+ fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
+ AT_file (a)->emitted_number);
+ break;
+ default:
+ break;
+ }
+
+ fprintf (outfile, "\n");
+ }
+
+ if (die->die_child != NULL)
+ {
+ print_indent += 4;
+ FOR_EACH_CHILD (die, c, print_die (c, outfile));
+ print_indent -= 4;
+ }
+ if (print_indent == 0)
+ fprintf (outfile, "\n");
+}
+
+/* Print the contents of the source code line number correspondence table.
+ This routine is a debugging aid only. */
+
+static void
+print_dwarf_line_table (FILE *outfile)
+{
+ unsigned i;
+ dw_line_info_ref line_info;
+
+ fprintf (outfile, "\n\nDWARF source line information\n");
+ for (i = 1; i < line_info_table_in_use; i++)
+ {
+ line_info = &line_info_table[i];
+ fprintf (outfile, "%5d: %4ld %6ld\n", i,
+ line_info->dw_file_num,
+ line_info->dw_line_num);
+ }
+
+ fprintf (outfile, "\n\n");
+}
+
+/* Print the information collected for a given DIE. */
+
+void
+debug_dwarf_die (dw_die_ref die)
+{
+ print_die (die, stderr);
+}
+
+/* Print all DWARF information collected for the compilation unit.
+ This routine is a debugging aid only. */
+
+void
+debug_dwarf (void)
+{
+ print_indent = 0;
+ print_die (comp_unit_die, stderr);
+ if (! DWARF2_ASM_LINE_DEBUG_INFO)
+ print_dwarf_line_table (stderr);
+}
+
+/* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU
+ for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL
+ DIE that marks the start of the DIEs for this include file. */
+
+static dw_die_ref
+push_new_compile_unit (dw_die_ref old_unit, dw_die_ref bincl_die)
+{
+ const char *filename = get_AT_string (bincl_die, DW_AT_name);
+ dw_die_ref new_unit = gen_compile_unit_die (filename);
+
+ new_unit->die_sib = old_unit;
+ return new_unit;
+}
+
+/* Close an include-file CU and reopen the enclosing one. */
+
+static dw_die_ref
+pop_compile_unit (dw_die_ref old_unit)
+{
+ dw_die_ref new_unit = old_unit->die_sib;
+
+ old_unit->die_sib = NULL;
+ return new_unit;
+}
+
+#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
+#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx)
+
+/* Calculate the checksum of a location expression. */
+
+static inline void
+loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx)
+{
+ CHECKSUM (loc->dw_loc_opc);
+ CHECKSUM (loc->dw_loc_oprnd1);
+ CHECKSUM (loc->dw_loc_oprnd2);
+}
+
+/* Calculate the checksum of an attribute. */
+
+static void
+attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
+{
+ dw_loc_descr_ref loc;
+ rtx r;
+
+ CHECKSUM (at->dw_attr);
+
+ /* We don't care that this was compiled with a different compiler
+ snapshot; if the output is the same, that's what matters. */
+ if (at->dw_attr == DW_AT_producer)
+ return;
+
+ switch (AT_class (at))
+ {
+ case dw_val_class_const:
+ CHECKSUM (at->dw_attr_val.v.val_int);
+ break;
+ case dw_val_class_unsigned_const:
+ CHECKSUM (at->dw_attr_val.v.val_unsigned);
+ break;
+ case dw_val_class_long_long:
+ CHECKSUM (at->dw_attr_val.v.val_long_long);
+ break;
+ case dw_val_class_vec:
+ CHECKSUM (at->dw_attr_val.v.val_vec);
+ break;
+ case dw_val_class_flag:
+ CHECKSUM (at->dw_attr_val.v.val_flag);
+ break;
+ case dw_val_class_str:
+ CHECKSUM_STRING (AT_string (at));
+ break;
+
+ case dw_val_class_addr:
+ r = AT_addr (at);
+ gcc_assert (GET_CODE (r) == SYMBOL_REF);
+ CHECKSUM_STRING (XSTR (r, 0));
+ break;
+
+ case dw_val_class_offset:
+ CHECKSUM (at->dw_attr_val.v.val_offset);
+ break;
+
+ case dw_val_class_loc:
+ for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+ loc_checksum (loc, ctx);
+ break;
+
+ case dw_val_class_die_ref:
+ die_checksum (AT_ref (at), ctx, mark);
+ break;
+
+ case dw_val_class_fde_ref:
+ case dw_val_class_lbl_id:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ break;
+
+ case dw_val_class_file:
+ CHECKSUM_STRING (AT_file (at)->filename);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Calculate the checksum of a DIE. */
+
+static void
+die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
+{
+ dw_die_ref c;
+ dw_attr_ref a;
+ unsigned ix;
+
+ /* To avoid infinite recursion. */
+ if (die->die_mark)
+ {
+ CHECKSUM (die->die_mark);
+ return;
+ }
+ die->die_mark = ++(*mark);
+
+ CHECKSUM (die->die_tag);
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ attr_checksum (a, ctx, mark);
+
+ FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
+}
+
+#undef CHECKSUM
+#undef CHECKSUM_STRING
+
+/* Do the location expressions look same? */
+static inline int
+same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
+{
+ return loc1->dw_loc_opc == loc2->dw_loc_opc
+ && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
+ && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+}
+
+/* Do the values look the same? */
+static int
+same_dw_val_p (dw_val_node *v1, dw_val_node *v2, int *mark)
+{
+ dw_loc_descr_ref loc1, loc2;
+ rtx r1, r2;
+
+ if (v1->val_class != v2->val_class)
+ return 0;
+
+ switch (v1->val_class)
+ {
+ case dw_val_class_const:
+ return v1->v.val_int == v2->v.val_int;
+ case dw_val_class_unsigned_const:
+ return v1->v.val_unsigned == v2->v.val_unsigned;
+ case dw_val_class_long_long:
+ return v1->v.val_long_long.hi == v2->v.val_long_long.hi
+ && v1->v.val_long_long.low == v2->v.val_long_long.low;
+ case dw_val_class_vec:
+ if (v1->v.val_vec.length != v2->v.val_vec.length
+ || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
+ return 0;
+ if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
+ v1->v.val_vec.length * v1->v.val_vec.elt_size))
+ return 0;
+ return 1;
+ case dw_val_class_flag:
+ return v1->v.val_flag == v2->v.val_flag;
+ case dw_val_class_str:
+ return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
+
+ case dw_val_class_addr:
+ r1 = v1->v.val_addr;
+ r2 = v2->v.val_addr;
+ if (GET_CODE (r1) != GET_CODE (r2))
+ return 0;
+ gcc_assert (GET_CODE (r1) == SYMBOL_REF);
+ return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
+
+ case dw_val_class_offset:
+ return v1->v.val_offset == v2->v.val_offset;
+
+ case dw_val_class_loc:
+ for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
+ loc1 && loc2;
+ loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
+ if (!same_loc_p (loc1, loc2, mark))
+ return 0;
+ return !loc1 && !loc2;
+
+ case dw_val_class_die_ref:
+ return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+
+ case dw_val_class_fde_ref:
+ case dw_val_class_lbl_id:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ return 1;
+
+ case dw_val_class_file:
+ return v1->v.val_file == v2->v.val_file;
+
+ default:
+ return 1;
+ }
+}
+
+/* Do the attributes look the same? */
+
+static int
+same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
+{
+ if (at1->dw_attr != at2->dw_attr)
+ return 0;
+
+ /* We don't care that this was compiled with a different compiler
+ snapshot; if the output is the same, that's what matters. */
+ if (at1->dw_attr == DW_AT_producer)
+ return 1;
+
+ return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
+}
+
+/* Do the dies look the same? */
+
+static int
+same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+{
+ dw_die_ref c1, c2;
+ dw_attr_ref a1;
+ unsigned ix;
+
+ /* To avoid infinite recursion. */
+ if (die1->die_mark)
+ return die1->die_mark == die2->die_mark;
+ die1->die_mark = die2->die_mark = ++(*mark);
+
+ if (die1->die_tag != die2->die_tag)
+ return 0;
+
+ if (VEC_length (dw_attr_node, die1->die_attr)
+ != VEC_length (dw_attr_node, die2->die_attr))
+ return 0;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
+ if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
+ return 0;
+
+ c1 = die1->die_child;
+ c2 = die2->die_child;
+ if (! c1)
+ {
+ if (c2)
+ return 0;
+ }
+ else
+ for (;;)
+ {
+ if (!same_die_p (c1, c2, mark))
+ return 0;
+ c1 = c1->die_sib;
+ c2 = c2->die_sib;
+ if (c1 == die1->die_child)
+ {
+ if (c2 == die2->die_child)
+ break;
+ else
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Do the dies look the same? Wrapper around same_die_p. */
+
+static int
+same_die_p_wrap (dw_die_ref die1, dw_die_ref die2)
+{
+ int mark = 0;
+ int ret = same_die_p (die1, die2, &mark);
+
+ unmark_all_dies (die1);
+ unmark_all_dies (die2);
+
+ return ret;
+}
+
+/* The prefix to attach to symbols on DIEs in the current comdat debug
+ info section. */
+static char *comdat_symbol_id;
+
+/* The index of the current symbol within the current comdat CU. */
+static unsigned int comdat_symbol_number;
+
+/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
+ children, and set comdat_symbol_id accordingly. */
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+ const char *die_name = get_AT_string (unit_die, DW_AT_name);
+ const char *base = die_name ? lbasename (die_name) : "anonymous";
+ char *name = alloca (strlen (base) + 64);
+ char *p;
+ int i, mark;
+ unsigned char checksum[16];
+ struct md5_ctx ctx;
+
+ /* Compute the checksum of the DIE, then append part of it as hex digits to
+ the name filename of the unit. */
+
+ md5_init_ctx (&ctx);
+ mark = 0;
+ die_checksum (unit_die, &ctx, &mark);
+ unmark_all_dies (unit_die);
+ md5_finish_ctx (&ctx, checksum);
+
+ sprintf (name, "%s.", base);
+ clean_symbol_name (name);
+
+ p = name + strlen (name);
+ for (i = 0; i < 4; i++)
+ {
+ sprintf (p, "%.2x", checksum[i]);
+ p += 2;
+ }
+
+ comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
+ comdat_symbol_number = 0;
+}
+
+/* Returns nonzero if DIE represents a type, in the sense of TYPE_P. */
+
+static int
+is_type_die (dw_die_ref die)
+{
+ switch (die->die_tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_union_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_set_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_base_type:
+ case DW_TAG_const_type:
+ case DW_TAG_file_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU.
+ Basically, we want to choose the bits that are likely to be shared between
+ compilations (types) and leave out the bits that are specific to individual
+ compilations (functions). */
+
+static int
+is_comdat_die (dw_die_ref c)
+{
+ /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as
+ we do for stabs. The advantage is a greater likelihood of sharing between
+ objects that don't include headers in the same order (and therefore would
+ put the base types in a different comdat). jason 8/28/00 */
+
+ if (c->die_tag == DW_TAG_base_type)
+ return 0;
+
+ if (c->die_tag == DW_TAG_pointer_type
+ || c->die_tag == DW_TAG_reference_type
+ || c->die_tag == DW_TAG_const_type
+ || c->die_tag == DW_TAG_volatile_type)
+ {
+ dw_die_ref t = get_AT_ref (c, DW_AT_type);
+
+ return t ? is_comdat_die (t) : 0;
+ }
+
+ return is_type_die (c);
+}
+
+/* Returns 1 iff C is the sort of DIE that might be referred to from another
+ compilation unit. */
+
+static int
+is_symbol_die (dw_die_ref c)
+{
+ return (is_type_die (c)
+ || (get_AT (c, DW_AT_declaration)
+ && !get_AT (c, DW_AT_specification))
+ || c->die_tag == DW_TAG_namespace);
+}
+
+static char *
+gen_internal_sym (const char *prefix)
+{
+ char buf[256];
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
+ return xstrdup (buf);
+}
+
+/* Assign symbols to all worthy DIEs under DIE. */
+
+static void
+assign_symbol_names (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ if (is_symbol_die (die))
+ {
+ if (comdat_symbol_id)
+ {
+ char *p = alloca (strlen (comdat_symbol_id) + 64);
+
+ sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
+ comdat_symbol_id, comdat_symbol_number++);
+ die->die_symbol = xstrdup (p);
+ }
+ else
+ die->die_symbol = gen_internal_sym ("LDIE");
+ }
+
+ FOR_EACH_CHILD (die, c, assign_symbol_names (c));
+}
+
+struct cu_hash_table_entry
+{
+ dw_die_ref cu;
+ unsigned min_comdat_num, max_comdat_num;
+ struct cu_hash_table_entry *next;
+};
+
+/* Routines to manipulate hash table of CUs. */
+static hashval_t
+htab_cu_hash (const void *of)
+{
+ const struct cu_hash_table_entry *entry = of;
+
+ return htab_hash_string (entry->cu->die_symbol);
+}
+
+static int
+htab_cu_eq (const void *of1, const void *of2)
+{
+ const struct cu_hash_table_entry *entry1 = of1;
+ const struct die_struct *entry2 = of2;
+
+ return !strcmp (entry1->cu->die_symbol, entry2->die_symbol);
+}
+
+static void
+htab_cu_del (void *what)
+{
+ struct cu_hash_table_entry *next, *entry = what;
+
+ while (entry)
+ {
+ next = entry->next;
+ free (entry);
+ entry = next;
+ }
+}
+
+/* Check whether we have already seen this CU and set up SYM_NUM
+ accordingly. */
+static int
+check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num)
+{
+ struct cu_hash_table_entry dummy;
+ struct cu_hash_table_entry **slot, *entry, *last = &dummy;
+
+ dummy.max_comdat_num = 0;
+
+ slot = (struct cu_hash_table_entry **)
+ htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+ INSERT);
+ entry = *slot;
+
+ for (; entry; last = entry, entry = entry->next)
+ {
+ if (same_die_p_wrap (cu, entry->cu))
+ break;
+ }
+
+ if (entry)
+ {
+ *sym_num = entry->min_comdat_num;
+ return 1;
+ }
+
+ entry = XCNEW (struct cu_hash_table_entry);
+ entry->cu = cu;
+ entry->min_comdat_num = *sym_num = last->max_comdat_num;
+ entry->next = *slot;
+ *slot = entry;
+
+ return 0;
+}
+
+/* Record SYM_NUM to record of CU in HTABLE. */
+static void
+record_comdat_symbol_number (dw_die_ref cu, htab_t htable, unsigned int sym_num)
+{
+ struct cu_hash_table_entry **slot, *entry;
+
+ slot = (struct cu_hash_table_entry **)
+ htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+ NO_INSERT);
+ entry = *slot;
+
+ entry->max_comdat_num = sym_num;
+}
+
+/* Traverse the DIE (which is always comp_unit_die), and set up
+ additional compilation units for each of the include files we see
+ bracketed by BINCL/EINCL. */
+
+static void
+break_out_includes (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_die_ref unit = NULL;
+ limbo_die_node *node, **pnode;
+ htab_t cu_hash_table;
+
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
+ || (unit && is_comdat_die (c)))
+ {
+ dw_die_ref next = c->die_sib;
+
+ /* This DIE is for a secondary CU; remove it from the main one. */
+ remove_child_with_prev (c, prev);
+
+ if (c->die_tag == DW_TAG_GNU_BINCL)
+ unit = push_new_compile_unit (unit, c);
+ else if (c->die_tag == DW_TAG_GNU_EINCL)
+ unit = pop_compile_unit (unit);
+ else
+ add_child_die (unit, c);
+ c = next;
+ if (c == die->die_child)
+ break;
+ }
+ } while (c != die->die_child);
+
+#if 0
+ /* We can only use this in debugging, since the frontend doesn't check
+ to make sure that we leave every include file we enter. */
+ gcc_assert (!unit);
+#endif
+
+ assign_symbol_names (die);
+ cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del);
+ for (node = limbo_die_list, pnode = &limbo_die_list;
+ node;
+ node = node->next)
+ {
+ int is_dupl;
+
+ compute_section_prefix (node->die);
+ is_dupl = check_duplicate_cu (node->die, cu_hash_table,
+ &comdat_symbol_number);
+ assign_symbol_names (node->die);
+ if (is_dupl)
+ *pnode = node->next;
+ else
+ {
+ pnode = &node->next;
+ record_comdat_symbol_number (node->die, cu_hash_table,
+ comdat_symbol_number);
+ }
+ }
+ htab_delete (cu_hash_table);
+}
+
+/* APPLE LOCAL begin radar 5636185 */
+/* Search backwards through the die structures to see if the current
+ die, DIE is contained within a subprogram die or not. Return the
+ result.
+
+ This is used when making final determination whether or not to
+ write out DW_AT_MIPS_linkage_name (in add_sibling_attributes).
+ DW_AT_MIPS_linkage_name needs to be written out for global level
+ structs, classes and namespaces, and any nested structs, classes
+ or namespaces, but not for such things that are local to
+ functions. */
+
+static bool
+contained_in_subroutine (dw_die_ref die)
+{
+ dw_die_ref ancestor_die;
+ bool ret_val = false;
+
+ ancestor_die = die->die_parent;
+
+ while (ancestor_die
+ && ancestor_die->die_tag != DW_TAG_compile_unit
+ && ancestor_die->die_tag != DW_TAG_subprogram)
+ ancestor_die = ancestor_die->die_parent;
+
+ if (ancestor_die && ancestor_die->die_tag == DW_TAG_subprogram)
+ ret_val = true;
+
+ return ret_val;
+}
+/* APPLE LOCAL end radar 5636185 */
+
+/* Traverse the DIE and add a sibling attribute if it may have the
+ effect of speeding up access to siblings. To save some space,
+ avoid generating sibling attributes for DIE's without children. */
+
+static void
+add_sibling_attributes (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ /* APPLE LOCAL radar 6066486 - move code further down. */
+ /* APPLE LOCAL begin radar 5636185 */
+ /* As we are traversing the entire structure of dies, to add the
+ sibling attributes, also check each die to see if it has the
+ attribute DW_AT_MIPS_linkage_name. If it has the attribute,
+ verify that the attribute is supposed to be output for the die,
+ i.e. that the die is not local to an subroutine. If the current
+ die *is* local to a subroutine, then remove the
+ DW_AT_MIPS_linkage_name attribute.
+
+ This is done here, rather than at the time the
+ DW_AT_MIPS_linkage_name attribute is first added to the die,
+ because *here* we are guaranteed that all the dies have been
+ generated and the die structure is complete, whereas that is not
+ true at the time the attribute is first generated. */
+
+ if (get_AT (die, DW_AT_MIPS_linkage_name)
+ && contained_in_subroutine (die))
+ remove_AT (die, DW_AT_MIPS_linkage_name);
+ /* APPLE LOCAL end radar 5636185 */
+ /* APPLE LOCAL begin radar 6066486 - Code moved from above. */
+ /* Don't return until after removing the DW_AT_MIPS_linkage_name,
+ if appropriate. */
+ if (! die->die_child)
+ return;
+ /* APPLE LOCAL end radar 6066486 - Code moved from above. */
+
+ if (die->die_parent && die != die->die_parent->die_child)
+ add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
+
+ FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
+}
+
+/* Output all location lists for the DIE and its children. */
+
+static void
+output_location_lists (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_attr_ref a;
+ unsigned ix;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_loc_list)
+ output_loc_list (AT_loc_list (a));
+
+ FOR_EACH_CHILD (die, c, output_location_lists (c));
+}
+
+/* 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 each abbreviation entry. The children of each
+ die are visited recursively. */
+
+static void
+build_abbrev_table (dw_die_ref die)
+{
+ unsigned long abbrev_id;
+ unsigned int n_alloc;
+ dw_die_ref c;
+ dw_attr_ref a;
+ unsigned ix;
+
+ /* Scan the DIE references, and mark as external any that refer to
+ DIEs from other CUs (i.e. those which are not marked). */
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_die_ref
+ && AT_ref (a)->die_mark == 0)
+ {
+ gcc_assert (AT_ref (a)->die_symbol);
+
+ set_AT_ref_external (a, 1);
+ }
+
+ for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ {
+ dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+ dw_attr_ref die_a, abbrev_a;
+ unsigned ix;
+ bool ok = true;
+
+ if (abbrev->die_tag != die->die_tag)
+ continue;
+ if ((abbrev->die_child != NULL) != (die->die_child != NULL))
+ continue;
+
+ if (VEC_length (dw_attr_node, abbrev->die_attr)
+ != VEC_length (dw_attr_node, die->die_attr))
+ continue;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
+ {
+ abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
+ if ((abbrev_a->dw_attr != die_a->dw_attr)
+ || (value_format (abbrev_a) != value_format (die_a)))
+ {
+ ok = false;
+ break;
+ }
+ }
+ if (ok)
+ break;
+ }
+
+ if (abbrev_id >= abbrev_die_table_in_use)
+ {
+ if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
+ {
+ n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
+ abbrev_die_table = ggc_realloc (abbrev_die_table,
+ sizeof (dw_die_ref) * n_alloc);
+
+ memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
+ (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
+ abbrev_die_table_allocated = n_alloc;
+ }
+
+ ++abbrev_die_table_in_use;
+ abbrev_die_table[abbrev_id] = die;
+ }
+
+ die->die_abbrev = abbrev_id;
+ FOR_EACH_CHILD (die, c, build_abbrev_table (c));
+}
+
+/* Return the power-of-two number of bytes necessary to represent VALUE. */
+
+static int
+constant_size (long unsigned int value)
+{
+ int log;
+
+ if (value == 0)
+ log = 0;
+ else
+ log = floor_log2 (value);
+
+ log = log / 8;
+ log = 1 << (floor_log2 (log) + 1);
+
+ return log;
+}
+
+/* Return the size of a DIE as it is represented in the
+ .debug_info section. */
+
+static unsigned long
+size_of_die (dw_die_ref die)
+{
+ unsigned long size = 0;
+ dw_attr_ref a;
+ unsigned ix;
+
+ size += size_of_uleb128 (die->die_abbrev);
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ {
+ switch (AT_class (a))
+ {
+ case dw_val_class_addr:
+ size += DWARF2_ADDR_SIZE;
+ break;
+ case dw_val_class_offset:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_loc:
+ {
+ unsigned long lsize = size_of_locs (AT_loc (a));
+
+ /* Block length. */
+ size += constant_size (lsize);
+ size += lsize;
+ }
+ break;
+ case dw_val_class_loc_list:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_range_list:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_const:
+ size += size_of_sleb128 (AT_int (a));
+ break;
+ case dw_val_class_unsigned_const:
+ size += constant_size (AT_unsigned (a));
+ break;
+ case dw_val_class_long_long:
+ size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
+ break;
+ case dw_val_class_vec:
+ size += 1 + (a->dw_attr_val.v.val_vec.length
+ * a->dw_attr_val.v.val_vec.elt_size); /* block */
+ break;
+ case dw_val_class_flag:
+ size += 1;
+ break;
+ case dw_val_class_die_ref:
+ if (AT_ref_external (a))
+ size += DWARF2_ADDR_SIZE;
+ else
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_fde_ref:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_lbl_id:
+ size += DWARF2_ADDR_SIZE;
+ break;
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_str:
+ if (AT_string_form (a) == DW_FORM_strp)
+ size += DWARF_OFFSET_SIZE;
+ else
+ size += strlen (a->dw_attr_val.v.val_str->str) + 1;
+ break;
+ case dw_val_class_file:
+ size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ return size;
+}
+
+/* Size the debugging information associated with a given DIE. Visits the
+ DIE's children recursively. Updates the global variable next_die_offset, on
+ each time through. Uses the current value of next_die_offset to update the
+ die_offset field in each DIE. */
+
+static void
+calc_die_sizes (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ die->die_offset = next_die_offset;
+ next_die_offset += size_of_die (die);
+
+ FOR_EACH_CHILD (die, c, calc_die_sizes (c));
+
+ if (die->die_child != NULL)
+ /* Count the null byte used to terminate sibling lists. */
+ next_die_offset += 1;
+}
+
+/* Set the marks for a die and its children. We do this so
+ that we know whether or not a reference needs to use FORM_ref_addr; only
+ DIEs in the same CU will be marked. We used to clear out the offset
+ and use that as the flag, but ran into ordering problems. */
+
+static void
+mark_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ gcc_assert (!die->die_mark);
+
+ die->die_mark = 1;
+ FOR_EACH_CHILD (die, c, mark_dies (c));
+}
+
+/* Clear the marks for a die and its children. */
+
+static void
+unmark_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ gcc_assert (die->die_mark);
+
+ die->die_mark = 0;
+ FOR_EACH_CHILD (die, c, unmark_dies (c));
+}
+
+/* Clear the marks for a die, its children and referred dies. */
+
+static void
+unmark_all_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_attr_ref a;
+ unsigned ix;
+
+ if (!die->die_mark)
+ return;
+ die->die_mark = 0;
+
+ FOR_EACH_CHILD (die, c, unmark_all_dies (c));
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_die_ref)
+ unmark_all_dies (AT_ref (a));
+}
+
+/* APPLE LOCAL begin radar 6275985 debug inlined section */
+static unsigned long
+size_of_inlined (VEC (inlined_entry, gc) * inlined_dies)
+{
+ unsigned long size;
+ unsigned i;
+ /* APPLE LOCAL begin radar 6476836 */
+ unsigned j;
+ dw_die_ref *diep;
+ /* APPLE LOCAL end radar 6476836 */
+ unsigned num_entries;
+ inlined_ref iptr;
+
+ size = DWARF_INLINED_HEADER_SIZE;
+
+ for (i = 0; VEC_iterate (inlined_entry, inlined_dies, i, iptr); i++)
+ {
+ /* APPLE LOCAL begin radar 6476836 */
+ /* Don't count or output entries that were eliminated as part of
+ unused types. */
+ num_entries = 0;
+ for (j = 0; VEC_iterate (dw_die_ref, iptr->inlined_instances, j, diep);
+ j++)
+ if (! (*diep)->dead)
+ num_entries++;
+ /* APPLE LOCAL end radar 6476836 */
+ size += (2 * DWARF_OFFSET_SIZE) + (num_entries * DWARF2_ADDR_SIZE)
+ + (num_entries * DWARF_OFFSET_SIZE) + size_of_uleb128 (num_entries);
+ }
+
+ return size;
+}
+/* APPLE LOCAL end radar 6275985 debug inlined section */
+/* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+/* Return the size of the .debug_pubnames or .debug_pubtypes table
+ generated for the compilation unit. */
+
+static unsigned long
+size_of_pubnames (VEC (pubname_entry, gc) * names)
+{
+ unsigned long size;
+ unsigned i;
+ pubname_ref p;
+
+ size = DWARF_PUBNAMES_HEADER_SIZE;
+ for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
+ if (names != pubtype_table
+ || p->die->die_offset != 0
+ || !flag_eliminate_unused_debug_types)
+ size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
+/* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+ size += DWARF_OFFSET_SIZE;
+ return size;
+}
+
+/* Return the size of the information in the .debug_aranges section. */
+
+static unsigned long
+size_of_aranges (void)
+{
+ unsigned long size;
+
+ size = DWARF_ARANGES_HEADER_SIZE;
+
+ /* Count the address/length pair for this compilation unit. */
+ size += 2 * DWARF2_ADDR_SIZE;
+ size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use;
+
+ /* Count the two zero words used to terminated the address range table. */
+ size += 2 * DWARF2_ADDR_SIZE;
+ return size;
+}
+
+/* Select the encoding of an attribute value. */
+
+static enum dwarf_form
+value_format (dw_attr_ref a)
+{
+ switch (a->dw_attr_val.val_class)
+ {
+ case dw_val_class_addr:
+ return DW_FORM_addr;
+ case dw_val_class_range_list:
+ case dw_val_class_offset:
+ case dw_val_class_loc_list:
+ switch (DWARF_OFFSET_SIZE)
+ {
+ case 4:
+ return DW_FORM_data4;
+ case 8:
+ return DW_FORM_data8;
+ default:
+ gcc_unreachable ();
+ }
+ case dw_val_class_loc:
+ switch (constant_size (size_of_locs (AT_loc (a))))
+ {
+ case 1:
+ return DW_FORM_block1;
+ case 2:
+ return DW_FORM_block2;
+ default:
+ gcc_unreachable ();
+ }
+ case dw_val_class_const:
+ return DW_FORM_sdata;
+ case dw_val_class_unsigned_const:
+ switch (constant_size (AT_unsigned (a)))
+ {
+ case 1:
+ return DW_FORM_data1;
+ case 2:
+ return DW_FORM_data2;
+ case 4:
+ return DW_FORM_data4;
+ case 8:
+ return DW_FORM_data8;
+ default:
+ gcc_unreachable ();
+ }
+ case dw_val_class_long_long:
+ return DW_FORM_block1;
+ case dw_val_class_vec:
+ return DW_FORM_block1;
+ case dw_val_class_flag:
+ return DW_FORM_flag;
+ case dw_val_class_die_ref:
+ if (AT_ref_external (a))
+ return DW_FORM_ref_addr;
+ else
+ return DW_FORM_ref;
+ case dw_val_class_fde_ref:
+ return DW_FORM_data;
+ case dw_val_class_lbl_id:
+ return DW_FORM_addr;
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ return DW_FORM_data;
+ case dw_val_class_str:
+ return AT_string_form (a);
+ case dw_val_class_file:
+ switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
+ {
+ case 1:
+ return DW_FORM_data1;
+ case 2:
+ return DW_FORM_data2;
+ case 4:
+ return DW_FORM_data4;
+ default:
+ gcc_unreachable ();
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Output the encoding of an attribute value. */
+
+static void
+output_value_format (dw_attr_ref a)
+{
+ enum dwarf_form form = value_format (a);
+
+ dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
+}
+
+/* Output the .debug_abbrev section which defines the DIE abbreviation
+ table. */
+
+static void
+output_abbrev_section (void)
+{
+ unsigned long abbrev_id;
+
+ for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ {
+ dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+ unsigned ix;
+ dw_attr_ref a_attr;
+
+ dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
+ dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
+ dwarf_tag_name (abbrev->die_tag));
+
+ if (abbrev->die_child != NULL)
+ dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
+ else
+ dw2_asm_output_data (1, DW_children_no, "DW_children_no");
+
+ for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+ ix++)
+ {
+ dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
+ dwarf_attr_name (a_attr->dw_attr));
+ output_value_format (a_attr);
+ }
+
+ dw2_asm_output_data (1, 0, NULL);
+ dw2_asm_output_data (1, 0, NULL);
+ }
+
+ /* Terminate the table. */
+ dw2_asm_output_data (1, 0, NULL);
+}
+
+/* Output a symbol we can use to refer to this DIE from another CU. */
+
+static inline void
+output_die_symbol (dw_die_ref die)
+{
+ char *sym = die->die_symbol;
+
+ if (sym == 0)
+ return;
+
+ if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0)
+ /* We make these global, not weak; if the target doesn't support
+ .linkonce, it doesn't support combining the sections, so debugging
+ will break. */
+ targetm.asm_out.globalize_label (asm_out_file, sym);
+
+ 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 (dw_loc_descr_ref expr, const char *begin, const char *end,
+ const char *section, unsigned int gensym)
+{
+ dw_loc_list_ref retlist = ggc_alloc_cleared (sizeof (dw_loc_list_node));
+
+ retlist->begin = begin;
+ retlist->end = end;
+ retlist->expr = expr;
+ retlist->section = section;
+ if (gensym)
+ retlist->ll_symbol = gen_internal_sym ("LLST");
+
+ return retlist;
+}
+
+/* Add a location description expression to a location list. */
+
+static inline void
+add_loc_descr_to_loc_list (dw_loc_list_ref *list_head, dw_loc_descr_ref descr,
+ const char *begin, const char *end,
+ const char *section)
+{
+ dw_loc_list_ref *d;
+
+ /* 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);
+}
+
+static void
+dwarf2out_switch_text_section (void)
+{
+ dw_fde_ref fde;
+
+ gcc_assert (cfun);
+
+ fde = &fde_table[fde_table_in_use - 1];
+ fde->dw_fde_switched_sections = true;
+ fde->dw_fde_hot_section_label = cfun->hot_section_label;
+ fde->dw_fde_hot_section_end_label = cfun->hot_section_end_label;
+ fde->dw_fde_unlikely_section_label = cfun->cold_section_label;
+ fde->dw_fde_unlikely_section_end_label = cfun->cold_section_end_label;
+ have_multiple_function_sections = true;
+
+ /* Reset the current label on switching text sections, so that we
+ don't attempt to advance_loc4 between labels in different sections. */
+ fde->dw_fde_current_label = NULL;
+}
+
+/* Output the location list given to us. */
+
+static void
+output_loc_list (dw_loc_list_ref list_head)
+{
+ dw_loc_list_ref curr = list_head;
+
+ ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
+
+ /* Walk the location list, and output each range + expression. */
+ for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+ {
+ unsigned long size;
+ /* APPLE LOCAL begin Don't output useless records. */
+ if (strcmp (curr->begin, curr->end) == 0)
+ continue;
+ /* APPLE LOCAL end Don't output useless records. */
+ if (!have_multiple_function_sections)
+ {
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
+ "Location list begin address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
+ "Location list end address (%s)",
+ list_head->ll_symbol);
+ }
+ else
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
+ "Location list begin address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
+ "Location list end address (%s)",
+ list_head->ll_symbol);
+ }
+ size = size_of_locs (curr->expr);
+
+ /* Output the block length for this list of location operations. */
+ gcc_assert (size <= 0xffff);
+ dw2_asm_output_data (2, size, "%s", "Location expression size");
+
+ output_loc_sequence (curr->expr);
+ }
+
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+ "Location list terminator begin (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+ "Location list terminator end (%s)",
+ list_head->ll_symbol);
+}
+
+/* Output the DIE and its attributes. Called recursively to generate
+ the definitions of each child DIE. */
+
+static void
+output_die (dw_die_ref die)
+{
+ dw_attr_ref a;
+ dw_die_ref c;
+ unsigned long size;
+ unsigned ix;
+
+ /* If someone in another CU might refer to us, set up a symbol for
+ them to point to. */
+ if (die->die_symbol)
+ output_die_symbol (die);
+
+ dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
+ die->die_offset, dwarf_tag_name (die->die_tag));
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ {
+ const char *name = dwarf_attr_name (a->dw_attr);
+
+ switch (AT_class (a))
+ {
+ case dw_val_class_addr:
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+ break;
+
+ case dw_val_class_offset:
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
+ "%s", name);
+ break;
+
+ case dw_val_class_range_list:
+ {
+ char *p = strchr (ranges_section_label, '\0');
+
+ sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
+ a->dw_attr_val.v.val_offset);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
+ debug_ranges_section, "%s", name);
+ *p = '\0';
+ }
+ break;
+
+ case dw_val_class_loc:
+ size = size_of_locs (AT_loc (a));
+
+ /* Output the block length for this list of location operations. */
+ dw2_asm_output_data (constant_size (size), size, "%s", name);
+
+ output_loc_sequence (AT_loc (a));
+ break;
+
+ case dw_val_class_const:
+ /* ??? It would be slightly more efficient to use a scheme like is
+ used for unsigned constants below, but gdb 4.x does not sign
+ extend. Gdb 5.x does sign extend. */
+ dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
+ break;
+
+ case dw_val_class_unsigned_const:
+ dw2_asm_output_data (constant_size (AT_unsigned (a)),
+ AT_unsigned (a), "%s", name);
+ break;
+
+ case dw_val_class_long_long:
+ {
+ unsigned HOST_WIDE_INT first, second;
+
+ dw2_asm_output_data (1,
+ 2 * HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ "%s", name);
+
+ if (WORDS_BIG_ENDIAN)
+ {
+ first = a->dw_attr_val.v.val_long_long.hi;
+ second = a->dw_attr_val.v.val_long_long.low;
+ }
+ else
+ {
+ first = a->dw_attr_val.v.val_long_long.low;
+ second = a->dw_attr_val.v.val_long_long.hi;
+ }
+
+ dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ first, "long long constant");
+ dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ second, NULL);
+ }
+ break;
+
+ case dw_val_class_vec:
+ {
+ unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
+ unsigned int len = a->dw_attr_val.v.val_vec.length;
+ unsigned int i;
+ unsigned char *p;
+
+ dw2_asm_output_data (1, len * elt_size, "%s", name);
+ if (elt_size > sizeof (HOST_WIDE_INT))
+ {
+ elt_size /= 2;
+ len *= 2;
+ }
+ for (i = 0, p = a->dw_attr_val.v.val_vec.array;
+ i < len;
+ i++, p += elt_size)
+ dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+ "fp or vector constant word %u", i);
+ break;
+ }
+
+ case dw_val_class_flag:
+ dw2_asm_output_data (1, AT_flag (a), "%s", name);
+ break;
+
+ case dw_val_class_loc_list:
+ {
+ char *sym = AT_loc_list (a)->ll_symbol;
+
+ gcc_assert (sym);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+ "%s", name);
+ }
+ break;
+
+ case dw_val_class_die_ref:
+ if (AT_ref_external (a))
+ {
+ char *sym = AT_ref (a)->die_symbol;
+
+ gcc_assert (sym);
+ dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, debug_info_section,
+ "%s", name);
+ }
+ else
+ {
+ gcc_assert (AT_ref (a)->die_offset);
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
+ "%s", name);
+ }
+ break;
+
+ case dw_val_class_fde_ref:
+ {
+ char l1[20];
+
+ ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
+ a->dw_attr_val.v.val_fde_index * 2);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
+ "%s", name);
+ }
+ break;
+
+ case dw_val_class_lbl_id:
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+ break;
+
+ case dw_val_class_lineptr:
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+ debug_line_section, "%s", name);
+ break;
+
+ case dw_val_class_macptr:
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+ debug_macinfo_section, "%s", name);
+ break;
+
+ case dw_val_class_str:
+ if (AT_string_form (a) == DW_FORM_strp)
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ a->dw_attr_val.v.val_str->label,
+ debug_str_section,
+ "%s: \"%s\"", name, AT_string (a));
+ else
+ dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
+ break;
+
+ case dw_val_class_file:
+ {
+ int f = maybe_emit_file (a->dw_attr_val.v.val_file);
+
+ dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
+ a->dw_attr_val.v.val_file->filename);
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ FOR_EACH_CHILD (die, c, output_die (c));
+
+ /* Add null byte to terminate sibling list. */
+ if (die->die_child != NULL)
+ dw2_asm_output_data (1, 0, "end of children of DIE 0x%lx",
+ die->die_offset);
+}
+
+/* Output the compilation unit that appears at the beginning of the
+ .debug_info section, and precedes the DIE descriptions. */
+
+static void
+output_compilation_unit_header (void)
+{
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE,
+ next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
+ "Length of Compilation Unit Info");
+ dw2_asm_output_data (2, DWARF_VERSION, "DWARF version number");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
+ debug_abbrev_section,
+ "Offset Into Abbrev. Section");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+}
+
+/* Output the compilation unit DIE and its children. */
+
+static void
+output_comp_unit (dw_die_ref die, int output_if_empty)
+{
+ const char *secname;
+ char *oldsym, *tmp;
+
+ /* Unless we are outputting main CU, we may throw away empty ones. */
+ if (!output_if_empty && die->die_child == NULL)
+ return;
+
+ /* Even if there are no children of this DIE, we must output the information
+ about the compilation unit. Otherwise, on an empty translation unit, we
+ will generate a present, but empty, .debug_info section. IRIX 6.5 `nm'
+ will then complain when examining the file. First mark all the DIEs in
+ this CU so we know which get local refs. */
+ mark_dies (die);
+
+ build_abbrev_table (die);
+
+ /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
+ next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
+ calc_die_sizes (die);
+
+ oldsym = die->die_symbol;
+ if (oldsym)
+ {
+ tmp = alloca (strlen (oldsym) + 24);
+
+ sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
+ secname = tmp;
+ die->die_symbol = NULL;
+ switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
+ }
+ else
+ switch_to_section (debug_info_section);
+
+ /* Output debugging information. */
+ output_compilation_unit_header ();
+ output_die (die);
+
+ /* Leave the marks on the main CU, so we can check them in
+ output_pubnames. */
+ if (oldsym)
+ {
+ unmark_dies (die);
+ die->die_symbol = oldsym;
+ }
+}
+
+/* Return the DWARF2/3 pubname associated with a decl. */
+
+static const char *
+dwarf2_name (tree decl, int scope)
+{
+ return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
+}
+
+/* Add a new entry to .debug_pubnames if appropriate. */
+
+static void
+add_pubname (tree decl, dw_die_ref die)
+{
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ pubname_entry e;
+
+ if (! TREE_PUBLIC (decl))
+ return;
+
+ e.die = die;
+ e.name = xstrdup (dwarf2_name (decl, 1));
+ VEC_safe_push (pubname_entry, gc, pubname_table, &e);
+}
+/* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+/* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+/* Add a new entry to .debug_pubtypes if appropriate. */
+
+static void
+add_pubtype (tree decl, dw_die_ref die)
+{
+ pubname_entry e;
+
+ e.name = NULL;
+ if ((TREE_PUBLIC (decl)
+ || die->die_parent == comp_unit_die)
+ && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
+ {
+ e.die = die;
+ if (TYPE_P (decl))
+ {
+ if (TYPE_NAME (decl))
+ {
+ if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
+ e.name =
+ xstrdup ((const char *) IDENTIFIER_POINTER (TYPE_NAME (decl)));
+ else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (decl)))
+ e.name =
+ xstrdup ((const char *) IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl))));
+ else
+ e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
+ }
+ }
+ else
+ e.name = xstrdup (dwarf2_name (decl, 1));
+
+ /* If we don't have a name for the type, there's no point in adding
+ it to the table. */
+ if (e.name && e.name[0] != '\0')
+ VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+ }
+}
+
+/* APPLE LOCAL begin radar 6275985 debug inlined section */
+static void
+add_inlined_section_entry (dw_die_ref die)
+{
+ unsigned i;
+ bool found = false;
+ inlined_ref iptr;
+ dw_die_ref current_origin_die = get_AT_ref (die, DW_AT_abstract_origin);
+
+ /* APPLE LOCAL begin radar 6292557 */
+ if (!current_origin_die)
+ return;
+ /* APPLE LOCAL end radar 6292557 */
+
+ if (!has_AT (die, DW_AT_low_pc))
+ return;
+
+ for (i = 0; VEC_iterate (inlined_entry, debug_inlined_table, i, iptr); i++)
+ {
+ if (iptr->origin_die == current_origin_die)
+ {
+ VEC_safe_push (dw_die_ref, gc, iptr->inlined_instances, &die);
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ inlined_entry *new_entry = (inlined_entry *) xmalloc (sizeof (inlined_entry));
+ new_entry->origin_die = current_origin_die;
+ new_entry->inlined_instances = VEC_alloc (dw_die_ref, gc, 32);
+ VEC_safe_push (dw_die_ref, gc, new_entry->inlined_instances, &die);
+ VEC_safe_push (inlined_entry, gc, debug_inlined_table, new_entry);
+ }
+}
+
+static void
+output_debug_inlined_section (VEC (inlined_entry, gc) * inlined_dies)
+{
+ unsigned i;
+ unsigned long inlined_length = size_of_inlined (inlined_dies);
+ inlined_entry *iptr;
+
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, inlined_length,
+ "Length of Inlined Subroutines Info");
+ dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
+ /* APPLE LOCAL radar 6476836 - eliminate some dead code. */
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+
+ for (i = 0; VEC_iterate (inlined_entry, inlined_dies, i, iptr); i++)
+ {
+ dw_attr_ref name_attr;
+ dw_attr_ref mips_name_attr;
+ dw_die_ref *diep;
+ unsigned j;
+ /* APPLE LOCAL radar 6476836 */
+ unsigned num_entries = 0;
+ dw_die_ref origin_die = iptr->origin_die;
+
+ /* APPLE LOCAL begin radar 6476836 */
+ /* Don't count or output dies that were eliminated as part of
+ unused types. */
+ for (j = 0; VEC_iterate (dw_die_ref, iptr->inlined_instances, j, diep);
+ j++)
+ if (! (*diep)->dead)
+ num_entries++;
+
+ /* If all the entries were eliminated, move to next origin die. */
+ if (num_entries == 0)
+ continue;
+ /* APPLE LOCAL end radar 6476836 */
+
+ mips_name_attr = get_AT (origin_die, DW_AT_MIPS_linkage_name);
+ name_attr = get_AT (origin_die, DW_AT_name);
+
+ if (!mips_name_attr)
+ mips_name_attr = name_attr;
+
+ gcc_assert (origin_die != NULL);
+ gcc_assert (name_attr != NULL);
+ gcc_assert (mips_name_attr != NULL);
+ gcc_assert (num_entries > 0);
+ gcc_assert (AT_string_form (name_attr) == DW_FORM_strp);
+ gcc_assert (AT_string_form (mips_name_attr) == DW_FORM_strp);
+
+ /* APPLE LOCAL radar 6476836 - eliminate some dead code. */
+
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ mips_name_attr->dw_attr_val.v.val_str->label,
+ debug_str_section,
+ "MIPS linkage name: \"%s\"",
+ AT_string (mips_name_attr));
+
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ name_attr->dw_attr_val.v.val_str->label,
+ debug_str_section,
+ "Function name: \"%s\"", AT_string (name_attr));
+
+ dw2_asm_output_data_uleb128 (num_entries, NULL);
+
+ for (j = 0; VEC_iterate (dw_die_ref, iptr->inlined_instances, j, diep);
+ j++)
+ {
+ const char *low_pc = get_AT_low_pc (*diep);
+
+ gcc_assert (low_pc != NULL);
+
+ /* APPLE LOCAL begin radar 6476836 */
+ /* Don't output dies that were eliminated as part of unused
+ types. */
+ if (! (*diep)->dead)
+ {
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, (*diep)->die_offset,
+ "inlined subroutine die offset");
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, low_pc, "%s",
+ "Low PC address");
+ }
+ /* APPLE LOCAL end radar 6476836 */
+ }
+ }
+}
+/* APPLE LOCAL end radar 6275985 debug inlined section */
+
+/* Output the public names table used to speed up access to externally
+ visible names; or the public types table used to find type
+ definitions. For now, only generate entries for externally
+ visible procedures (in pubnames table). */
+
+static void
+output_pubnames (VEC (pubname_entry, gc) * names)
+{
+ unsigned i;
+ unsigned long pubnames_length = size_of_pubnames (names);
+ pubname_ref pub;
+/* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ if (names == pubname_table)
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+ "Length of Public Names Info");
+ else
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+ "Length of Public Type Names Info");
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+ dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+ debug_info_section,
+ "Offset of Compilation Unit Info");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
+ "Compilation Unit Length");
+
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
+ {
+ /* We shouldn't see pubnames for DIEs outside of the main CU. */
+ if (names == pubname_table)
+ gcc_assert (pub->die->die_mark);
+
+ if (names != pubtype_table
+ || pub->die->die_offset != 0
+ || !flag_eliminate_unused_debug_types)
+ {
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
+ "DIE offset");
+
+ dw2_asm_output_nstring (pub->name, -1, "external name");
+ }
+ }
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
+}
+
+/* Add a new entry to .debug_aranges if appropriate. */
+
+static void
+add_arange (tree decl, dw_die_ref die)
+{
+ if (! DECL_SECTION_NAME (decl))
+ return;
+
+ if (arange_table_in_use == arange_table_allocated)
+ {
+ arange_table_allocated += ARANGE_TABLE_INCREMENT;
+ arange_table = ggc_realloc (arange_table,
+ (arange_table_allocated
+ * sizeof (dw_die_ref)));
+ memset (arange_table + arange_table_in_use, 0,
+ ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref));
+ }
+
+ arange_table[arange_table_in_use++] = die;
+}
+
+/* Output the information that goes into the .debug_aranges table.
+ Namely, define the beginning and ending address range of the
+ text section generated for this compilation unit. */
+
+static void
+output_aranges (void)
+{
+ unsigned i;
+ unsigned long aranges_length = size_of_aranges ();
+
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
+ "Length of Address Ranges Info");
+ dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+ debug_info_section,
+ "Offset of Compilation Unit Info");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
+ dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
+
+ /* We need to align to twice the pointer size here. */
+ if (DWARF_ARANGES_PAD_SIZE)
+ {
+ /* Pad using a 2 byte words so that padding is correct for any
+ pointer size. */
+ dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
+ 2 * DWARF2_ADDR_SIZE);
+ for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
+ dw2_asm_output_data (2, 0, NULL);
+ }
+
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+ text_section_label, "Length");
+ if (flag_reorder_blocks_and_partition)
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
+ "Address");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
+ cold_text_section_label, "Length");
+ }
+
+ for (i = 0; i < arange_table_in_use; i++)
+ {
+ dw_die_ref die = arange_table[i];
+
+ /* We shouldn't see aranges for DIEs outside of the main CU. */
+ gcc_assert (die->die_mark);
+
+ if (die->die_tag == DW_TAG_subprogram)
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die),
+ "Address");
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die),
+ get_AT_low_pc (die), "Length");
+ }
+ else
+ {
+ /* A static variable; extract the symbol from DW_AT_location.
+ Note that this code isn't currently hit, as we only emit
+ aranges for functions (jason 9/23/99). */
+ dw_attr_ref a = get_AT (die, DW_AT_location);
+ dw_loc_descr_ref loc;
+
+ gcc_assert (a && AT_class (a) == dw_val_class_loc);
+
+ loc = AT_loc (a);
+ gcc_assert (loc->dw_loc_opc == DW_OP_addr);
+
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
+ loc->dw_loc_oprnd1.v.val_addr, "Address");
+ dw2_asm_output_data (DWARF2_ADDR_SIZE,
+ get_AT_unsigned (die, DW_AT_byte_size),
+ "Length");
+ }
+ }
+
+ /* Output the terminator words. */
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+}
+
+/* Add a new entry to .debug_ranges. Return the offset at which it
+ was placed. */
+
+static unsigned int
+add_ranges (tree block)
+{
+ unsigned int in_use = ranges_table_in_use;
+
+ if (in_use == ranges_table_allocated)
+ {
+ ranges_table_allocated += RANGES_TABLE_INCREMENT;
+ ranges_table
+ = ggc_realloc (ranges_table, (ranges_table_allocated
+ * sizeof (struct dw_ranges_struct)));
+ memset (ranges_table + ranges_table_in_use, 0,
+ RANGES_TABLE_INCREMENT * sizeof (struct dw_ranges_struct));
+ }
+
+ ranges_table[in_use].block_num = (block ? BLOCK_NUMBER (block) : 0);
+ ranges_table_in_use = in_use + 1;
+
+ return in_use * 2 * DWARF2_ADDR_SIZE;
+}
+
+static void
+output_ranges (void)
+{
+ unsigned i;
+ static const char *const start_fmt = "Offset 0x%x";
+ const char *fmt = start_fmt;
+
+ for (i = 0; i < ranges_table_in_use; i++)
+ {
+ int block_num = ranges_table[i].block_num;
+
+ if (block_num)
+ {
+ char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
+ char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
+ ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
+
+ /* If all code is in the text section, then the compilation
+ unit base address defaults to DW_AT_low_pc, which is the
+ base of the text section. */
+ if (!have_multiple_function_sections)
+ {
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
+ text_section_label,
+ fmt, i * 2 * DWARF2_ADDR_SIZE);
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
+ text_section_label, NULL);
+ }
+
+ /* Otherwise, we add a DW_AT_entry_pc attribute to force the
+ compilation unit base address to zero, which allows us to
+ use absolute addresses, and not worry about whether the
+ target supports cross-section arithmetic. */
+ else
+ {
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+ fmt, i * 2 * DWARF2_ADDR_SIZE);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
+ }
+
+ fmt = NULL;
+ }
+ else
+ {
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+ dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+ fmt = start_fmt;
+ }
+ }
+}
+
+/* Data structure containing information about input files. */
+struct file_info
+{
+ const char *path; /* Complete file name. */
+ const char *fname; /* File name part. */
+ int length; /* Length of entire string. */
+ struct dwarf_file_data * file_idx; /* Index in input file table. */
+ int dir_idx; /* Index in directory table. */
+};
+
+/* Data structure containing information about directories with source
+ files. */
+struct dir_info
+{
+ const char *path; /* Path including directory name. */
+ int length; /* Path length. */
+ int prefix; /* Index of directory entry which is a prefix. */
+ int count; /* Number of files in this directory. */
+ int dir_idx; /* Index of directory used as base. */
+};
+
+/* Callback function for file_info comparison. We sort by looking at
+ the directories in the path. */
+
+static int
+file_info_cmp (const void *p1, const void *p2)
+{
+ const struct file_info *s1 = p1;
+ const struct file_info *s2 = p2;
+ unsigned char *cp1;
+ unsigned char *cp2;
+
+ /* Take care of file names without directories. We need to make sure that
+ we return consistent values to qsort since some will get confused if
+ we return the same value when identical operands are passed in opposite
+ orders. So if neither has a directory, return 0 and otherwise return
+ 1 or -1 depending on which one has the directory. */
+ if ((s1->path == s1->fname || s2->path == s2->fname))
+ return (s2->path == s2->fname) - (s1->path == s1->fname);
+
+ cp1 = (unsigned char *) s1->path;
+ cp2 = (unsigned char *) s2->path;
+
+ while (1)
+ {
+ ++cp1;
+ ++cp2;
+ /* Reached the end of the first path? If so, handle like above. */
+ if ((cp1 == (unsigned char *) s1->fname)
+ || (cp2 == (unsigned char *) s2->fname))
+ return ((cp2 == (unsigned char *) s2->fname)
+ - (cp1 == (unsigned char *) s1->fname));
+
+ /* Character of current path component the same? */
+ else if (*cp1 != *cp2)
+ return *cp1 - *cp2;
+ }
+}
+
+struct file_name_acquire_data
+{
+ struct file_info *files;
+ int used_files;
+ int max_files;
+};
+
+/* Traversal function for the hash table. */
+
+static int
+file_name_acquire (void ** slot, void *data)
+{
+ struct file_name_acquire_data *fnad = data;
+ struct dwarf_file_data *d = *slot;
+ struct file_info *fi;
+ const char *f;
+
+ gcc_assert (fnad->max_files >= d->emitted_number);
+
+ if (! d->emitted_number)
+ return 1;
+
+ gcc_assert (fnad->max_files != fnad->used_files);
+
+ fi = fnad->files + fnad->used_files++;
+
+ /* Skip all leading "./". */
+ f = d->filename;
+ while (f[0] == '.' && f[1] == '/')
+ f += 2;
+
+ /* Create a new array entry. */
+ fi->path = f;
+ fi->length = strlen (f);
+ fi->file_idx = d;
+
+ /* Search for the file name part. */
+ f = strrchr (f, '/');
+ fi->fname = f == NULL ? fi->path : f + 1;
+ return 1;
+}
+
+/* Output the directory table and the file name table. We try to minimize
+ the total amount of memory needed. A heuristic is used to avoid large
+ slowdowns with many input files. */
+
+static void
+output_file_names (void)
+{
+ struct file_name_acquire_data fnad;
+ int numfiles;
+ struct file_info *files;
+ struct dir_info *dirs;
+ int *saved;
+ int *savehere;
+ int *backmap;
+ int ndirs;
+ int idx_offset;
+ int i;
+ int idx;
+
+ if (!last_emitted_file)
+ {
+ dw2_asm_output_data (1, 0, "End directory table");
+ dw2_asm_output_data (1, 0, "End file name table");
+ return;
+ }
+
+ numfiles = last_emitted_file->emitted_number;
+
+ /* Allocate the various arrays we need. */
+ files = alloca (numfiles * sizeof (struct file_info));
+ dirs = alloca (numfiles * sizeof (struct dir_info));
+
+ fnad.files = files;
+ fnad.used_files = 0;
+ fnad.max_files = numfiles;
+ htab_traverse (file_table, file_name_acquire, &fnad);
+ gcc_assert (fnad.used_files == fnad.max_files);
+
+ qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
+
+ /* Find all the different directories used. */
+ dirs[0].path = files[0].path;
+ dirs[0].length = files[0].fname - files[0].path;
+ dirs[0].prefix = -1;
+ dirs[0].count = 1;
+ dirs[0].dir_idx = 0;
+ files[0].dir_idx = 0;
+ ndirs = 1;
+
+ for (i = 1; i < numfiles; i++)
+ if (files[i].fname - files[i].path == dirs[ndirs - 1].length
+ && memcmp (dirs[ndirs - 1].path, files[i].path,
+ dirs[ndirs - 1].length) == 0)
+ {
+ /* Same directory as last entry. */
+ files[i].dir_idx = ndirs - 1;
+ ++dirs[ndirs - 1].count;
+ }
+ else
+ {
+ int j;
+
+ /* This is a new directory. */
+ dirs[ndirs].path = files[i].path;
+ dirs[ndirs].length = files[i].fname - files[i].path;
+ dirs[ndirs].count = 1;
+ dirs[ndirs].dir_idx = ndirs;
+ files[i].dir_idx = ndirs;
+
+ /* Search for a prefix. */
+ dirs[ndirs].prefix = -1;
+ for (j = 0; j < ndirs; j++)
+ if (dirs[j].length < dirs[ndirs].length
+ && dirs[j].length > 1
+ && (dirs[ndirs].prefix == -1
+ || dirs[j].length > dirs[dirs[ndirs].prefix].length)
+ && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
+ dirs[ndirs].prefix = j;
+
+ ++ndirs;
+ }
+
+ /* Now to the actual work. We have to find a subset of the directories which
+ allow expressing the file name using references to the directory table
+ with the least amount of characters. We do not do an exhaustive search
+ where we would have to check out every combination of every single
+ possible prefix. Instead we use a heuristic which provides nearly optimal
+ results in most cases and never is much off. */
+ saved = alloca (ndirs * sizeof (int));
+ savehere = alloca (ndirs * sizeof (int));
+
+ memset (saved, '\0', ndirs * sizeof (saved[0]));
+ for (i = 0; i < ndirs; i++)
+ {
+ int j;
+ int total;
+
+ /* We can always save some space for the current directory. But this
+ does not mean it will be enough to justify adding the directory. */
+ savehere[i] = dirs[i].length;
+ total = (savehere[i] - saved[i]) * dirs[i].count;
+
+ for (j = i + 1; j < ndirs; j++)
+ {
+ savehere[j] = 0;
+ if (saved[j] < dirs[i].length)
+ {
+ /* Determine whether the dirs[i] path is a prefix of the
+ dirs[j] path. */
+ int k;
+
+ k = dirs[j].prefix;
+ while (k != -1 && k != (int) i)
+ k = dirs[k].prefix;
+
+ if (k == (int) i)
+ {
+ /* Yes it is. We can possibly save some memory by
+ writing the filenames in dirs[j] relative to
+ dirs[i]. */
+ savehere[j] = dirs[i].length;
+ total += (savehere[j] - saved[j]) * dirs[j].count;
+ }
+ }
+ }
+
+ /* Check whether we can save enough to justify adding the dirs[i]
+ directory. */
+ if (total > dirs[i].length + 1)
+ {
+ /* It's worthwhile adding. */
+ for (j = i; j < ndirs; j++)
+ if (savehere[j] > 0)
+ {
+ /* Remember how much we saved for this directory so far. */
+ saved[j] = savehere[j];
+
+ /* Remember the prefix directory. */
+ dirs[j].dir_idx = i;
+ }
+ }
+ }
+
+ /* Emit the directory name table. */
+ idx = 1;
+ idx_offset = dirs[0].length > 0 ? 1 : 0;
+ for (i = 1 - idx_offset; i < ndirs; i++)
+ dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
+ "Directory Entry: 0x%x", i + idx_offset);
+
+ dw2_asm_output_data (1, 0, "End directory table");
+
+ /* We have to emit them in the order of emitted_number since that's
+ used in the debug info generation. To do this efficiently we
+ generate a back-mapping of the indices first. */
+ backmap = alloca (numfiles * sizeof (int));
+ for (i = 0; i < numfiles; i++)
+ backmap[files[i].file_idx->emitted_number - 1] = i;
+
+ /* Now write all the file names. */
+ for (i = 0; i < numfiles; i++)
+ {
+ int file_idx = backmap[i];
+ int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+
+ dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
+ "File Entry: 0x%x", (unsigned) i + 1);
+
+ /* Include directory index. */
+ dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+
+ /* Modification time. */
+ dw2_asm_output_data_uleb128 (0, NULL);
+
+ /* File length in bytes. */
+ dw2_asm_output_data_uleb128 (0, NULL);
+ }
+
+ dw2_asm_output_data (1, 0, "End file name table");
+}
+
+
+/* Output the source line number correspondence information. This
+ information goes into the .debug_line section. */
+
+static void
+output_line_info (void)
+{
+ char l1[20], l2[20], p1[20], p2[20];
+ char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ unsigned opc;
+ unsigned n_op_args;
+ unsigned long lt_index;
+ unsigned long current_line;
+ long line_offset;
+ long line_delta;
+ unsigned long current_file;
+ unsigned long function;
+
+ ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
+
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
+ "Length of Source Line Info");
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+ dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
+ ASM_OUTPUT_LABEL (asm_out_file, p1);
+
+ /* Define the architecture-dependent minimum instruction length (in
+ bytes). In this implementation of DWARF, this field is used for
+ information purposes only. Since GCC generates assembly language,
+ we have no a priori knowledge of how many instruction bytes are
+ generated for each source line, and therefore can use only the
+ DW_LNE_set_address and DW_LNS_fixed_advance_pc line information
+ commands. Accordingly, we fix this as `1', which is "correct
+ enough" for all architectures, and don't let the target override. */
+ dw2_asm_output_data (1, 1,
+ "Minimum Instruction Length");
+
+ dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
+ "Default is_stmt_start flag");
+ dw2_asm_output_data (1, DWARF_LINE_BASE,
+ "Line Base Value (Special Opcodes)");
+ dw2_asm_output_data (1, DWARF_LINE_RANGE,
+ "Line Range Value (Special Opcodes)");
+ dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
+ "Special Opcode Base");
+
+ for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++)
+ {
+ switch (opc)
+ {
+ case DW_LNS_advance_pc:
+ case DW_LNS_advance_line:
+ case DW_LNS_set_file:
+ case DW_LNS_set_column:
+ case DW_LNS_fixed_advance_pc:
+ n_op_args = 1;
+ break;
+ default:
+ n_op_args = 0;
+ break;
+ }
+
+ dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
+ opc, n_op_args);
+ }
+
+ /* Write out the information about the files we use. */
+ output_file_names ();
+ ASM_OUTPUT_LABEL (asm_out_file, p2);
+
+ /* We used to set the address register to the first location in the text
+ section here, but that didn't accomplish anything since we already
+ have a line note for the opening brace of the first function. */
+
+ /* Generate the line number to PC correspondence table, encoded as
+ a series of state machine operations. */
+ current_file = 1;
+ current_line = 1;
+
+ if (cfun && in_cold_section_p)
+ strcpy (prev_line_label, cfun->cold_section_label);
+ else
+ strcpy (prev_line_label, text_section_label);
+ for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+ {
+ dw_line_info_ref line_info = &line_info_table[lt_index];
+
+#if 0
+ /* Disable this optimization for now; GDB wants to see two line notes
+ at the beginning of a function so it can find the end of the
+ prologue. */
+
+ /* Don't emit anything for redundant notes. Just updating the
+ address doesn't accomplish anything, because we already assume
+ that anything after the last address is this line. */
+ if (line_info->dw_line_num == current_line
+ && line_info->dw_file_num == current_file)
+ continue;
+#endif
+
+ /* Emit debug info for the address of the current line.
+
+ Unfortunately, we have little choice here currently, and must always
+ use the most general form. GCC does not know the address delta
+ itself, so we can't use DW_LNS_advance_pc. Many ports do have length
+ attributes which will give an upper bound on the address range. We
+ could perhaps use length attributes to determine when it is safe to
+ use DW_LNS_fixed_advance_pc. */
+
+ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
+ if (0)
+ {
+ /* This can handle deltas up to 0xffff. This takes 3 bytes. */
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+ "DW_LNS_fixed_advance_pc");
+ dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+ }
+ else
+ {
+ /* This can handle any delta. This takes
+ 4+DWARF2_ADDR_SIZE bytes. */
+ dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+ dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+ dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+ }
+
+ strcpy (prev_line_label, line_label);
+
+ /* Emit debug info for the source file of the current line, if
+ different from the previous line. */
+ if (line_info->dw_file_num != current_file)
+ {
+ current_file = line_info->dw_file_num;
+ dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
+ dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
+ }
+
+ /* Emit debug info for the current line number, choosing the encoding
+ that uses the least amount of space. */
+ 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))
+ /* This can handle deltas from -10 to 234, using the current
+ definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This
+ takes 1 byte. */
+ dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+ "line %lu", current_line);
+ else
+ {
+ /* This can handle any delta. This takes at least 4 bytes,
+ depending on the value being encoded. */
+ dw2_asm_output_data (1, DW_LNS_advance_line,
+ "advance to line %lu", current_line);
+ dw2_asm_output_data_sleb128 (line_offset, NULL);
+ dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+ }
+ }
+ else
+ /* We still need to start a new row, so output a copy insn. */
+ dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+ }
+
+ /* Emit debug info for the address of the end of the function. */
+ if (0)
+ {
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+ "DW_LNS_fixed_advance_pc");
+ dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
+ }
+ else
+ {
+ dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+ dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+ dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
+ }
+
+ dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
+ dw2_asm_output_data_uleb128 (1, NULL);
+ dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+
+ function = 0;
+ current_file = 1;
+ current_line = 1;
+ for (lt_index = 0; lt_index < separate_line_info_table_in_use;)
+ {
+ dw_separate_line_info_ref line_info
+ = &separate_line_info_table[lt_index];
+
+#if 0
+ /* Don't emit anything for redundant notes. */
+ if (line_info->dw_line_num == current_line
+ && line_info->dw_file_num == current_file
+ && line_info->function == function)
+ goto cont;
+#endif
+
+ /* Emit debug info for the address of the current line. If this is
+ a new function, or the first line of a function, then we need
+ to handle it differently. */
+ ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
+ lt_index);
+ if (function != line_info->function)
+ {
+ function = line_info->function;
+
+ /* Set the address register to the first line in the function. */
+ dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+ dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+ dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+ }
+ else
+ {
+ /* ??? See the DW_LNS_advance_pc comment above. */
+ if (0)
+ {
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+ "DW_LNS_fixed_advance_pc");
+ dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+ }
+ else
+ {
+ dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+ dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+ dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+ }
+ }
+
+ strcpy (prev_line_label, line_label);
+
+ /* Emit debug info for the source file of the current line, if
+ different from the previous line. */
+ if (line_info->dw_file_num != current_file)
+ {
+ current_file = line_info->dw_file_num;
+ dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
+ dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
+ }
+
+ /* Emit debug info for the current line number, choosing the encoding
+ that uses the least amount of space. */
+ if (line_info->dw_line_num != current_line)
+ {
+ line_offset = line_info->dw_line_num - current_line;
+ line_delta = line_offset - DWARF_LINE_BASE;
+ current_line = line_info->dw_line_num;
+ if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+ dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+ "line %lu", current_line);
+ else
+ {
+ dw2_asm_output_data (1, DW_LNS_advance_line,
+ "advance to line %lu", current_line);
+ dw2_asm_output_data_sleb128 (line_offset, NULL);
+ dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+ }
+ }
+ else
+ dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
+
+#if 0
+ cont:
+#endif
+
+ lt_index++;
+
+ /* If we're done with a function, end its sequence. */
+ if (lt_index == separate_line_info_table_in_use
+ || separate_line_info_table[lt_index].function != function)
+ {
+ current_file = 1;
+ current_line = 1;
+
+ /* Emit debug info for the address of the end of the function. */
+ ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
+ if (0)
+ {
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+ "DW_LNS_fixed_advance_pc");
+ dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
+ }
+ else
+ {
+ dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+ dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+ dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+ }
+
+ /* Output the marker for the end of this sequence. */
+ dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
+ dw2_asm_output_data_uleb128 (1, NULL);
+ dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
+ }
+ }
+
+ /* Output the marker for the end of the line number info. */
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+}
+
+/* Given a pointer to a tree node for some base type, return a pointer to
+ a DIE that describes the given type.
+
+ This routine must only be called for GCC type nodes that correspond to
+ Dwarf base (fundamental) types. */
+
+static dw_die_ref
+base_type_die (tree type)
+{
+ dw_die_ref base_type_result;
+ enum dwarf_type encoding;
+
+ if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
+ return 0;
+
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ if (TYPE_STRING_FLAG (type))
+ {
+ if (TYPE_UNSIGNED (type))
+ encoding = DW_ATE_unsigned_char;
+ else
+ encoding = DW_ATE_signed_char;
+ }
+ else if (TYPE_UNSIGNED (type))
+ encoding = DW_ATE_unsigned;
+ else
+ encoding = DW_ATE_signed;
+ break;
+
+ case REAL_TYPE:
+ if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
+ encoding = DW_ATE_decimal_float;
+ else
+ encoding = DW_ATE_float;
+ break;
+
+ /* Dwarf2 doesn't know anything about complex ints, so use
+ a user defined type for it. */
+ case COMPLEX_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+ encoding = DW_ATE_complex_float;
+ else
+ encoding = DW_ATE_lo_user;
+ break;
+
+ case BOOLEAN_TYPE:
+ /* GNU FORTRAN/Ada/C++ BOOLEAN type. */
+ encoding = DW_ATE_boolean;
+ break;
+
+ default:
+ /* No other TREE_CODEs are Dwarf fundamental types. */
+ gcc_unreachable ();
+ }
+
+ base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
+
+ /* This probably indicates a bug. */
+ if (! TYPE_NAME (type))
+ add_name_attribute (base_type_result, "__unknown__");
+
+ add_AT_unsigned (base_type_result, DW_AT_byte_size,
+ int_size_in_bytes (type));
+ add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+
+ return base_type_result;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to
+ the Dwarf "root" type for the given input type. The Dwarf "root" type of
+ a given type is generally the same as the given type, except that if the
+ given type is a pointer or reference type, then the root type of the given
+ type is the root type of the "basis" type for the pointer or reference
+ type. (This definition of the "root" type is recursive.) Also, the root
+ type of a `const' qualified type or a `volatile' qualified type is the
+ root type of the given type without the qualifiers. */
+
+static tree
+root_type (tree type)
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ return error_mark_node;
+
+ /* APPLE LOCAL radar 5732232 - blocks */
+ case BLOCK_POINTER_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return type_main_variant (root_type (TREE_TYPE (type)));
+
+ default:
+ return type_main_variant (type);
+ }
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
+ given input type is a Dwarf "fundamental" type. Otherwise return null. */
+
+static inline int
+is_base_type (tree type)
+{
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ return 1;
+
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case ENUMERAL_TYPE:
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ /* APPLE LOCAL radar 5732232 - blocks */
+ case BLOCK_POINTER_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case OFFSET_TYPE:
+ case LANG_TYPE:
+ case VECTOR_TYPE:
+ return 0;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return 0;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+ node, return the size in bits for the type if it is a constant, or else
+ return the alignment for the type if the type's size is not constant, or
+ else return BITS_PER_WORD if the type actually turns out to be an
+ ERROR_MARK node. */
+
+static inline unsigned HOST_WIDE_INT
+simple_type_size_in_bits (tree type)
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return BITS_PER_WORD;
+ else if (TYPE_SIZE (type) == NULL_TREE)
+ return 0;
+ else if (host_integerp (TYPE_SIZE (type), 1))
+ return tree_low_cst (TYPE_SIZE (type), 1);
+ else
+ return TYPE_ALIGN (type);
+}
+
+/* Return true if the debug information for the given type should be
+ emitted as a subrange type. */
+
+static inline bool
+is_subrange_type (tree type)
+{
+ tree subtype = TREE_TYPE (type);
+
+ /* Subrange types are identified by the fact that they are integer
+ types, and that they have a subtype which is either an integer type
+ or an enumeral type. */
+
+ if (TREE_CODE (type) != INTEGER_TYPE
+ || subtype == NULL_TREE)
+ return false;
+
+ if (TREE_CODE (subtype) != INTEGER_TYPE
+ && TREE_CODE (subtype) != ENUMERAL_TYPE)
+ return false;
+
+ if (TREE_CODE (type) == TREE_CODE (subtype)
+ && int_size_in_bytes (type) == int_size_in_bytes (subtype)
+ && TYPE_MIN_VALUE (type) != NULL
+ && TYPE_MIN_VALUE (subtype) != NULL
+ && tree_int_cst_equal (TYPE_MIN_VALUE (type), TYPE_MIN_VALUE (subtype))
+ && TYPE_MAX_VALUE (type) != NULL
+ && TYPE_MAX_VALUE (subtype) != NULL
+ && tree_int_cst_equal (TYPE_MAX_VALUE (type), TYPE_MAX_VALUE (subtype)))
+ {
+ /* The type and its subtype have the same representation. If in
+ addition the two types also have the same name, then the given
+ type is not a subrange type, but rather a plain base type. */
+ /* FIXME: brobecker/2004-03-22:
+ Sizetype INTEGER_CSTs nodes are canonicalized. It should
+ therefore be sufficient to check the TYPE_SIZE node pointers
+ rather than checking the actual size. Unfortunately, we have
+ found some cases, such as in the Ada "integer" type, where
+ this is not the case. Until this problem is solved, we need to
+ keep checking the actual size. */
+ tree type_name = TYPE_NAME (type);
+ tree subtype_name = TYPE_NAME (subtype);
+
+ if (type_name != NULL && TREE_CODE (type_name) == TYPE_DECL)
+ type_name = DECL_NAME (type_name);
+
+ if (subtype_name != NULL && TREE_CODE (subtype_name) == TYPE_DECL)
+ subtype_name = DECL_NAME (subtype_name);
+
+ if (type_name == subtype_name)
+ return false;
+ }
+
+ return true;
+}
+
+/* Given a pointer to a tree node for a subrange type, return a pointer
+ to a DIE that describes the given type. */
+
+static dw_die_ref
+subrange_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref subrange_die;
+ const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
+
+ if (context_die == NULL)
+ context_die = comp_unit_die;
+
+ subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
+
+ if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
+ {
+ /* The size of the subrange type and its base type do not match,
+ so we need to generate a size attribute for the subrange type. */
+ add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
+ }
+
+ if (TYPE_MIN_VALUE (type) != NULL)
+ add_bound_info (subrange_die, DW_AT_lower_bound,
+ TYPE_MIN_VALUE (type));
+ if (TYPE_MAX_VALUE (type) != NULL)
+ add_bound_info (subrange_die, DW_AT_upper_bound,
+ TYPE_MAX_VALUE (type));
+
+ return subrange_die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
+ entry that chains various modifiers in front of the given type. */
+
+static dw_die_ref
+modified_type_die (tree type, int is_const_type, int is_volatile_type,
+ dw_die_ref context_die)
+{
+ enum tree_code code = TREE_CODE (type);
+ dw_die_ref mod_type_die;
+ dw_die_ref sub_die = NULL;
+ tree item_type = NULL;
+ tree qualified_type;
+ tree name;
+
+ if (code == ERROR_MARK)
+ return NULL;
+
+ /* APPLE LOCAL begin Radar 5741731, typedefs used in '@try' blocks */
+ if (is_volatile_type
+ /* APPLE LOCAL - radar 6113240 */
+ && (is_objc () || is_objcxx ())
+ && lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (type)))
+ {
+ is_volatile_type = 0;
+ if (TYPE_NAME (type) && TREE_TYPE (TYPE_NAME (type)))
+ type = TREE_TYPE (TYPE_NAME (type));
+ }
+ /* APPLE LOCAL end Radar 5741731, typedefs used in '@try' blocks */
+
+ /* 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;
+ }
+
+ name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
+
+ /* Handle C typedef types. */
+ if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
+ {
+ tree dtype = TREE_TYPE (name);
+
+ if (qualified_type == dtype)
+ {
+ /* For a named type, use the typedef. */
+ gen_type_die (qualified_type, context_die);
+ return lookup_type_die (qualified_type);
+ }
+ else if (is_const_type < TYPE_READONLY (dtype)
+ || is_volatile_type < TYPE_VOLATILE (dtype)
+ || (is_const_type <= TYPE_READONLY (dtype)
+ && is_volatile_type <= TYPE_VOLATILE (dtype)
+ && DECL_ORIGINAL_TYPE (name) != type))
+ /* cv-unqualified version of named type. Just use the unnamed
+ type to which it refers. */
+ return modified_type_die (DECL_ORIGINAL_TYPE (name),
+ is_const_type, is_volatile_type,
+ context_die);
+ /* Else cv-qualified version of named type; fall through. */
+ }
+
+ if (is_const_type)
+ {
+ mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
+ sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
+ }
+ else if (is_volatile_type)
+ {
+ mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
+ sub_die = modified_type_die (type, 0, 0, context_die);
+ }
+ /* APPLE LOCAL radar 5732232 - blocks */
+ else if (code == POINTER_TYPE || code == BLOCK_POINTER_TYPE)
+ {
+ mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+ simple_type_size_in_bits (type) / BITS_PER_UNIT);
+ item_type = TREE_TYPE (type);
+ }
+ else if (code == REFERENCE_TYPE)
+ {
+ mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+ simple_type_size_in_bits (type) / BITS_PER_UNIT);
+ item_type = TREE_TYPE (type);
+ }
+ else if (is_subrange_type (type))
+ {
+ mod_type_die = subrange_type_die (type, context_die);
+ item_type = TREE_TYPE (type);
+ }
+ else if (is_base_type (type))
+ mod_type_die = base_type_die (type);
+ else
+ {
+ gen_type_die (type, context_die);
+
+ /* We have to get the type_main_variant here (and pass that to the
+ `lookup_type_die' routine) because the ..._TYPE node we have
+ might simply be a *copy* of some original type node (where the
+ copy was created to help us keep track of typedef names) and
+ that copy might have a different TYPE_UID from the original
+ ..._TYPE node. */
+ if (TREE_CODE (type) != VECTOR_TYPE)
+ return lookup_type_die (type_main_variant (type));
+ else
+ /* Vectors have the debugging information in the type,
+ not the main variant. */
+ return lookup_type_die (type);
+ }
+
+ /* Builtin types don't have a DECL_ORIGINAL_TYPE. For those,
+ don't output a DW_TAG_typedef, since there isn't one in the
+ user's program; just attach a DW_AT_name to the type. */
+ if (name
+ && (TREE_CODE (name) != TYPE_DECL || TREE_TYPE (name) == qualified_type))
+ {
+ if (TREE_CODE (name) == TYPE_DECL)
+ /* Could just call add_name_and_src_coords_attributes here,
+ but since this is a builtin type it doesn't have any
+ useful source coordinates anyway. */
+ name = DECL_NAME (name);
+ add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
+ }
+
+ if (qualified_type)
+ equate_type_number_to_die (qualified_type, mod_type_die);
+
+ if (item_type)
+ /* We must do this after the equate_type_number_to_die call, in case
+ this is a recursive type. This ensures that the modified_type_die
+ recursion will terminate even if the type is recursive. Recursive
+ types are possible in Ada. */
+ 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);
+
+ /* APPLE LOCAL begin radar 5359827 add named pointer types to pubtype table */
+ if (mod_type_die
+ && mod_type_die->die_tag == DW_TAG_pointer_type
+ && get_AT (mod_type_die, DW_AT_name))
+ add_pubtype (type, mod_type_die);
+ /* APPLE LOCAL end radar 5359827 add named pointer types to pubtype table */
+
+ return mod_type_die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
+ an enumerated type. */
+
+static inline int
+type_is_enum (tree type)
+{
+ return TREE_CODE (type) == ENUMERAL_TYPE;
+}
+
+/* Return the DBX register number described by a given RTL node. */
+
+static unsigned int
+dbx_reg_number (rtx rtl)
+{
+ unsigned regno = REGNO (rtl);
+
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+
+#ifdef LEAF_REG_REMAP
+ if (current_function_uses_only_leaf_regs)
+ {
+ int leaf_reg = LEAF_REG_REMAP (regno);
+ if (leaf_reg != -1)
+ regno = (unsigned) leaf_reg;
+ }
+#endif
+
+ return DBX_REGISTER_NUMBER (regno);
+}
+
+/* Optionally add a DW_OP_piece term to a location description expression.
+ DW_OP_piece is only added if the location description expression already
+ doesn't end with DW_OP_piece. */
+
+static void
+add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
+{
+ dw_loc_descr_ref loc;
+
+ if (*list_head != NULL)
+ {
+ /* Find the end of the chain. */
+ for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
+ ;
+
+ if (loc->dw_loc_opc != DW_OP_piece)
+ loc->dw_loc_next = new_loc_descr (DW_OP_piece, size, 0);
+ }
+}
+
+/* Return a location descriptor that designates a machine register or
+ zero if there is none. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
+/* APPLE LOCAL end track initialization status 4964532 */
+{
+ rtx regs;
+
+ if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ regs = targetm.dwarf_register_span (rtl);
+
+/* APPLE LOCAL begin 6186914 */
+#ifdef TARGET_DWARF2_REG_HANDLER
+ /* If this macro is defined, it should provide any target-specific
+ register debug info handling. The macro should return the
+ dw_loc_descr_ref if it performs any alternative handling, and
+ fall through otherwise. */
+ TARGET_DWARF2_REG_HANDLER (rtl);
+#endif
+/* APPLE LOCAL end 6186914 */
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
+ return multiple_reg_loc_descriptor (rtl, regs, initialized);
+ else
+ return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
+ /* APPLE LOCAL end track initialization status 4964532 */
+}
+
+/* Return a location descriptor that designates a machine register for
+ a given hard register number. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
+{
+ dw_loc_descr_ref reg_loc_descr;
+
+ if (regno <= 31)
+ reg_loc_descr = new_loc_descr (DW_OP_reg0 + regno, 0, 0);
+ else
+ reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+
+ if (initialized == STATUS_UNINITIALIZED)
+ add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
+
+ return reg_loc_descr;
+}
+/* APPLE LOCAL end track initialization status 4964532 */
+
+/* Given an RTL of a register, return a location descriptor that
+ designates a value that spans more than one register. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+multiple_reg_loc_descriptor (rtx rtl, rtx regs,
+ enum var_init_status initialized)
+/* APPLE LOCAL end track initialization status 4964532 */
+{
+ int nregs, size, i;
+ unsigned reg;
+ dw_loc_descr_ref loc_result = NULL;
+
+ reg = REGNO (rtl);
+#ifdef LEAF_REG_REMAP
+ if (current_function_uses_only_leaf_regs)
+ {
+ int leaf_reg = LEAF_REG_REMAP (reg);
+ if (leaf_reg != -1)
+ reg = (unsigned) leaf_reg;
+ }
+#endif
+ gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
+ nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+
+ /* Simple, contiguous registers. */
+ if (regs == NULL_RTX)
+ {
+ size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+
+ loc_result = NULL;
+ while (nregs--)
+ {
+ dw_loc_descr_ref t;
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
+ STATUS_INITIALIZED);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ add_loc_descr (&loc_result, t);
+ add_loc_descr_op_piece (&loc_result, size);
+ ++reg;
+ }
+ return loc_result;
+ }
+
+ /* Now onto stupid register sets in non contiguous locations. */
+
+ gcc_assert (GET_CODE (regs) == PARALLEL);
+
+ size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+ loc_result = NULL;
+
+ for (i = 0; i < XVECLEN (regs, 0); ++i)
+ {
+ dw_loc_descr_ref t;
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
+ STATUS_INITIALIZED);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ add_loc_descr (&loc_result, t);
+ size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+ add_loc_descr_op_piece (&loc_result, size);
+ }
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (loc_result && initialized == STATUS_UNINITIALIZED)
+ add_loc_descr (&loc_result, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
+ /* APPLE LOCAL end track initialization status 4964532 */
+
+ return loc_result;
+}
+
+/* Return a location descriptor that designates a constant. */
+
+static dw_loc_descr_ref
+int_loc_descriptor (HOST_WIDE_INT i)
+{
+ enum dwarf_location_atom op;
+
+ /* Pick the smallest representation of a constant, rather than just
+ defaulting to the LEB encoding. */
+ if (i >= 0)
+ {
+ if (i <= 31)
+ op = DW_OP_lit0 + i;
+ else if (i <= 0xff)
+ op = DW_OP_const1u;
+ else if (i <= 0xffff)
+ op = DW_OP_const2u;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i <= 0xffffffff)
+ op = DW_OP_const4u;
+ else
+ op = DW_OP_constu;
+ }
+ else
+ {
+ if (i >= -0x80)
+ op = DW_OP_const1s;
+ else if (i >= -0x8000)
+ op = DW_OP_const2s;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i >= -0x80000000)
+ op = DW_OP_const4s;
+ else
+ op = DW_OP_consts;
+ }
+
+ return new_loc_descr (op, i, 0);
+}
+
+/* Return a location descriptor that designates a base+offset location. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+based_loc_descr (rtx reg, HOST_WIDE_INT offset,
+ enum var_init_status initialized)
+{
+ unsigned int regno;
+ dw_loc_descr_ref result;
+/* APPLE LOCAL end track initialization status 4964532 */
+
+ /* We only use "frame base" when we're sure we're talking about the
+ post-prologue local stack frame. We do this by *not* running
+ register elimination until this point, and recognizing the special
+ argument pointer and soft frame pointer rtx's. */
+ if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
+ {
+ rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+
+ if (elim != reg)
+ {
+ if (GET_CODE (elim) == PLUS)
+ {
+ offset += INTVAL (XEXP (elim, 1));
+ elim = XEXP (elim, 0);
+ }
+ /* APPLE LOCAL begin ARM prefer SP to FP */
+ /* Make sure we are using the same base register. */
+ gcc_assert (elim == frame_pointer_fb_offset_from);
+ /* APPLE LOCAL end ARM prefer SP to FP */
+ offset += frame_pointer_fb_offset;
+
+ return new_loc_descr (DW_OP_fbreg, offset, 0);
+ }
+ }
+
+ regno = dbx_reg_number (reg);
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (regno <= 31)
+ result = new_loc_descr (DW_OP_breg0 + regno, offset, 0);
+ else
+ result = new_loc_descr (DW_OP_bregx, regno, offset);
+
+ if (initialized == STATUS_UNINITIALIZED)
+ add_loc_descr (&result, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
+
+ return result;
+ /* APPLE LOCAL end track initialization status 4964532 */
+}
+
+/* Return true if this RTL expression describes a base+offset calculation. */
+
+static inline int
+is_based_loc (rtx rtl)
+{
+ return (GET_CODE (rtl) == PLUS
+ && ((REG_P (XEXP (rtl, 0))
+ && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
+ && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
+}
+
+/* The following routine converts the RTL for a variable or parameter
+ (resident in memory) into an equivalent Dwarf representation of a
+ mechanism for getting the address of that same variable onto the top of a
+ hypothetical "address evaluation" stack.
+
+ When creating memory location descriptors, we are effectively transforming
+ the RTL for a memory-resident object into its Dwarf postfix expression
+ equivalent. This routine recursively descends an RTL tree, turning
+ it into Dwarf postfix code as it goes.
+
+ MODE is the mode of the memory reference, needed to handle some
+ autoincrement addressing modes.
+
+ CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
+ location list for RTL.
+
+ Return 0 if we can't represent the location. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+mem_loc_descriptor (rtx rtl, enum machine_mode mode,
+ enum var_init_status initialized)
+/* APPLE LOCAL end track initialization status 4964532 */
+{
+ dw_loc_descr_ref mem_loc_result = NULL;
+ enum dwarf_location_atom op;
+
+ /* Note that for a dynamically sized array, the location we will generate a
+ description of here will be the lowest numbered location which is
+ actually within the array. That's *not* necessarily the same as the
+ zeroth element of the array. */
+
+ rtl = targetm.delegitimize_address (rtl);
+
+ switch (GET_CODE (rtl))
+ {
+ case POST_INC:
+ case POST_DEC:
+ case POST_MODIFY:
+ /* POST_INC and POST_DEC can be handled just like a SUBREG. So we
+ just fall into the SUBREG code. */
+
+ /* ... fall through ... */
+
+ case SUBREG:
+ /* The case of a subreg may arise when we have a local (register)
+ variable or a formal (register) parameter which doesn't quite fill
+ up an entire register. For now, just assume that it is
+ legitimate to make the Dwarf info refer to the whole register which
+ contains the given subreg. */
+ rtl = XEXP (rtl, 0);
+
+ /* ... fall through ... */
+
+ case REG:
+ /* Whenever a register number forms a part of the description of the
+ method for calculating the (dynamic) address of a memory resident
+ object, DWARF rules require the register number be referred to as
+ a "base register". This distinction is not based in any way upon
+ what category of register the hardware believes the given register
+ belongs to. This is strictly DWARF terminology we're dealing with
+ here. Note that in cases where the location of a memory-resident
+ data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+ OP_CONST (0)) the actual DWARF location descriptor that we generate
+ may just be OP_BASEREG (basereg). This may look deceptively like
+ the object in question was allocated to a register (rather than in
+ memory) so DWARF consumers need to be aware of the subtle
+ distinction between OP_REG and OP_BASEREG. */
+ if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
+ /* APPLE LOCAL track initialization status 4964532 */
+ mem_loc_result = based_loc_descr (rtl, 0, STATUS_INITIALIZED);
+ break;
+
+ case MEM:
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+ STATUS_INITIALIZED);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ if (mem_loc_result != 0)
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+ break;
+
+ case LO_SUM:
+ rtl = XEXP (rtl, 1);
+
+ /* ... fall through ... */
+
+ case LABEL_REF:
+ /* Some ports can transform a symbol ref into a label ref, because
+ the symbol ref is too far away and has to be dumped into a constant
+ pool. */
+ 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))
+ {
+ bool marked;
+ rtx tmp = get_pool_constant_mark (rtl, &marked);
+
+ if (GET_CODE (tmp) == SYMBOL_REF)
+ {
+ rtl = tmp;
+ if (CONSTANT_POOL_ADDRESS_P (tmp))
+ get_pool_constant_mark (tmp, &marked);
+ else
+ marked = true;
+ }
+
+ /* If all references to this pool constant were optimized away,
+ it was not output and thus we can't represent it.
+ FIXME: might try to use DW_OP_const_value here, though
+ DW_OP_piece complicates it. */
+ if (!marked)
+ return 0;
+ }
+
+ mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+ mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+ break;
+
+ case PRE_MODIFY:
+ /* Extract the PLUS expression nested inside and fall into
+ PLUS code below. */
+ rtl = XEXP (rtl, 1);
+ goto plus;
+
+ case PRE_INC:
+ case PRE_DEC:
+ /* Turn these into a PLUS expression and fall into the PLUS code
+ below. */
+ rtl = gen_rtx_PLUS (word_mode, XEXP (rtl, 0),
+ GEN_INT (GET_CODE (rtl) == PRE_INC
+ ? GET_MODE_UNIT_SIZE (mode)
+ : -GET_MODE_UNIT_SIZE (mode)));
+
+ /* ... fall through ... */
+
+ case PLUS:
+ plus:
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (is_based_loc (rtl))
+ mem_loc_result = based_loc_descr (XEXP (rtl, 0),
+ INTVAL (XEXP (rtl, 1)),
+ STATUS_INITIALIZED);
+ else
+ {
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ STATUS_INITIALIZED);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ if (mem_loc_result == 0)
+ break;
+
+ if (GET_CODE (XEXP (rtl, 1)) == CONST_INT
+ && INTVAL (XEXP (rtl, 1)) >= 0)
+ add_loc_descr (&mem_loc_result,
+ new_loc_descr (DW_OP_plus_uconst,
+ INTVAL (XEXP (rtl, 1)), 0));
+ else
+ {
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ add_loc_descr (&mem_loc_result,
+ mem_loc_descriptor (XEXP (rtl, 1), mode,
+ STATUS_INITIALIZED));
+ /* APPLE LOCAL end track initialization status 4964532 */
+ add_loc_descr (&mem_loc_result,
+ new_loc_descr (DW_OP_plus, 0, 0));
+ }
+ }
+ break;
+
+ /* If a pseudo-reg is optimized away, it is possible for it to
+ be replaced with a MEM containing a multiply or shift. */
+ case MULT:
+ op = DW_OP_mul;
+ goto do_binop;
+
+ case ASHIFT:
+ op = DW_OP_shl;
+ goto do_binop;
+
+ case ASHIFTRT:
+ op = DW_OP_shra;
+ goto do_binop;
+
+ case LSHIFTRT:
+ op = DW_OP_shr;
+ goto do_binop;
+
+ do_binop:
+ {
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+ STATUS_INITIALIZED);
+ dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+ STATUS_INITIALIZED);
+ /* APPLE LOCAL end track initialization status 4964532 */
+
+ if (op0 == 0 || op1 == 0)
+ break;
+
+ mem_loc_result = op0;
+ add_loc_descr (&mem_loc_result, op1);
+ add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
+ break;
+ }
+
+ case CONST_INT:
+ mem_loc_result = int_loc_descriptor (INTVAL (rtl));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (mem_loc_result && initialized == STATUS_UNINITIALIZED)
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_APPLE_uninit, 0,
+ 0));
+ /* APPLE LOCAL end track initialization status 4964532 */
+
+ return mem_loc_result;
+}
+
+/* Return a descriptor that describes the concatenation of two locations.
+ This is typically a complex variable. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
+{
+ dw_loc_descr_ref cc_loc_result = NULL;
+ dw_loc_descr_ref x0_ref = loc_descriptor (x0, STATUS_INITIALIZED);
+ dw_loc_descr_ref x1_ref = loc_descriptor (x1, STATUS_INITIALIZED);
+/* APPLE LOCAL end track initialization status 4964532 */
+
+ if (x0_ref == 0 || x1_ref == 0)
+ return 0;
+
+ cc_loc_result = x0_ref;
+ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x0)));
+
+ add_loc_descr (&cc_loc_result, x1_ref);
+ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (initialized == STATUS_UNINITIALIZED)
+ add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_APPLE_uninit, 0, 0));
+ /* APPLE LOCAL end track initialization status 4964532 */
+
+ return cc_loc_result;
+}
+
+/* Output a proper Dwarf location descriptor for a variable or parameter
+ which is either allocated in a register or in a memory location. For a
+ register, we just generate an OP_REG and the register number. For a
+ memory location we provide a Dwarf postfix expression describing how to
+ generate the (dynamic) address of the object onto the address stack.
+
+ If we don't know how to describe it, return 0. */
+
+/* APPLE LOCAL begin track initialization status 4964532 */
+static dw_loc_descr_ref
+loc_descriptor (rtx rtl, enum var_init_status initialized)
+/* APPLE LOCAL end track initialization status 4964532 */
+{
+ dw_loc_descr_ref loc_result = NULL;
+
+ switch (GET_CODE (rtl))
+ {
+ case SUBREG:
+ /* The case of a subreg may arise when we have a local (register)
+ variable or a formal (register) parameter which doesn't quite fill
+ up an entire register. For now, just assume that it is
+ legitimate to make the Dwarf info refer to the whole register which
+ contains the given subreg. */
+ rtl = SUBREG_REG (rtl);
+
+ /* ... fall through ... */
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ case REG:
+ loc_result = reg_loc_descriptor (rtl, initialized);
+ break;
+
+ case MEM:
+ loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+ initialized);
+ break;
+
+ case CONCAT:
+ loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
+ initialized);
+ break;
+
+ case VAR_LOCATION:
+ /* Single part. */
+ if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+ {
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
+ break;
+ }
+ /* APPLE LOCAL end track initialization status 4964532 */
+
+ rtl = XEXP (rtl, 1);
+ /* FALLTHRU */
+
+ case PARALLEL:
+ {
+ rtvec par_elems = XVEC (rtl, 0);
+ int num_elem = GET_NUM_ELEM (par_elems);
+ enum machine_mode mode;
+ int i;
+
+ /* Create the first one, so we have something to add to. */
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
+ initialized);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+ add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+ for (i = 1; i < num_elem; i++)
+ {
+ dw_loc_descr_ref temp;
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
+ initialized);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ add_loc_descr (&loc_result, temp);
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
+ add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
+ }
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return loc_result;
+}
+
+/* Similar, but generate the descriptor from trees instead of rtl. This comes
+ up particularly with variable length arrays. WANT_ADDRESS is 2 if this is
+ a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a
+ top-level invocation, and we require the address of LOC; is 0 if we require
+ the value of LOC. */
+
+static dw_loc_descr_ref
+loc_descriptor_from_tree_1 (tree loc, int want_address)
+{
+ dw_loc_descr_ref ret, ret1;
+ int have_address = 0;
+ enum dwarf_location_atom op;
+
+ /* ??? Most of the time we do not take proper care for sign/zero
+ extending the values properly. Hopefully this won't be a real
+ problem... */
+
+ switch (TREE_CODE (loc))
+ {
+ case ERROR_MARK:
+ return 0;
+
+ case PLACEHOLDER_EXPR:
+ /* This case involves extracting fields from an object to determine the
+ position of other fields. We don't try to encode this here. The
+ only user of this is Ada, which encodes the needed information using
+ the names of types. */
+ return 0;
+
+ case CALL_EXPR:
+ return 0;
+
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ /* There are no opcodes for these operations. */
+ return 0;
+
+ case ADDR_EXPR:
+ /* If we already want an address, there's nothing we can do. */
+ if (want_address)
+ return 0;
+
+ /* Otherwise, process the argument and look for the address. */
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
+
+ case VAR_DECL:
+ if (DECL_THREAD_LOCAL_P (loc))
+ {
+ rtx rtl;
+
+ /* If this is not defined, we have no way to emit the data. */
+ if (!targetm.asm_out.output_dwarf_dtprel)
+ return 0;
+
+ /* The way DW_OP_GNU_push_tls_address is specified, we can only
+ look up addresses of objects in the current module. */
+ if (DECL_EXTERNAL (loc))
+ return 0;
+
+ rtl = rtl_for_decl_location (loc);
+ if (rtl == NULL_RTX)
+ return 0;
+
+ if (!MEM_P (rtl))
+ return 0;
+ rtl = XEXP (rtl, 0);
+ if (! CONSTANT_P (rtl))
+ return 0;
+
+ ret = new_loc_descr (INTERNAL_DW_OP_tls_addr, 0, 0);
+ ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ ret->dw_loc_oprnd1.v.val_addr = rtl;
+
+ ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+ add_loc_descr (&ret, ret1);
+
+ have_address = 1;
+ break;
+ }
+ /* FALLTHRU */
+
+ case PARM_DECL:
+ if (DECL_HAS_VALUE_EXPR_P (loc))
+ return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc),
+ want_address);
+ /* FALLTHRU */
+
+ case RESULT_DECL:
+ case FUNCTION_DECL:
+ {
+ rtx rtl = rtl_for_decl_location (loc);
+
+ if (rtl == NULL_RTX)
+ return 0;
+ else if (GET_CODE (rtl) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (rtl);
+ if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+ val &= GET_MODE_MASK (DECL_MODE (loc));
+ ret = int_loc_descriptor (val);
+ }
+ else if (GET_CODE (rtl) == CONST_STRING)
+ return 0;
+ else if (CONSTANT_P (rtl))
+ {
+ ret = new_loc_descr (DW_OP_addr, 0, 0);
+ ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ ret->dw_loc_oprnd1.v.val_addr = rtl;
+ }
+ else
+ {
+ enum machine_mode mode;
+
+ /* Certain constructs can only be represented at top-level. */
+ if (want_address == 2)
+ /* APPLE LOCAL track initialization status 4964532 */
+ return loc_descriptor (rtl, STATUS_INITIALIZED);
+
+ mode = GET_MODE (rtl);
+ if (MEM_P (rtl))
+ {
+ rtl = XEXP (rtl, 0);
+ have_address = 1;
+ }
+ /* APPLE LOCAL track initialization status 4964532 */
+ ret = mem_loc_descriptor (rtl, mode, STATUS_INITIALIZED);
+ }
+ }
+ break;
+
+ case INDIRECT_REF:
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ have_address = 1;
+ break;
+
+ case COMPOUND_EXPR:
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address);
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
+ case SAVE_EXPR:
+ case MODIFY_EXPR:
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
+
+ case COMPONENT_REF:
+ case BIT_FIELD_REF:
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ {
+ tree obj, offset;
+ HOST_WIDE_INT bitsize, bitpos, bytepos;
+ enum machine_mode mode;
+ int volatilep;
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+
+ obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+
+ if (obj == loc)
+ return 0;
+
+ ret = loc_descriptor_from_tree_1 (obj, 1);
+ if (ret == 0
+ || bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
+ return 0;
+
+ if (offset != NULL_TREE)
+ {
+ /* Variable offset. */
+ add_loc_descr (&ret, loc_descriptor_from_tree_1 (offset, 0));
+ add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+ }
+
+ bytepos = bitpos / BITS_PER_UNIT;
+ if (bytepos > 0)
+ add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
+ else if (bytepos < 0)
+ {
+ add_loc_descr (&ret, int_loc_descriptor (bytepos));
+ add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+ }
+
+ have_address = 1;
+ break;
+ }
+
+ case INTEGER_CST:
+ if (host_integerp (loc, 0))
+ ret = int_loc_descriptor (tree_low_cst (loc, 0));
+ else
+ return 0;
+ break;
+
+ case CONSTRUCTOR:
+ {
+ /* Get an RTL for this, if something has been emitted. */
+ rtx rtl = lookup_constant_def (loc);
+ enum machine_mode mode;
+
+ if (!rtl || !MEM_P (rtl))
+ return 0;
+ mode = GET_MODE (rtl);
+ rtl = XEXP (rtl, 0);
+ /* APPLE LOCAL track initialization status 4964532 */
+ ret = mem_loc_descriptor (rtl, mode, STATUS_INITIALIZED);
+ have_address = 1;
+ break;
+ }
+
+ case TRUTH_AND_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case BIT_AND_EXPR:
+ op = DW_OP_and;
+ goto do_binop;
+
+ case TRUTH_XOR_EXPR:
+ case BIT_XOR_EXPR:
+ op = DW_OP_xor;
+ goto do_binop;
+
+ case TRUTH_OR_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case BIT_IOR_EXPR:
+ op = DW_OP_or;
+ goto do_binop;
+
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case TRUNC_DIV_EXPR:
+ op = DW_OP_div;
+ goto do_binop;
+
+ case MINUS_EXPR:
+ op = DW_OP_minus;
+ goto do_binop;
+
+ case FLOOR_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+ case TRUNC_MOD_EXPR:
+ op = DW_OP_mod;
+ goto do_binop;
+
+ case MULT_EXPR:
+ op = DW_OP_mul;
+ goto do_binop;
+
+ case LSHIFT_EXPR:
+ op = DW_OP_shl;
+ goto do_binop;
+
+ case RSHIFT_EXPR:
+ op = (TYPE_UNSIGNED (TREE_TYPE (loc)) ? DW_OP_shr : DW_OP_shra);
+ goto do_binop;
+
+ case PLUS_EXPR:
+ if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
+ && host_integerp (TREE_OPERAND (loc, 1), 0))
+ {
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ if (ret == 0)
+ return 0;
+
+ add_loc_descr (&ret,
+ new_loc_descr (DW_OP_plus_uconst,
+ tree_low_cst (TREE_OPERAND (loc, 1),
+ 0),
+ 0));
+ break;
+ }
+
+ op = DW_OP_plus;
+ goto do_binop;
+
+ case LE_EXPR:
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+ return 0;
+
+ op = DW_OP_le;
+ goto do_binop;
+
+ case GE_EXPR:
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+ return 0;
+
+ op = DW_OP_ge;
+ goto do_binop;
+
+ case LT_EXPR:
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+ return 0;
+
+ op = DW_OP_lt;
+ goto do_binop;
+
+ case GT_EXPR:
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+ return 0;
+
+ op = DW_OP_gt;
+ goto do_binop;
+
+ case EQ_EXPR:
+ op = DW_OP_eq;
+ goto do_binop;
+
+ case NE_EXPR:
+ op = DW_OP_ne;
+ goto do_binop;
+
+ do_binop:
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
+ if (ret == 0 || ret1 == 0)
+ return 0;
+
+ add_loc_descr (&ret, ret1);
+ add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+ break;
+
+ case TRUTH_NOT_EXPR:
+ case BIT_NOT_EXPR:
+ op = DW_OP_not;
+ goto do_unop;
+
+ case ABS_EXPR:
+ op = DW_OP_abs;
+ goto do_unop;
+
+ case NEGATE_EXPR:
+ op = DW_OP_neg;
+ goto do_unop;
+
+ do_unop:
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ if (ret == 0)
+ return 0;
+
+ add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+ break;
+
+ case MIN_EXPR:
+ case MAX_EXPR:
+ {
+ const enum tree_code code =
+ TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
+
+ loc = build3 (COND_EXPR, TREE_TYPE (loc),
+ build2 (code, integer_type_node,
+ TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
+ TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+ }
+
+ /* ... fall through ... */
+
+ case COND_EXPR:
+ {
+ dw_loc_descr_ref lhs
+ = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
+ dw_loc_descr_ref rhs
+ = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0);
+ dw_loc_descr_ref bra_node, jump_node, tmp;
+
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ if (ret == 0 || lhs == 0 || rhs == 0)
+ return 0;
+
+ bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+ add_loc_descr (&ret, bra_node);
+
+ add_loc_descr (&ret, rhs);
+ jump_node = new_loc_descr (DW_OP_skip, 0, 0);
+ add_loc_descr (&ret, jump_node);
+
+ add_loc_descr (&ret, lhs);
+ bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ bra_node->dw_loc_oprnd1.v.val_loc = lhs;
+
+ /* ??? Need a node to point the skip at. Use a nop. */
+ tmp = new_loc_descr (DW_OP_nop, 0, 0);
+ add_loc_descr (&ret, tmp);
+ jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+ jump_node->dw_loc_oprnd1.v.val_loc = tmp;
+ }
+ break;
+
+ case FIX_TRUNC_EXPR:
+ case FIX_CEIL_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ return 0;
+
+ default:
+ /* Leave front-end specific codes as simply unknown. This comes
+ up, for instance, with the C STMT_EXPR. */
+ if ((unsigned int) TREE_CODE (loc)
+ >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
+ return 0;
+
+#ifdef ENABLE_CHECKING
+ /* Otherwise this is a generic code; we should just lists all of
+ these explicitly. We forgot one. */
+ gcc_unreachable ();
+#else
+ /* In a release build, we want to degrade gracefully: better to
+ generate incomplete debugging information than to crash. */
+ return NULL;
+#endif
+ }
+
+ /* Show if we can't fill the request for an address. */
+ if (want_address && !have_address)
+ return 0;
+
+ /* If we've got an address and don't want one, dereference. */
+ if (!want_address && have_address && ret)
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
+
+ if (size > DWARF2_ADDR_SIZE || size == -1)
+ return 0;
+ else if (size == DWARF2_ADDR_SIZE)
+ op = DW_OP_deref;
+ else
+ op = DW_OP_deref_size;
+
+ add_loc_descr (&ret, new_loc_descr (op, size, 0));
+ }
+
+ return ret;
+}
+
+static inline dw_loc_descr_ref
+loc_descriptor_from_tree (tree loc)
+{
+ return loc_descriptor_from_tree_1 (loc, 2);
+}
+
+/* Given a value, round it up to the lowest multiple of `boundary'
+ which is not less than the value itself. */
+
+static inline HOST_WIDE_INT
+ceiling (HOST_WIDE_INT value, unsigned int boundary)
+{
+ return (((value + boundary - 1) / boundary) * boundary);
+}
+
+/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
+ pointer to the declared type for the relevant field variable, or return
+ `integer_type_node' if the given node turns out to be an
+ ERROR_MARK node. */
+
+static inline tree
+field_type (tree decl)
+{
+ tree type;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return integer_type_node;
+
+ type = DECL_BIT_FIELD_TYPE (decl);
+ if (type == NULL_TREE)
+ type = TREE_TYPE (decl);
+
+ return type;
+}
+
+/* Given a pointer to a tree node, return the alignment in bits for
+ it, or else return BITS_PER_WORD if the node actually turns out to
+ be an ERROR_MARK node. */
+
+static inline unsigned
+simple_type_align_in_bits (tree type)
+{
+ return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
+}
+
+static inline unsigned
+simple_decl_align_in_bits (tree decl)
+{
+ return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
+}
+
+/* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
+ lowest addressed byte of the "containing object" for the given FIELD_DECL,
+ or return 0 if we are unable to determine what that offset is, either
+ because the argument turns out to be a pointer to an ERROR_MARK node, or
+ because the offset is actually variable. (We can't handle the latter case
+ just yet). */
+
+static HOST_WIDE_INT
+field_byte_offset (tree decl)
+{
+ unsigned int type_align_in_bits;
+ unsigned int decl_align_in_bits;
+ unsigned HOST_WIDE_INT type_size_in_bits;
+ HOST_WIDE_INT object_offset_in_bits;
+ tree type;
+ tree field_size_tree;
+ HOST_WIDE_INT bitpos_int;
+ HOST_WIDE_INT deepest_bitpos;
+ unsigned HOST_WIDE_INT field_size_in_bits;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return 0;
+
+ gcc_assert (TREE_CODE (decl) == FIELD_DECL);
+
+ type = field_type (decl);
+ field_size_tree = DECL_SIZE (decl);
+
+ /* The size could be unspecified if there was an error, or for
+ a flexible array member. */
+ if (! field_size_tree)
+ field_size_tree = bitsize_zero_node;
+
+ /* We cannot yet cope with fields whose positions are variable, so
+ for now, when we see such things, we simply return 0. Someday, we may
+ be able to handle such cases, but it will be damn difficult. */
+ if (! host_integerp (bit_position (decl), 0))
+ return 0;
+
+ bitpos_int = int_bit_position (decl);
+
+ /* If we don't know the size of the field, pretend it's a full word. */
+ if (host_integerp (field_size_tree, 1))
+ field_size_in_bits = tree_low_cst (field_size_tree, 1);
+ else
+ field_size_in_bits = BITS_PER_WORD;
+
+ type_size_in_bits = simple_type_size_in_bits (type);
+ type_align_in_bits = simple_type_align_in_bits (type);
+ decl_align_in_bits = simple_decl_align_in_bits (decl);
+
+ /* The GCC front-end doesn't make any attempt to keep track of the starting
+ bit offset (relative to the start of the containing structure type) of the
+ hypothetical "containing object" for a bit-field. Thus, when computing
+ the byte offset value for the start of the "containing object" of a
+ bit-field, we must deduce this information on our own. This can be rather
+ tricky to do in some cases. For example, handling the following structure
+ type definition when compiling for an i386/i486 target (which only aligns
+ long long's to 32-bit boundaries) can be very tricky:
+
+ struct S { int field1; long long field2:31; };
+
+ Fortunately, there is a simple rule-of-thumb which can be used in such
+ cases. When compiling for an i386/i486, GCC will allocate 8 bytes for the
+ structure shown above. It decides to do this based upon one simple rule
+ for bit-field allocation. GCC allocates each "containing object" for each
+ bit-field at the first (i.e. lowest addressed) legitimate alignment
+ boundary (based upon the required minimum alignment for the declared type
+ of the field) which it can possibly use, subject to the condition that
+ there is still enough available space remaining in the containing object
+ (when allocated at the selected point) to fully accommodate all of the
+ bits of the bit-field itself.
+
+ This simple rule makes it obvious why GCC allocates 8 bytes for each
+ object of the structure type shown above. When looking for a place to
+ allocate the "containing object" for `field2', the compiler simply tries
+ to allocate a 64-bit "containing object" at each successive 32-bit
+ boundary (starting at zero) until it finds a place to allocate that 64-
+ bit field such that at least 31 contiguous (and previously unallocated)
+ bits remain within that selected 64 bit field. (As it turns out, for the
+ example above, the compiler finds it is OK to allocate the "containing
+ object" 64-bit field at bit-offset zero within the structure type.)
+
+ Here we attempt to work backwards from the limited set of facts we're
+ given, and we try to deduce from those facts, where GCC must have believed
+ that the containing object started (within the structure type). The value
+ we deduce is then used (by the callers of this routine) to generate
+ DW_AT_location and DW_AT_bit_offset attributes for fields (both bit-fields
+ and, in the case of DW_AT_location, regular fields as well). */
+
+ /* Figure out the bit-distance from the start of the structure to the
+ "deepest" bit of the bit-field. */
+ deepest_bitpos = bitpos_int + field_size_in_bits;
+
+ /* This is the tricky part. Use some fancy footwork to deduce where the
+ lowest addressed bit of the containing object must be. */
+ object_offset_in_bits = deepest_bitpos - type_size_in_bits;
+
+ /* Round up to type_align by default. This works best for bitfields. */
+ object_offset_in_bits += type_align_in_bits - 1;
+ object_offset_in_bits /= type_align_in_bits;
+ object_offset_in_bits *= type_align_in_bits;
+
+ if (object_offset_in_bits > bitpos_int)
+ {
+ /* Sigh, the decl must be packed. */
+ object_offset_in_bits = deepest_bitpos - type_size_in_bits;
+
+ /* Round up to decl_align instead. */
+ object_offset_in_bits += decl_align_in_bits - 1;
+ object_offset_in_bits /= decl_align_in_bits;
+ object_offset_in_bits *= decl_align_in_bits;
+ }
+
+ return object_offset_in_bits / BITS_PER_UNIT;
+}
+
+/* The following routines define various Dwarf attributes and any data
+ associated with them. */
+
+/* Add a location description attribute value to a DIE.
+
+ This emits location attributes suitable for whole variables and
+ whole parameters. Note that the location attributes for struct fields are
+ generated by the routine `data_member_location_attribute' below. */
+
+static inline void
+add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
+ dw_loc_descr_ref descr)
+{
+ if (descr != 0)
+ add_AT_loc (die, attr_kind, descr);
+}
+
+/* Attach the specialized form of location attribute used for data members of
+ struct and union types. In the special case of a FIELD_DECL node which
+ represents a bit-field, the "offset" part of this special location
+ descriptor must indicate the distance in bytes from the lowest-addressed
+ byte of the containing struct or union type to the lowest-addressed byte of
+ the "containing object" for the bit-field. (See the `field_byte_offset'
+ function above).
+
+ For any given bit-field, the "containing object" is a hypothetical object
+ (of some integral or enum type) within which the given bit-field lives. The
+ type of this hypothetical "containing object" is always the same as the
+ declared type of the individual bit-field itself (for GCC anyway... the
+ DWARF spec doesn't actually mandate this). Note that it is the size (in
+ bytes) of the hypothetical "containing object" which will be given in the
+ DW_AT_byte_size attribute for this bit-field. (See the
+ `byte_size_attribute' function below.) It is also used when calculating the
+ value of the DW_AT_bit_offset attribute. (See the `bit_offset_attribute'
+ function below.) */
+
+static void
+add_data_member_location_attribute (dw_die_ref die, tree decl)
+{
+ HOST_WIDE_INT offset;
+ dw_loc_descr_ref loc_descr = 0;
+
+ if (TREE_CODE (decl) == TREE_BINFO)
+ {
+ /* We're working on the TAG_inheritance for a base class. */
+ if (BINFO_VIRTUAL_P (decl) && is_cxx ())
+ {
+ /* For C++ virtual bases we can't just use BINFO_OFFSET, as they
+ aren't at a fixed offset from all (sub)objects of the same
+ type. We need to extract the appropriate offset from our
+ vtable. The following dwarf expression means
+
+ BaseAddr = ObAddr + *((*ObAddr) - Offset)
+
+ This is specific to the V3 ABI, of course. */
+
+ dw_loc_descr_ref tmp;
+
+ /* Make a copy of the object address. */
+ tmp = new_loc_descr (DW_OP_dup, 0, 0);
+ add_loc_descr (&loc_descr, tmp);
+
+ /* Extract the vtable address. */
+ tmp = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (&loc_descr, tmp);
+
+ /* Calculate the address of the offset. */
+ offset = tree_low_cst (BINFO_VPTR_FIELD (decl), 0);
+ gcc_assert (offset < 0);
+
+ tmp = int_loc_descriptor (-offset);
+ add_loc_descr (&loc_descr, tmp);
+ tmp = new_loc_descr (DW_OP_minus, 0, 0);
+ add_loc_descr (&loc_descr, tmp);
+
+ /* Extract the offset. */
+ tmp = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (&loc_descr, tmp);
+
+ /* Add it to the object address. */
+ tmp = new_loc_descr (DW_OP_plus, 0, 0);
+ add_loc_descr (&loc_descr, tmp);
+ }
+ else
+ offset = tree_low_cst (BINFO_OFFSET (decl), 0);
+ }
+ else
+ offset = field_byte_offset (decl);
+
+ if (! loc_descr)
+ {
+ enum dwarf_location_atom op;
+
+ /* The DWARF2 standard says that we should assume that the structure
+ address is already on the stack, so we can specify a structure field
+ address by using DW_OP_plus_uconst. */
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
+ operator correctly. It works only if we leave the offset on the
+ stack. */
+ 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);
+}
+
+/* Writes integer values to dw_vec_const array. */
+
+static void
+insert_int (HOST_WIDE_INT val, unsigned int size, unsigned char *dest)
+{
+ while (size != 0)
+ {
+ *dest++ = val & 0xff;
+ val >>= 8;
+ --size;
+ }
+}
+
+/* Reads integers from dw_vec_const array. Inverse of insert_int. */
+
+static HOST_WIDE_INT
+extract_int (const unsigned char *src, unsigned int size)
+{
+ HOST_WIDE_INT val = 0;
+
+ src += size;
+ while (size != 0)
+ {
+ val <<= 8;
+ val |= *--src & 0xff;
+ --size;
+ }
+ return val;
+}
+
+/* Writes floating point values to dw_vec_const array. */
+
+static void
+insert_float (rtx rtl, unsigned char *array)
+{
+ REAL_VALUE_TYPE rv;
+ long val[4];
+ int i;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
+ real_to_target (val, &rv, GET_MODE (rtl));
+
+ /* real_to_target puts 32-bit pieces in each long. Pack them. */
+ for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
+ {
+ insert_int (val[i], 4, array);
+ array += 4;
+ }
+}
+
+/* Attach a DW_AT_const_value attribute for a variable or a parameter which
+ does not have a "location" either in memory or in a register. These
+ things can arise in GNU C when a constant is passed as an actual parameter
+ to an inlined function. They can also arise in C++ where declared
+ constants do not necessarily get memory "homes". */
+
+static void
+add_const_value_attribute (dw_die_ref die, rtx rtl)
+{
+ switch (GET_CODE (rtl))
+ {
+ case CONST_INT:
+ {
+ HOST_WIDE_INT val = INTVAL (rtl);
+
+ if (val < 0)
+ add_AT_int (die, DW_AT_const_value, val);
+ else
+ add_AT_unsigned (die, DW_AT_const_value, (unsigned HOST_WIDE_INT) val);
+ }
+ break;
+
+ case CONST_DOUBLE:
+ /* Note that a CONST_DOUBLE rtx could represent either an integer or a
+ floating-point constant. A CONST_DOUBLE is used whenever the
+ constant requires more than one word in order to be adequately
+ represented. We output CONST_DOUBLEs as blocks. */
+ {
+ enum machine_mode mode = GET_MODE (rtl);
+
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ unsigned int length = GET_MODE_SIZE (mode);
+ unsigned char *array = ggc_alloc (length);
+
+ insert_float (rtl, array);
+ add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
+ }
+ else
+ {
+ /* ??? We really should be using HOST_WIDE_INT throughout. */
+ gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
+
+ add_AT_long_long (die, DW_AT_const_value,
+ CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+ }
+ }
+ break;
+
+ case CONST_VECTOR:
+ {
+ enum machine_mode mode = GET_MODE (rtl);
+ unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
+ unsigned int length = CONST_VECTOR_NUNITS (rtl);
+ unsigned char *array = ggc_alloc (length * elt_size);
+ unsigned int i;
+ unsigned char *p;
+
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_VECTOR_INT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ HOST_WIDE_INT lo, hi;
+
+ switch (GET_CODE (elt))
+ {
+ case CONST_INT:
+ lo = INTVAL (elt);
+ hi = -(lo < 0);
+ break;
+
+ case CONST_DOUBLE:
+ lo = CONST_DOUBLE_LOW (elt);
+ hi = CONST_DOUBLE_HIGH (elt);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (elt_size <= sizeof (HOST_WIDE_INT))
+ insert_int (lo, elt_size, p);
+ else
+ {
+ unsigned char *p0 = p;
+ unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+ gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+ if (WORDS_BIG_ENDIAN)
+ {
+ p0 = p1;
+ p1 = p;
+ }
+ insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+ insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+ }
+ }
+ break;
+
+ case MODE_VECTOR_FLOAT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ insert_float (elt, p);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
+ }
+ break;
+
+ case CONST_STRING:
+ add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
+ break;
+
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST:
+ add_AT_addr (die, DW_AT_const_value, rtl);
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+ break;
+
+ case PLUS:
+ /* In cases where an inlined instance of an inline function is passed
+ the address of an `auto' variable (which is local to the caller) we
+ can get a situation where the DECL_RTL of the artificial local
+ variable (for the inlining) which acts as a stand-in for the
+ corresponding formal parameter (of the inline function) will look
+ like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
+ exactly a compile-time constant expression, but it isn't the address
+ of the (artificial) local variable either. Rather, it represents the
+ *value* which the artificial local variable always has during its
+ lifetime. We currently have no way to represent such quasi-constant
+ values in Dwarf, so for now we just punt and generate nothing. */
+ break;
+
+ default:
+ /* No other kinds of rtx should be possible here. */
+ gcc_unreachable ();
+ }
+
+}
+
+/* Determine whether the evaluation of EXPR references any variables
+ or functions which aren't otherwise used (and therefore may not be
+ output). */
+static tree
+reference_to_unused (tree * tp, int * walk_subtrees,
+ void * data ATTRIBUTE_UNUSED)
+{
+ if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
+ *walk_subtrees = 0;
+
+ if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
+ && ! TREE_ASM_WRITTEN (*tp))
+ return *tp;
+ else if (!flag_unit_at_a_time)
+ return NULL_TREE;
+ else if (!cgraph_global_info_ready
+ && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
+ gcc_unreachable ();
+ else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
+ {
+ struct cgraph_varpool_node *node = cgraph_varpool_node (*tp);
+ if (!node->needed)
+ return *tp;
+ }
+ else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
+ && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
+ {
+ struct cgraph_node *node = cgraph_node (*tp);
+ if (!node->output)
+ return *tp;
+ }
+
+ return NULL_TREE;
+}
+
+/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
+ for use in a later add_const_value_attribute call. */
+
+static rtx
+rtl_for_decl_init (tree init, tree type)
+{
+ rtx rtl = NULL_RTX;
+
+ /* If a variable is initialized with a string constant without embedded
+ zeros, build CONST_STRING. */
+ if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree enttype = TREE_TYPE (type);
+ tree domain = TYPE_DOMAIN (type);
+ enum machine_mode mode = TYPE_MODE (enttype);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
+ && domain
+ && integer_zerop (TYPE_MIN_VALUE (domain))
+ && compare_tree_int (TYPE_MAX_VALUE (domain),
+ TREE_STRING_LENGTH (init) - 1) == 0
+ && ((size_t) TREE_STRING_LENGTH (init)
+ == strlen (TREE_STRING_POINTER (init)) + 1))
+ rtl = gen_rtx_CONST_STRING (VOIDmode,
+ ggc_strdup (TREE_STRING_POINTER (init)));
+ }
+ /* Other aggregates, and complex values, could be represented using
+ CONCAT: FIXME! */
+ else if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
+ ;
+ /* Vectors only work if their mode is supported by the target.
+ FIXME: generic vectors ought to work too. */
+ else if (TREE_CODE (type) == VECTOR_TYPE && TYPE_MODE (type) == BLKmode)
+ ;
+ /* If the initializer is something that we know will expand into an
+ immediate RTL constant, expand it now. We must be careful not to
+ reference variables which won't be output. */
+ else if (initializer_constant_valid_p (init, type)
+ && ! walk_tree (&init, reference_to_unused, NULL, NULL))
+ {
+ rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+
+ /* If expand_expr returns a MEM, it wasn't immediate. */
+ gcc_assert (!rtl || !MEM_P (rtl));
+ }
+
+ return rtl;
+}
+
+/* Generate RTL for the variable DECL to represent its location. */
+
+static rtx
+rtl_for_decl_location (tree decl)
+{
+ rtx rtl;
+
+ /* Here we have to decide where we are going to say the parameter "lives"
+ (as far as the debugger is concerned). We only have a couple of
+ choices. GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
+
+ DECL_RTL normally indicates where the parameter lives during most of the
+ activation of the function. If optimization is enabled however, this
+ could be either NULL or else a pseudo-reg. Both of those cases indicate
+ that the parameter doesn't really live anywhere (as far as the code
+ generation parts of GCC are concerned) during most of the function's
+ activation. That will happen (for example) if the parameter is never
+ referenced within the function.
+
+ We could just generate a location descriptor here for all non-NULL
+ non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
+ a little nicer than that if we also consider DECL_INCOMING_RTL in cases
+ where DECL_RTL is NULL or is a pseudo-reg.
+
+ Note however that we can only get away with using DECL_INCOMING_RTL as
+ a backup substitute for DECL_RTL in certain limited cases. In cases
+ where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
+ we can be sure that the parameter was passed using the same type as it is
+ declared to have within the function, and that its DECL_INCOMING_RTL
+ points us to a place where a value of that type is passed.
+
+ In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
+ we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
+ because in these cases DECL_INCOMING_RTL points us to a value of some
+ type which is *different* from the type of the parameter itself. Thus,
+ if we tried to use DECL_INCOMING_RTL to generate a location attribute in
+ such cases, the debugger would end up (for example) trying to fetch a
+ `float' from a place which actually contains the first part of a
+ `double'. That would lead to really incorrect and confusing
+ output at debug-time.
+
+ So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
+ in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl). There
+ are a couple of exceptions however. On little-endian machines we can
+ get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
+ not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
+ an integral type that is smaller than TREE_TYPE (decl). These cases arise
+ when (on a little-endian machine) a non-prototyped function has a
+ parameter declared to be of type `short' or `char'. In such cases,
+ TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
+ be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
+ passed `int' value. If the debugger then uses that address to fetch
+ a `short' or a `char' (on a little-endian machine) the result will be
+ the correct data, so we allow for such exceptional cases below.
+
+ Note that our goal here is to describe the place where the given formal
+ parameter lives during most of the function's activation (i.e. between the
+ end of the prologue and the start of the epilogue). We'll do that as best
+ as we can. Note however that if the given formal parameter is modified
+ sometime during the execution of the function, then a stack backtrace (at
+ debug-time) will show the function as having been called with the *new*
+ value rather than the value which was originally passed in. This happens
+ rarely enough that it is not a major problem, but it *is* a problem, and
+ I'd like to fix it.
+
+ A future version of dwarf2out.c may generate two additional attributes for
+ any given DW_TAG_formal_parameter DIE which will describe the "passed
+ type" and the "passed location" for the given formal parameter in addition
+ to the attributes we now generate to indicate the "declared type" and the
+ "active location" for each parameter. This additional set of attributes
+ could be used by debuggers for stack backtraces. Separately, note that
+ sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be NULL also.
+ This happens (for example) for inlined-instances of inline function formal
+ parameters which are never referenced. This really shouldn't be
+ happening. All PARM_DECL nodes should get valid non-NULL
+ DECL_INCOMING_RTL values. FIXME. */
+
+ /* Use DECL_RTL as the "location" unless we find something better. */
+ rtl = DECL_RTL_IF_SET (decl);
+
+ /* When generating abstract instances, ignore everything except
+ constants, symbols living in memory, and symbols living in
+ fixed registers. */
+ if (! reload_completed)
+ {
+ if (rtl
+ && (CONSTANT_P (rtl)
+ || (MEM_P (rtl)
+ && CONSTANT_P (XEXP (rtl, 0)))
+ || (REG_P (rtl)
+ && TREE_CODE (decl) == VAR_DECL
+ && TREE_STATIC (decl))))
+ {
+ rtl = targetm.delegitimize_address (rtl);
+ return rtl;
+ }
+ rtl = NULL_RTX;
+ }
+ else if (TREE_CODE (decl) == PARM_DECL)
+ {
+ if (rtl == NULL_RTX || is_pseudo_reg (rtl))
+ {
+ tree declared_type = TREE_TYPE (decl);
+ tree passed_type = DECL_ARG_TYPE (decl);
+ enum machine_mode dmode = TYPE_MODE (declared_type);
+ enum machine_mode pmode = TYPE_MODE (passed_type);
+
+ /* This decl represents a formal parameter which was optimized out.
+ Note that DECL_INCOMING_RTL may be NULL in here, but we handle
+ all cases where (rtl == NULL_RTX) just below. */
+ if (dmode == pmode)
+ rtl = DECL_INCOMING_RTL (decl);
+ else if (SCALAR_INT_MODE_P (dmode)
+ && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode)
+ && DECL_INCOMING_RTL (decl))
+ {
+ rtx inc = DECL_INCOMING_RTL (decl);
+ if (REG_P (inc))
+ rtl = inc;
+ else if (MEM_P (inc))
+ {
+ if (BYTES_BIG_ENDIAN)
+ rtl = adjust_address_nv (inc, dmode,
+ GET_MODE_SIZE (pmode)
+ - GET_MODE_SIZE (dmode));
+ else
+ rtl = inc;
+ }
+ }
+ }
+
+ /* If the parm was passed in registers, but lives on the stack, then
+ make a big endian correction if the mode of the type of the
+ parameter is not the same as the mode of the rtl. */
+ /* ??? This is the same series of checks that are made in dbxout.c before
+ we reach the big endian correction code there. It isn't clear if all
+ of these checks are necessary here, but keeping them all is the safe
+ thing to do. */
+ else if (MEM_P (rtl)
+ && XEXP (rtl, 0) != const0_rtx
+ && ! CONSTANT_P (XEXP (rtl, 0))
+ /* Not passed in memory. */
+ && !MEM_P (DECL_INCOMING_RTL (decl))
+ /* Not passed by invisible reference. */
+ && (!REG_P (XEXP (rtl, 0))
+ || REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM
+ || REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ || REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM
+#endif
+ )
+ /* Big endian correction check. */
+ && BYTES_BIG_ENDIAN
+ && TYPE_MODE (TREE_TYPE (decl)) != GET_MODE (rtl)
+ && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))
+ < UNITS_PER_WORD))
+ {
+ int offset = (UNITS_PER_WORD
+ - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))));
+
+ rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
+ plus_constant (XEXP (rtl, 0), offset));
+ }
+ }
+ else if (TREE_CODE (decl) == VAR_DECL
+ && rtl
+ && MEM_P (rtl)
+ && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
+ && BYTES_BIG_ENDIAN)
+ {
+ int rsize = GET_MODE_SIZE (GET_MODE (rtl));
+ int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
+
+ /* If a variable is declared "register" yet is smaller than
+ a register, then if we store the variable to memory, it
+ looks like we're storing a register-sized value, when in
+ fact we are not. We need to adjust the offset of the
+ storage location to reflect the actual value's bytes,
+ else gdb will not be able to display it. */
+ if (rsize > dsize)
+ rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
+ plus_constant (XEXP (rtl, 0), rsize-dsize));
+ }
+
+ /* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
+ and will have been substituted directly into all expressions that use it.
+ C does not have such a concept, but C++ and other languages do. */
+ if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
+ rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
+
+ if (rtl)
+ rtl = targetm.delegitimize_address (rtl);
+
+ /* If we don't look past the constant pool, we risk emitting a
+ reference to a constant pool entry that isn't referenced from
+ code, and thus is not emitted. */
+ if (rtl)
+ rtl = avoid_constant_pool_reference (rtl);
+
+ return rtl;
+}
+
+/* We need to figure out what section we should use as the base for the
+ address ranges where a given location is valid.
+ 1. If this particular DECL has a section associated with it, use that.
+ 2. If this function has a section associated with it, use that.
+ 3. Otherwise, use the text section.
+ XXX: If you split a variable across multiple sections, we won't notice. */
+
+static const char *
+secname_for_decl (tree decl)
+{
+ const char *secname;
+
+ if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
+ {
+ tree sectree = DECL_SECTION_NAME (decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
+ {
+ tree sectree = DECL_SECTION_NAME (current_function_decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (cfun && in_cold_section_p)
+ secname = cfun->cold_section_label;
+ else
+ secname = text_section_label;
+
+ return secname;
+}
+
+/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
+ data attribute for a variable or a parameter. We generate the
+ DW_AT_const_value attribute only in those cases where the given variable
+ or parameter does not have a true "location" either in memory or in a
+ register. This can happen (for example) when a constant is passed as an
+ actual argument in a call to an inline function. (It's possible that
+ these things can crop up in other ways also.) Note that one type of
+ constant value which can be passed into an inlined function is a constant
+ pointer. This can happen for example if an actual argument in an inlined
+ function call evaluates to a compile-time constant address. */
+
+static void
+add_location_or_const_value_attribute (dw_die_ref die, tree decl,
+ enum dwarf_attribute attr)
+{
+ rtx rtl;
+ dw_loc_descr_ref descr;
+ var_loc_list *loc_list;
+ struct var_loc_node *node;
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return;
+
+ gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL);
+
+ /* See if we possibly have multiple locations for this variable. */
+ loc_list = lookup_decl_loc (decl);
+
+ /* If it truly has multiple locations, the first and last node will
+ differ. */
+ if (loc_list && loc_list->first != loc_list->last)
+ {
+ const char *endname, *secname;
+ dw_loc_list_ref list;
+ rtx varloc;
+ /* APPLE LOCAL track initialization status 4964532 */
+ enum var_init_status initialized;
+
+ /* Now that we know what section we are using for a base,
+ actually construct the list of locations.
+ The first location information is what is passed to the
+ function that creates the location list, and the remaining
+ locations just get added on to that list.
+ Note that we only know the start address for a location
+ (IE location changes), so to build the range, we use
+ the range [current location start, next location start].
+ This means we have to special case the last node, and generate
+ a range of [last location start, end of function label]. */
+
+ node = loc_list->first;
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ secname = secname_for_decl (decl);
+
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
+ initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+ else
+ initialized = STATUS_INITIALIZED;
+
+ list = new_loc_list (loc_descriptor (varloc, initialized),
+ node->label, node->next->label, secname, 1);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ node = node->next;
+
+ for (; node->next; node = node->next)
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ /* The variable has a location between NODE->LABEL and
+ NODE->NEXT->LABEL. */
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ enum var_init_status initialized =
+ NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ add_loc_descr_to_loc_list (&list,
+ loc_descriptor (varloc, initialized),
+ node->label, node->next->label, secname);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ }
+
+ /* If the variable has a location at the last label
+ it keeps its location until the end of function. */
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ enum var_init_status initialized =
+ NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+ /* APPLE LOCAL end track initialization status 4964532 */
+
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ if (!current_function_decl)
+ endname = text_end_label;
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ endname = ggc_strdup (label_id);
+ }
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ add_loc_descr_to_loc_list (&list,
+ loc_descriptor (varloc, initialized),
+ node->label, endname, secname);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ }
+
+ /* Finally, add the location list to the DIE, and we are done. */
+ add_AT_loc_list (die, attr, list);
+ return;
+ }
+
+ /* Try to get some constant RTL for this decl, and use that as the value of
+ the location. */
+
+ rtl = rtl_for_decl_location (decl);
+ if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
+ {
+ add_const_value_attribute (die, rtl);
+ return;
+ }
+
+ /* If we have tried to generate the location otherwise, and it
+ didn't work out (we wouldn't be here if we did), and we have a one entry
+ location list, try generating a location from that. */
+ if (loc_list && loc_list->first)
+ {
+ /* APPLE LOCAL begin track initialization status 4964532 */
+ enum var_init_status status;
+ node = loc_list->first;
+ status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
+ /* APPLE LOCAL end track initialization status 4964532 */
+ if (descr)
+ {
+ add_AT_location_description (die, attr, descr);
+ return;
+ }
+ }
+
+ /* We couldn't get any rtl, so try directly generating the location
+ description from the tree. */
+ descr = loc_descriptor_from_tree (decl);
+ if (descr)
+ {
+ add_AT_location_description (die, attr, descr);
+ return;
+ }
+ /* None of that worked, so it must not really have a location;
+ try adding a constant value attribute from the DECL_INITIAL. */
+ tree_add_const_value_attribute (die, decl);
+}
+
+/* If we don't have a copy of this variable in memory for some reason (such
+ as a C++ member constant that doesn't have an out-of-line definition),
+ we should tell the debugger about the constant value. */
+
+static void
+tree_add_const_value_attribute (dw_die_ref var_die, tree decl)
+{
+ tree init = DECL_INITIAL (decl);
+ tree type = TREE_TYPE (decl);
+ rtx rtl;
+
+ if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init)
+ /* OK */;
+ else
+ return;
+
+ rtl = rtl_for_decl_init (init, type);
+ if (rtl)
+ add_const_value_attribute (var_die, rtl);
+}
+
+/* Convert the CFI instructions for the current function into a
+ location list. This is used for DW_AT_frame_base when we targeting
+ a dwarf2 consumer that does not support the dwarf3
+ DW_OP_call_frame_cfa. OFFSET is a constant to be added to all CFA
+ expressions. */
+
+static dw_loc_list_ref
+convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
+{
+ dw_fde_ref fde;
+ dw_loc_list_ref list, *list_tail;
+ dw_cfi_ref cfi;
+ dw_cfa_location last_cfa, next_cfa;
+ const char *start_label, *last_label, *section;
+
+ fde = &fde_table[fde_table_in_use - 1];
+
+ section = secname_for_decl (current_function_decl);
+ list_tail = &list;
+ list = NULL;
+
+ next_cfa.reg = INVALID_REGNUM;
+ next_cfa.offset = 0;
+ next_cfa.indirect = 0;
+ next_cfa.base_offset = 0;
+
+ start_label = fde->dw_fde_begin;
+
+ /* ??? Bald assumption that the CIE opcode list does not contain
+ advance opcodes. */
+ for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, &next_cfa);
+
+ last_cfa = next_cfa;
+ last_label = start_label;
+
+ for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_set_loc:
+ case DW_CFA_advance_loc1:
+ case DW_CFA_advance_loc2:
+ case DW_CFA_advance_loc4:
+ if (!cfa_equal_p (&last_cfa, &next_cfa))
+ {
+ *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+ start_label, last_label, section,
+ list == NULL);
+
+ list_tail = &(*list_tail)->dw_loc_next;
+ last_cfa = next_cfa;
+ start_label = last_label;
+ }
+ last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_advance_loc:
+ /* The encoding is complex enough that we should never emit this. */
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ /* We don't handle these two in this function. It would be possible
+ if it were to be required. */
+ gcc_unreachable ();
+
+ default:
+ lookup_cfa_1 (cfi, &next_cfa);
+ break;
+ }
+
+ if (!cfa_equal_p (&last_cfa, &next_cfa))
+ {
+ *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+ start_label, last_label, section,
+ list == NULL);
+ list_tail = &(*list_tail)->dw_loc_next;
+ start_label = last_label;
+ }
+ *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
+ start_label, fde->dw_fde_end, section,
+ list == NULL);
+
+ return list;
+}
+
+/* Compute a displacement from the "steady-state frame pointer" to the
+ frame base (often the same as the CFA), and store it in
+ frame_pointer_fb_offset. OFFSET is added to the displacement
+ before the latter is negated. */
+
+static void
+compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
+{
+ rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+ reg = frame_pointer_rtx;
+ offset += FRAME_POINTER_CFA_OFFSET (current_function_decl);
+#else
+ reg = arg_pointer_rtx;
+ offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
+#endif
+
+ elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+ if (GET_CODE (elim) == PLUS)
+ {
+ offset += INTVAL (XEXP (elim, 1));
+ elim = XEXP (elim, 0);
+ }
+ /* APPLE LOCAL begin ARM prefer SP to FP */
+
+ frame_pointer_fb_offset_from = elim;
+ /* APPLE LOCAL end ARM prefer SP to FP */
+ frame_pointer_fb_offset = -offset;
+}
+
+/* Generate a DW_AT_name attribute given some string value to be included as
+ the value of the attribute. */
+
+static void
+add_name_attribute (dw_die_ref die, const char *name_string)
+{
+ if (name_string != NULL && *name_string != 0)
+ {
+ if (demangle_name_func)
+ name_string = (*demangle_name_func) (name_string);
+
+ add_AT_string (die, DW_AT_name, name_string);
+ }
+}
+
+/* Generate a DW_AT_comp_dir attribute for DIE. */
+
+static void
+add_comp_dir_attribute (dw_die_ref die)
+{
+ const char *wd = get_src_pwd ();
+ if (wd != NULL)
+ add_AT_string (die, DW_AT_comp_dir, wd);
+}
+
+/* Given a tree node describing an array bound (either lower or upper) output
+ a representation for that bound. */
+
+static void
+add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
+{
+ switch (TREE_CODE (bound))
+ {
+ case ERROR_MARK:
+ return;
+
+ /* All fixed-bounds are represented by INTEGER_CST nodes. */
+ case INTEGER_CST:
+ if (! host_integerp (bound, 0)
+ || (bound_attr == DW_AT_lower_bound
+ && (((is_c_family () || is_java ()) && integer_zerop (bound))
+ || (is_fortran () && integer_onep (bound)))))
+ /* Use the default. */
+ ;
+ else
+ add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
+ break;
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
+ add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
+ break;
+
+ case SAVE_EXPR:
+ break;
+
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ {
+ dw_die_ref decl_die = lookup_decl_die (bound);
+
+ /* ??? Can this happen, or should the variable have been bound
+ first? Probably it can, since I imagine that we try to create
+ the types of parameters in the order in which they exist in
+ the list, and won't have created a forward reference to a
+ later parameter. */
+ if (decl_die != NULL)
+ add_AT_die_ref (subrange_die, bound_attr, decl_die);
+ break;
+ }
+
+ default:
+ {
+ /* Otherwise try to create a stack operation procedure to
+ evaluate the value of the array bound. */
+
+ dw_die_ref ctx, decl_die;
+ dw_loc_descr_ref loc;
+
+ loc = loc_descriptor_from_tree (bound);
+ if (loc == NULL)
+ break;
+
+ if (current_function_decl == 0)
+ ctx = comp_unit_die;
+ else
+ ctx = lookup_decl_die (current_function_decl);
+
+ decl_die = new_die (DW_TAG_variable, ctx, bound);
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+ add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
+ add_AT_loc (decl_die, DW_AT_location, loc);
+
+ add_AT_die_ref (subrange_die, bound_attr, decl_die);
+ break;
+ }
+ }
+}
+
+/* Note that the block of subscript information for an array type also
+ includes information about the element type of type given array type. */
+
+static void
+add_subscript_info (dw_die_ref type_die, tree type)
+{
+#ifndef MIPS_DEBUGGING_INFO
+ unsigned dimension_number;
+#endif
+ tree lower, upper;
+ dw_die_ref subrange_die;
+
+ /* The GNU compilers represent multidimensional array types as sequences of
+ one dimensional array types whose element types are themselves array
+ types. Here we squish that down, so that each multidimensional array
+ type gets only one array_type DIE in the Dwarf debugging info. The draft
+ Dwarf specification say that we are allowed to do this kind of
+ compression in C (because there is no difference between an array or
+ arrays and a multidimensional array in C) but for other source languages
+ (e.g. Ada) we probably shouldn't do this. */
+
+ /* ??? The SGI dwarf reader fails for multidimensional arrays with a
+ const enum type. E.g. const enum machine_mode insn_operand_mode[2][10].
+ We work around this by disabling this feature. See also
+ gen_array_type_die. */
+#ifndef MIPS_DEBUGGING_INFO
+ for (dimension_number = 0;
+ TREE_CODE (type) == ARRAY_TYPE;
+ type = TREE_TYPE (type), dimension_number++)
+#endif
+ {
+ tree domain = TYPE_DOMAIN (type);
+
+ /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
+ and (in GNU C only) variable bounds. Handle all three forms
+ here. */
+ subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+ if (domain)
+ {
+ /* We have an array type with specified bounds. */
+ lower = TYPE_MIN_VALUE (domain);
+ upper = TYPE_MAX_VALUE (domain);
+
+ /* Define the index type. */
+ if (TREE_TYPE (domain))
+ {
+ /* ??? This is probably an Ada unnamed subrange type. Ignore the
+ TREE_TYPE field. We can't emit debug info for this
+ because it is an unnamed integral type. */
+ 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);
+ }
+
+ /* ??? If upper is NULL, the array has unspecified length,
+ but it does have a lower bound. This happens with Fortran
+ dimension arr(N:*)
+ Since the debugger is definitely going to need to know N
+ to produce useful results, go ahead and output the lower
+ bound solo, and hope the debugger can cope. */
+
+ add_bound_info (subrange_die, DW_AT_lower_bound, lower);
+ if (upper)
+ add_bound_info (subrange_die, DW_AT_upper_bound, upper);
+ }
+
+ /* Otherwise we have an array type with an unspecified length. The
+ DWARF-2 spec does not say how to handle this; let's just leave out the
+ bounds. */
+ }
+}
+
+static void
+add_byte_size_attribute (dw_die_ref die, tree tree_node)
+{
+ unsigned size;
+
+ switch (TREE_CODE (tree_node))
+ {
+ case ERROR_MARK:
+ size = 0;
+ break;
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ size = int_size_in_bytes (tree_node);
+ break;
+ case FIELD_DECL:
+ /* For a data member of a struct or union, the DW_AT_byte_size is
+ generally given as the number of bytes normally allocated for an
+ object of the *declared* type of the member itself. This is true
+ even for bit-fields. */
+ size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Note that `size' might be -1 when we get to this point. If it is, that
+ indicates that the byte size of the entity in question is variable. We
+ have no good way of expressing this fact in Dwarf at the present time,
+ so just let the -1 pass on through. */
+ add_AT_unsigned (die, DW_AT_byte_size, size);
+}
+
+/* For a FIELD_DECL node which represents a bit-field, output an attribute
+ which specifies the distance in bits from the highest order bit of the
+ "containing object" for the bit-field to the highest order bit of the
+ bit-field itself.
+
+ For any given bit-field, the "containing object" is a hypothetical object
+ (of some integral or enum type) within which the given bit-field lives. The
+ type of this hypothetical "containing object" is always the same as the
+ declared type of the individual bit-field itself. The determination of the
+ exact location of the "containing object" for a bit-field is rather
+ complicated. It's handled by the `field_byte_offset' function (above).
+
+ Note that it is the size (in bytes) of the hypothetical "containing object"
+ which will be given in the DW_AT_byte_size attribute for this bit-field.
+ (See `byte_size_attribute' above). */
+
+static inline void
+add_bit_offset_attribute (dw_die_ref die, tree decl)
+{
+ HOST_WIDE_INT object_offset_in_bytes = field_byte_offset (decl);
+ tree type = DECL_BIT_FIELD_TYPE (decl);
+ HOST_WIDE_INT bitpos_int;
+ HOST_WIDE_INT highest_order_object_bit_offset;
+ HOST_WIDE_INT highest_order_field_bit_offset;
+ HOST_WIDE_INT unsigned bit_offset;
+
+ /* Must be a field and a bit field. */
+ gcc_assert (type && TREE_CODE (decl) == FIELD_DECL);
+
+ /* We can't yet handle bit-fields whose offsets are variable, so if we
+ encounter such things, just return without generating any attribute
+ whatsoever. Likewise for variable or too large size. */
+ if (! host_integerp (bit_position (decl), 0)
+ || ! host_integerp (DECL_SIZE (decl), 1))
+ return;
+
+ bitpos_int = int_bit_position (decl);
+
+ /* Note that the bit offset is always the distance (in bits) from the
+ highest-order bit of the "containing object" to the highest-order bit of
+ the bit-field itself. Since the "high-order end" of any object or field
+ is different on big-endian and little-endian machines, the computation
+ below must take account of these differences. */
+ highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
+ highest_order_field_bit_offset = bitpos_int;
+
+ if (! BYTES_BIG_ENDIAN)
+ {
+ highest_order_field_bit_offset += tree_low_cst (DECL_SIZE (decl), 0);
+ highest_order_object_bit_offset += simple_type_size_in_bits (type);
+ }
+
+ bit_offset
+ = (! BYTES_BIG_ENDIAN
+ ? highest_order_object_bit_offset - highest_order_field_bit_offset
+ : highest_order_field_bit_offset - highest_order_object_bit_offset);
+
+ add_AT_unsigned (die, DW_AT_bit_offset, bit_offset);
+}
+
+/* For a FIELD_DECL node which represents a bit field, output an attribute
+ which specifies the length in bits of the given field. */
+
+static inline void
+add_bit_size_attribute (dw_die_ref die, tree decl)
+{
+ /* Must be a field and a bit field. */
+ gcc_assert (TREE_CODE (decl) == FIELD_DECL
+ && DECL_BIT_FIELD_TYPE (decl));
+
+ if (host_integerp (DECL_SIZE (decl), 1))
+ add_AT_unsigned (die, DW_AT_bit_size, tree_low_cst (DECL_SIZE (decl), 1));
+}
+
+/* If the compiled language is ANSI C, then add a 'prototyped'
+ attribute, if arg types are given for the parameters of a function. */
+
+static inline void
+add_prototyped_attribute (dw_die_ref die, tree func_type)
+{
+ /* APPLE LOCAL begin radar 5344182 */
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ if ((lang == DW_LANG_C89 || lang == DW_LANG_ObjC)
+ && TYPE_ARG_TYPES (func_type) != NULL)
+ /* APPLE LOCAL end radar 5344182 */
+ add_AT_flag (die, DW_AT_prototyped, 1);
+}
+
+/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found
+ by looking in either the type declaration or object declaration
+ equate table. */
+
+static inline void
+add_abstract_origin_attribute (dw_die_ref die, tree origin)
+{
+ dw_die_ref origin_die = NULL;
+
+ if (TREE_CODE (origin) != FUNCTION_DECL)
+ {
+ /* We may have gotten separated from the block for the inlined
+ function, if we're in an exception handler or some such; make
+ sure that the abstract function has been written out.
+
+ Doing this for nested functions is wrong, however; functions are
+ distinct units, and our context might not even be inline. */
+ tree fn = origin;
+
+ if (TYPE_P (fn))
+ fn = TYPE_STUB_DECL (fn);
+
+ fn = decl_function_context (fn);
+ if (fn)
+ dwarf2out_abstract_function (fn);
+ }
+
+ if (DECL_P (origin))
+ origin_die = lookup_decl_die (origin);
+ else if (TYPE_P (origin))
+ origin_die = lookup_type_die (origin);
+
+ /* XXX: Functions that are never lowered don't always have correct block
+ trees (in the case of java, they simply have no block tree, in some other
+ languages). For these functions, there is nothing we can really do to
+ output correct debug info for inlined functions in all cases. Rather
+ than die, we'll just produce deficient debug info now, in that we will
+ have variables without a proper abstract origin. In the future, when all
+ functions are lowered, we should re-add a gcc_assert (origin_die)
+ here. */
+
+ if (origin_die)
+ /* APPLE LOCAL begin radar 6275985 debug inlined section */
+ {
+ add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
+ if (die->die_tag == DW_TAG_inlined_subroutine)
+ {
+ dw_attr_ref inline_attr = get_AT (origin_die, DW_AT_inline);
+ if (!inline_attr)
+ {
+ if (DECL_P (origin) && DECL_DECLARED_INLINE_P (origin))
+ add_AT_unsigned (origin_die, DW_AT_inline, DW_INL_declared_inlined);
+ else
+ add_AT_unsigned (origin_die, DW_AT_inline, DW_INL_inlined);
+ }
+ }
+ }
+ /* APPLE LOCAL end radar 6275985 debug inlined section */
+}
+
+/* We do not currently support the pure_virtual attribute. */
+
+static inline void
+add_pure_or_virtual_attribute (dw_die_ref die, tree func_decl)
+{
+ if (DECL_VINDEX (func_decl))
+ {
+ add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+
+ if (host_integerp (DECL_VINDEX (func_decl), 0))
+ add_AT_loc (die, DW_AT_vtable_elem_location,
+ new_loc_descr (DW_OP_constu,
+ tree_low_cst (DECL_VINDEX (func_decl), 0),
+ 0));
+
+ /* GNU extension: Record what type this method came from originally. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ add_AT_die_ref (die, DW_AT_containing_type,
+ lookup_type_die (DECL_CONTEXT (func_decl)));
+ }
+}
+
+/* APPLE LOCAL begin opt diary */
+/* Add source coordinate attributes for the given location. */
+
+static void
+add_src_coords_attributes_locus (dw_die_ref die, expanded_location s)
+{
+ add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
+ add_AT_unsigned (die, DW_AT_decl_line, s.line);
+}
+/* APPLE LOCAL end opt diary */
+
+/* Add source coordinate attributes for the given decl. */
+
+static void
+add_src_coords_attributes (dw_die_ref die, tree decl)
+{
+ expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+
+ add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
+ add_AT_unsigned (die, DW_AT_decl_line, s.line);
+}
+
+/* APPLE LOCAL begin radar 5636185 */
+/* Given a function or variable decl, DECL, check to see if
+ it has an assembler name, and if so, check to see if the
+ decl name is just a prefix for the assembler name, or if the
+ assembler name is really different. For example if the name
+ is "foo" and the assembler name is "foo.37", then the names
+ do not really differ, and the assembler name should not be written
+ out. However for names such as "cXf" vs "_ZN1cblahblahF3cXfE",
+ the assembler name does differ and should be written out.
+
+ This is used to determine if the DW_AT_MIPS_linkage_name attribute
+ needs to be added to the die for DECL or not. Later, after all
+ the dies have been generated, there is a further check to see
+ if the die is local to a subroutine; if it is, then the attribute
+ is removed before the debug information is written out. */
+
+static bool
+assembler_name_exists_and_is_different (tree decl)
+{
+ bool ret_val = true;
+ const char *assem_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+ unsigned int len = strlen (name);
+
+ if (!assem_name)
+ ret_val = false;
+ else
+ {
+ if (strlen (assem_name) < len)
+ len = strlen (assem_name);
+
+ if (strncmp (name, assem_name, len) == 0)
+ ret_val = false;
+ }
+
+ return ret_val;
+}
+
+/* APPLE LOCAL end radar 5636185 */
+
+/* Add a DW_AT_name attribute and source coordinate attribute for the
+ given decl, but only if it actually has a name. */
+
+static void
+add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
+{
+ tree decl_name;
+
+ decl_name = DECL_NAME (decl);
+ if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
+ {
+ add_name_attribute (die, dwarf2_name (decl, 0));
+ if (! DECL_ARTIFICIAL (decl))
+ add_src_coords_attributes (die, decl);
+
+ if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
+ /* APPLE LOCAL begin radar 5636185 */
+ && (TREE_PUBLIC (decl) || TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && assembler_name_exists_and_is_different (decl)
+ /* APPLE LOCAL end radar 5636185 */
+ && !DECL_ABSTRACT (decl)
+ && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)))
+ add_AT_string (die, DW_AT_MIPS_linkage_name,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ }
+
+#ifdef VMS_DEBUGGING_INFO
+ /* Get the function's name, as described by its RTL. This may be different
+ from the DECL_NAME name used in the source file. */
+ if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
+ {
+ add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
+ XEXP (DECL_RTL (decl), 0));
+ VEC_safe_push (tree, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
+ }
+#endif
+}
+
+/* Push a new declaration scope. */
+
+static void
+push_decl_scope (tree scope)
+{
+ VEC_safe_push (tree, gc, decl_scope_table, scope);
+}
+
+/* Pop a declaration scope. */
+
+static inline void
+pop_decl_scope (void)
+{
+ VEC_pop (tree, decl_scope_table);
+}
+
+/* Return the DIE for the scope that immediately contains this type.
+ Non-named types get global scope. Named types nested in other
+ types get their containing scope if it's open, or global scope
+ otherwise. All other types (i.e. function-local named types) get
+ the current active scope. */
+
+static dw_die_ref
+scope_die_for (tree t, dw_die_ref context_die)
+{
+ dw_die_ref scope_die = NULL;
+ tree containing_scope;
+ int i;
+
+ /* Non-types always go in the current scope. */
+ gcc_assert (TYPE_P (t));
+
+ containing_scope = TYPE_CONTEXT (t);
+
+ /* Use the containing namespace if it was passed in (for a declaration). */
+ if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
+ {
+ if (context_die == lookup_decl_die (containing_scope))
+ /* OK */;
+ else
+ containing_scope = NULL_TREE;
+ }
+
+ /* Ignore function type "scopes" from the C frontend. They mean that
+ a tagged type is local to a parmlist of a function declarator, but
+ that isn't useful to DWARF. */
+ if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE)
+ containing_scope = NULL_TREE;
+
+ if (containing_scope == NULL_TREE)
+ scope_die = comp_unit_die;
+ else if (TYPE_P (containing_scope))
+ {
+ /* For types, we can just look up the appropriate DIE. But
+ first we check to see if we're in the middle of emitting it
+ so we know where the new DIE should go. */
+ for (i = VEC_length (tree, decl_scope_table) - 1; i >= 0; --i)
+ if (VEC_index (tree, decl_scope_table, i) == containing_scope)
+ break;
+
+ if (i < 0)
+ {
+ gcc_assert (debug_info_level <= DINFO_LEVEL_TERSE
+ || TREE_ASM_WRITTEN (containing_scope));
+
+ /* If none of the current dies are suitable, we get file scope. */
+ scope_die = comp_unit_die;
+ }
+ else
+ scope_die = lookup_type_die (containing_scope);
+ }
+ else
+ scope_die = context_die;
+
+ return scope_die;
+}
+
+/* Returns nonzero if CONTEXT_DIE is internal to a function. */
+
+static inline int
+local_scope_p (dw_die_ref context_die)
+{
+ for (; context_die; context_die = context_die->die_parent)
+ if (context_die->die_tag == DW_TAG_inlined_subroutine
+ || context_die->die_tag == DW_TAG_subprogram)
+ return 1;
+
+ return 0;
+}
+
+/* Returns nonzero if CONTEXT_DIE is a class or namespace, for deciding
+ whether or not to treat a DIE in this context as a declaration. */
+
+static inline int
+class_or_namespace_scope_p (dw_die_ref context_die)
+{
+ return (context_die
+ && (context_die->die_tag == DW_TAG_structure_type
+ || context_die->die_tag == DW_TAG_union_type
+ || context_die->die_tag == DW_TAG_namespace));
+}
+
+/* Many forms of DIEs require a "type description" attribute. This
+ routine locates the proper "type descriptor" die for the type given
+ by 'type', and adds a DW_AT_type attribute below the given die. */
+
+static void
+add_type_attribute (dw_die_ref object_die, tree type, int decl_const,
+ int decl_volatile, dw_die_ref context_die)
+{
+ enum tree_code code = TREE_CODE (type);
+ dw_die_ref type_die = NULL;
+
+/* APPLE LOCAL begin radar 5847213 */
+ /* APPLE LOCAL begin radar 5811943 - Fix type of pointers to blocks */
+ /* APPLE LOCAL - radar 6113240 */
+ /* APPLE LOCAL begin radar 6300081 */
+ if (code == BLOCK_POINTER_TYPE && generic_block_literal_struct_type)
+ {
+ type = build_pointer_type (generic_block_literal_struct_type);
+ code = TREE_CODE (type);
+ }
+ /* APPLE LOCAL end radar 6300081 */
+ /* APPLE LOCAL end radar 5811943 - Fix type of pointers to Blocks */
+/* APPLE LOCAL end radar 5847213 */
+
+ /* ??? If this type is an unnamed subrange type of an integral or
+ floating-point type, use the inner type. This is because we have no
+ support for unnamed types in base_type_die. This can happen if this is
+ an Ada subrange type. Correct solution is emit a subrange type die. */
+ 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
+ /* Handle a special case. For functions whose return type is void, we
+ generate *no* type attribute. (Note that no object may have type
+ `void', so this only applies to function return types). */
+ || 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);
+}
+
+/* Given an object die, add the calling convention attribute for the
+ function call type. */
+static void
+add_calling_convention_attribute (dw_die_ref subr_die, tree type)
+{
+ enum dwarf_calling_convention value = DW_CC_normal;
+
+ value = targetm.dwarf_calling_convention (type);
+
+ /* Only add the attribute if the backend requests it, and
+ is not DW_CC_normal. */
+ if (value && (value != DW_CC_normal))
+ add_AT_unsigned (subr_die, DW_AT_calling_convention, value);
+}
+
+/* Given a tree pointer to a struct, class, union, or enum type node, return
+ a pointer to the (string) tag name for the given type, or zero if the type
+ was declared without a tag. */
+
+static const char *
+type_tag (tree type)
+{
+ const char *name = 0;
+
+ if (TYPE_NAME (type) != 0)
+ {
+ tree t = 0;
+
+ /* Find the IDENTIFIER_NODE for the type name. */
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ t = TYPE_NAME (type);
+
+ /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
+ a TYPE_DECL node, regardless of whether or not a `typedef' was
+ involved. */
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && ! DECL_IGNORED_P (TYPE_NAME (type)))
+ t = DECL_NAME (TYPE_NAME (type));
+
+ /* Now get the name as a string, or invent one. */
+ if (t != 0)
+ name = IDENTIFIER_POINTER (t);
+ }
+
+ return (name == 0 || *name == '\0') ? 0 : name;
+}
+
+/* Return the type associated with a data member, make a special check
+ for bit field types. */
+
+static inline tree
+member_declared_type (tree member)
+{
+ return (DECL_BIT_FIELD_TYPE (member)
+ ? DECL_BIT_FIELD_TYPE (member) : TREE_TYPE (member));
+}
+
+/* Get the decl's label, as described by its RTL. This may be different
+ from the DECL_NAME name used in the source file. */
+
+#if 0
+static const char *
+decl_start_label (tree decl)
+{
+ rtx x;
+ const char *fnname;
+
+ x = DECL_RTL (decl);
+ gcc_assert (MEM_P (x));
+
+ x = XEXP (x, 0);
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+ fnname = XSTR (x, 0);
+ return fnname;
+}
+#endif
+
+/* These routines generate the internal representation of the DIE's for
+ the compilation unit. Debugging information is collected by walking
+ the declaration trees passed in from dwarf2out_decl(). */
+
+static void
+gen_array_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref scope_die = scope_die_for (type, context_die);
+ dw_die_ref array_die;
+ tree element_type;
+
+ /* ??? The SGI dwarf reader fails for array of array of enum types unless
+ the inner array type comes before the outer array type. Thus we must
+ call gen_type_die before we call new_die. See below also. */
+#ifdef MIPS_DEBUGGING_INFO
+ gen_type_die (TREE_TYPE (type), context_die);
+#endif
+
+ array_die = new_die (DW_TAG_array_type, scope_die, type);
+ add_name_attribute (array_die, type_tag (type));
+ equate_type_number_to_die (type, array_die);
+
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ /* The frontend feeds us a representation for the vector as a struct
+ containing an array. Pull out the array type. */
+ type = TREE_TYPE (TYPE_FIELDS (TYPE_DEBUG_REPRESENTATION_TYPE (type)));
+ add_AT_flag (array_die, DW_AT_GNU_vector, 1);
+ }
+
+#if 0
+ /* We default the array ordering. SDB will probably do
+ the right things even if DW_AT_ordering is not present. It's not even
+ an issue until we start to get into multidimensional arrays anyway. If
+ SDB is ever caught doing the Wrong Thing for multi-dimensional arrays,
+ then we'll have to put the DW_AT_ordering attribute back in. (But if
+ and when we find out that we need to put these in, we will only do so
+ for multidimensional arrays. */
+ add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
+#endif
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* The SGI compilers handle arrays of unknown bound by setting
+ AT_declaration and not emitting any subrange DIEs. */
+ if (! TYPE_DOMAIN (type))
+ add_AT_flag (array_die, DW_AT_declaration, 1);
+ else
+#endif
+ add_subscript_info (array_die, type);
+
+ /* Add representation of the type of the elements of this array type. */
+ element_type = TREE_TYPE (type);
+
+ /* ??? The SGI dwarf reader fails for multidimensional arrays with a
+ const enum type. E.g. const enum machine_mode insn_operand_mode[2][10].
+ We work around this by disabling this feature. See also
+ add_subscript_info. */
+#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);
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ if (get_AT (array_die, DW_AT_name))
+ add_pubtype (type, array_die);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+}
+
+#if 0
+static void
+gen_entry_point_die (tree decl, dw_die_ref context_die)
+{
+ tree origin = decl_ultimate_origin (decl);
+ dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die, decl);
+
+ if (origin != NULL)
+ add_abstract_origin_attribute (decl_die, origin);
+ else
+ {
+ add_name_and_src_coords_attributes (decl_die, decl);
+ add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
+ 0, 0, context_die);
+ }
+
+ if (DECL_ABSTRACT (decl))
+ equate_decl_number_to_die (decl, decl_die);
+ else
+ add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
+}
+#endif
+
+/* Walk through the list of incomplete types again, trying once more to
+ emit full debugging info for them. */
+
+static void
+retry_incomplete_types (void)
+{
+ int i;
+
+ for (i = VEC_length (tree, incomplete_types) - 1; i >= 0; i--)
+ gen_type_die (VEC_index (tree, incomplete_types, i), comp_unit_die);
+}
+
+/* Generate a DIE to represent an inlined instance of an enumeration type. */
+
+static void
+gen_inlined_enumeration_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref type_die = new_die (DW_TAG_enumeration_type, context_die, type);
+
+ /* We do not check for TREE_ASM_WRITTEN (type) being set, as the type may
+ be incomplete and such types are not marked. */
+ add_abstract_origin_attribute (type_die, type);
+}
+
+/* Generate a DIE to represent an inlined instance of a structure type. */
+
+static void
+gen_inlined_structure_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref type_die = new_die (DW_TAG_structure_type, context_die, type);
+
+ /* We do not check for TREE_ASM_WRITTEN (type) being set, as the type may
+ be incomplete and such types are not marked. */
+ add_abstract_origin_attribute (type_die, type);
+}
+
+/* Generate a DIE to represent an inlined instance of a union type. */
+
+static void
+gen_inlined_union_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref type_die = new_die (DW_TAG_union_type, context_die, type);
+
+ /* We do not check for TREE_ASM_WRITTEN (type) being set, as the type may
+ be incomplete and such types are not marked. */
+ add_abstract_origin_attribute (type_die, type);
+}
+
+/* Generate a DIE to represent an enumeration type. Note that these DIEs
+ include all of the information about the enumeration values also. Each
+ enumerated type name/value is listed as a child of the enumerated type
+ DIE. */
+
+static dw_die_ref
+gen_enumeration_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref type_die = lookup_type_die (type);
+
+ if (type_die == NULL)
+ {
+ type_die = new_die (DW_TAG_enumeration_type,
+ scope_die_for (type, context_die), type);
+ equate_type_number_to_die (type, type_die);
+ add_name_attribute (type_die, type_tag (type));
+ }
+ else if (! TYPE_SIZE (type))
+ return type_die;
+ else
+ remove_AT (type_die, DW_AT_declaration);
+
+ /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the
+ given enum type is incomplete, do not generate the DW_AT_byte_size
+ attribute or the DW_AT_element_list attribute. */
+ if (TYPE_SIZE (type))
+ {
+ tree link;
+
+ TREE_ASM_WRITTEN (type) = 1;
+ add_byte_size_attribute (type_die, type);
+ if (TYPE_STUB_DECL (type) != NULL_TREE)
+ add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+
+ /* If the first reference to this type was as the return type of an
+ inline function, then it may not have a parent. Fix this now. */
+ if (type_die->die_parent == NULL)
+ add_child_die (scope_die_for (type, context_die), type_die);
+
+ for (link = TYPE_VALUES (type);
+ link != NULL; link = TREE_CHAIN (link))
+ {
+ dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
+ tree value = TREE_VALUE (link);
+
+ add_name_attribute (enum_die,
+ IDENTIFIER_POINTER (TREE_PURPOSE (link)));
+
+ if (host_integerp (value, TYPE_UNSIGNED (TREE_TYPE (value))))
+ /* DWARF2 does not provide a way of indicating whether or
+ not enumeration constants are signed or unsigned. GDB
+ always assumes the values are signed, so we output all
+ values as if they were signed. That means that
+ enumeration constants with very large unsigned values
+ will appear to have negative values in the debugger. */
+ add_AT_int (enum_die, DW_AT_const_value,
+ tree_low_cst (value, tree_int_cst_sgn (value) > 0));
+ }
+ }
+ else
+ add_AT_flag (type_die, DW_AT_declaration, 1);
+
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ if (get_AT (type_die, DW_AT_name))
+ add_pubtype (type, type_die);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+ return type_die;
+}
+
+/* Generate a DIE to represent either a real live formal parameter decl or to
+ represent just the type of some formal parameter position in some function
+ type.
+
+ Note that this routine is a bit unusual because its argument may be a
+ ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
+ represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
+ node. If it's the former then this function is being called to output a
+ DIE to represent a formal parameter object (or some inlining thereof). If
+ it's the latter, then this function is only being called to output a
+ DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
+ argument type of some subprogram type. */
+
+static dw_die_ref
+gen_formal_parameter_die (tree node, dw_die_ref context_die)
+{
+ dw_die_ref parm_die
+ = new_die (DW_TAG_formal_parameter, context_die, node);
+ tree origin;
+
+ switch (TREE_CODE_CLASS (TREE_CODE (node)))
+ {
+ case tcc_declaration:
+ origin = decl_ultimate_origin (node);
+ if (origin != NULL)
+ add_abstract_origin_attribute (parm_die, origin);
+ else
+ {
+ add_name_and_src_coords_attributes (parm_die, node);
+ add_type_attribute (parm_die, TREE_TYPE (node),
+ TREE_READONLY (node),
+ TREE_THIS_VOLATILE (node),
+ context_die);
+ if (DECL_ARTIFICIAL (node))
+ add_AT_flag (parm_die, DW_AT_artificial, 1);
+ }
+
+ equate_decl_number_to_die (node, parm_die);
+ if (! DECL_ABSTRACT (node))
+ add_location_or_const_value_attribute (parm_die, node, DW_AT_location);
+
+ break;
+
+ case tcc_type:
+ /* We were called with some kind of a ..._TYPE node. */
+ add_type_attribute (parm_die, node, 0, 0, context_die);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return parm_die;
+}
+
+/* Generate a special type of DIE used as a stand-in for a trailing ellipsis
+ at the end of an (ANSI prototyped) formal parameters list. */
+
+static void
+gen_unspecified_parameters_die (tree decl_or_type, dw_die_ref context_die)
+{
+ new_die (DW_TAG_unspecified_parameters, context_die, decl_or_type);
+}
+
+/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
+ DW_TAG_unspecified_parameters DIE) to represent the types of the formal
+ parameters as specified in some function type specification (except for
+ those which appear as part of a function *definition*). */
+
+static void
+gen_formal_types_die (tree function_or_method_type, dw_die_ref context_die)
+{
+ tree link;
+ tree formal_type = NULL;
+ tree first_parm_type;
+ tree arg;
+
+ if (TREE_CODE (function_or_method_type) == FUNCTION_DECL)
+ {
+ arg = DECL_ARGUMENTS (function_or_method_type);
+ function_or_method_type = TREE_TYPE (function_or_method_type);
+ }
+ else
+ arg = NULL_TREE;
+
+ first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
+
+ /* Make our first pass over the list of formal parameter types and output a
+ DW_TAG_formal_parameter DIE for each one. */
+ for (link = first_parm_type; link; )
+ {
+ dw_die_ref parm_die;
+
+ formal_type = TREE_VALUE (link);
+ if (formal_type == void_type_node)
+ break;
+
+ /* Output a (nameless) DIE to represent the formal parameter itself. */
+ parm_die = gen_formal_parameter_die (formal_type, context_die);
+ if ((TREE_CODE (function_or_method_type) == METHOD_TYPE
+ && link == first_parm_type)
+ || (arg && DECL_ARTIFICIAL (arg)))
+ add_AT_flag (parm_die, DW_AT_artificial, 1);
+
+ link = TREE_CHAIN (link);
+ if (arg)
+ arg = TREE_CHAIN (arg);
+ }
+
+ /* If this function type has an ellipsis, add a
+ DW_TAG_unspecified_parameters DIE to the end of the parameter list. */
+ if (formal_type != void_type_node)
+ gen_unspecified_parameters_die (function_or_method_type, context_die);
+
+ /* Make our second (and final) pass over the list of formal parameter types
+ and output DIEs to represent those types (as necessary). */
+ for (link = TYPE_ARG_TYPES (function_or_method_type);
+ link && TREE_VALUE (link);
+ link = TREE_CHAIN (link))
+ gen_type_die (TREE_VALUE (link), context_die);
+}
+
+/* We want to generate the DIE for TYPE so that we can generate the
+ die for MEMBER, which has been defined; we will need to refer back
+ to the member declaration nested within TYPE. If we're trying to
+ generate minimal debug info for TYPE, processing TYPE won't do the
+ trick; we need to attach the member declaration by hand. */
+
+static void
+gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
+{
+ gen_type_die (type, context_die);
+
+ /* If we're trying to avoid duplicate debug info, we may not have
+ emitted the member decl for this function. Emit it now. */
+ if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
+ && ! lookup_decl_die (member))
+ {
+ dw_die_ref type_die;
+ gcc_assert (!decl_ultimate_origin (member));
+
+ push_decl_scope (type);
+ type_die = lookup_type_die (type);
+ if (TREE_CODE (member) == FUNCTION_DECL)
+ gen_subprogram_die (member, type_die);
+ else if (TREE_CODE (member) == FIELD_DECL)
+ {
+ /* Ignore the nameless fields that are used to skip bits but handle
+ C++ anonymous unions and structs. */
+ if (DECL_NAME (member) != NULL_TREE
+ || TREE_CODE (TREE_TYPE (member)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)
+ {
+ gen_type_die (member_declared_type (member), type_die);
+ gen_field_die (member, type_die);
+ }
+ }
+ else
+ gen_variable_die (member, type_die);
+
+ pop_decl_scope ();
+ }
+}
+
+/* Generate the DWARF2 info for the "abstract" instance of a function which we
+ may later generate inlined and/or out-of-line instances of. */
+
+static void
+dwarf2out_abstract_function (tree decl)
+{
+ dw_die_ref old_die;
+ tree save_fn;
+ struct function *save_cfun;
+ tree context;
+ int was_abstract = DECL_ABSTRACT (decl);
+
+ /* Make sure we have the actual abstract inline, not a clone. */
+ decl = DECL_ORIGIN (decl);
+
+ old_die = lookup_decl_die (decl);
+ if (old_die && get_AT (old_die, DW_AT_inline))
+ /* We've already generated the abstract instance. */
+ return;
+
+ /* Be sure we've emitted the in-class declaration DIE (if any) first, so
+ we don't get confused by DECL_ABSTRACT. */
+ 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;
+ save_cfun = cfun;
+ current_function_decl = decl;
+ cfun = DECL_STRUCT_FUNCTION (decl);
+
+ set_decl_abstract_flags (decl, 1);
+ dwarf2out_decl (decl);
+ if (! was_abstract)
+ set_decl_abstract_flags (decl, 0);
+
+ current_function_decl = save_fn;
+ cfun = save_cfun;
+}
+
+/* Helper function of premark_used_types() which gets called through
+ htab_traverse_resize().
+
+ Marks the DIE of a given type in *SLOT as perennial, so it never gets
+ marked as unused by prune_unused_types. */
+static int
+premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ tree type;
+ dw_die_ref die;
+
+ type = *slot;
+ die = lookup_type_die (type);
+ if (die != NULL)
+ die->die_perennial_p = 1;
+ return 1;
+}
+
+/* Mark all members of used_types_hash as perennial. */
+static void
+premark_used_types (void)
+{
+ if (cfun && cfun->used_types_hash)
+ htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
+}
+
+/* Generate a DIE to represent a declared function (either file-scope or
+ block-local). */
+
+static void
+gen_subprogram_die (tree decl, dw_die_ref context_die)
+{
+ char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+ tree origin = decl_ultimate_origin (decl);
+ dw_die_ref subr_die;
+ tree fn_arg_types;
+ tree outer_scope;
+ dw_die_ref old_die = lookup_decl_die (decl);
+ int declaration = (current_function_decl != decl
+ || class_or_namespace_scope_p (context_die));
+
+ premark_used_types ();
+
+ /* It is possible to have both DECL_ABSTRACT and DECLARATION be true if we
+ started to generate the abstract instance of an inline, decided to output
+ its containing class, and proceeded to emit the declaration of the inline
+ from the member list for the class. If so, DECLARATION takes priority;
+ we'll get back to the abstract instance when done with the class. */
+
+ /* The class-scope declaration DIE must be the primary DIE. */
+ if (origin && declaration && class_or_namespace_scope_p (context_die))
+ {
+ origin = NULL;
+ gcc_assert (!old_die);
+ }
+
+ /* Now that the C++ front end lazily declares artificial member fns, we
+ might need to retrofit the declaration into its class. */
+ if (!declaration && !origin && !old_die
+ && DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
+ && !class_or_namespace_scope_p (context_die)
+ && debug_info_level > DINFO_LEVEL_TERSE)
+ old_die = force_decl_die (decl);
+
+ if (origin != NULL)
+ {
+ gcc_assert (!declaration || local_scope_p (context_die));
+
+ /* Fixup die_parent for the abstract instance of a nested
+ inline function. */
+ if (old_die && old_die->die_parent == NULL)
+ add_child_die (context_die, old_die);
+
+ subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+ add_abstract_origin_attribute (subr_die, origin);
+ }
+ else if (old_die)
+ {
+ expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+ struct dwarf_file_data * file_index = lookup_filename (s.file);
+
+ if (!get_AT_flag (old_die, DW_AT_declaration)
+ /* We can have a normal definition following an inline one in the
+ case of redefinition of GNU C extern inlines.
+ It seems reasonable to use AT_specification in this case. */
+ && !get_AT (old_die, DW_AT_inline))
+ {
+ /* Detect and ignore this case, where we are trying to output
+ something we have already output. */
+ return;
+ }
+
+ /* If the definition comes from the same place as the declaration,
+ maybe use the old DIE. We always want the DIE for this function
+ that has the *_pc attributes to be under comp_unit_die so the
+ debugger can find it. We also need to do this for abstract
+ instances of inlines, since the spec requires the out-of-line copy
+ to have the same parent. For local class methods, this doesn't
+ apply; we just use the old DIE. */
+ if ((old_die->die_parent == comp_unit_die || context_die == NULL)
+ && (DECL_ARTIFICIAL (decl)
+ || (get_AT_file (old_die, DW_AT_decl_file) == file_index
+ && (get_AT_unsigned (old_die, DW_AT_decl_line)
+ == (unsigned) s.line))))
+ {
+ subr_die = old_die;
+
+ /* Clear out the declaration attribute and the formal parameters.
+ Do not remove all children, because it is possible that this
+ declaration die was forced using force_decl_die(). In such
+ cases die that forced declaration die (e.g. TAG_imported_module)
+ is one of the children that we do not want to remove. */
+ remove_AT (subr_die, DW_AT_declaration);
+ remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+ }
+ else
+ {
+ subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+ add_AT_specification (subr_die, old_die);
+ if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+ add_AT_file (subr_die, DW_AT_decl_file, file_index);
+ if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
+ add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
+ }
+ }
+ else
+ {
+ /* APPLE LOCAL begin radar 6193416 */
+ if (BLOCK_SYNTHESIZED_FUNC (decl))
+ subr_die = new_die (DW_TAG_subprogram, comp_unit_die, decl);
+ else
+ subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+ /* APPLE LOCAL end radar 6193416 */
+
+ if (TREE_PUBLIC (decl))
+ add_AT_flag (subr_die, DW_AT_external, 1);
+
+ add_name_and_src_coords_attributes (subr_die, decl);
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ {
+ add_prototyped_attribute (subr_die, TREE_TYPE (decl));
+ add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
+ 0, 0, context_die);
+ }
+
+ add_pure_or_virtual_attribute (subr_die, decl);
+ if (DECL_ARTIFICIAL (decl))
+ add_AT_flag (subr_die, DW_AT_artificial, 1);
+
+ if (TREE_PROTECTED (decl))
+ add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected);
+ else if (TREE_PRIVATE (decl))
+ add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private);
+ }
+
+ if (declaration)
+ {
+ if (!old_die || !get_AT (old_die, DW_AT_inline))
+ {
+ add_AT_flag (subr_die, DW_AT_declaration, 1);
+
+ /* The first time we see a member function, it is in the context of
+ the class to which it belongs. We make sure of this by emitting
+ the class first. The next time is the definition, which is
+ handled above. The two may come from the same source text.
+
+ Note that force_decl_die() forces function declaration die. It is
+ later reused to represent definition. */
+ equate_decl_number_to_die (decl, subr_die);
+ }
+ }
+ else if (DECL_ABSTRACT (decl))
+ {
+ if (DECL_DECLARED_INLINE_P (decl))
+ {
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
+ else
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
+ }
+ else
+ {
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+ else
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
+ }
+
+ equate_decl_number_to_die (decl, subr_die);
+ }
+ else if (!DECL_EXTERNAL (decl))
+ {
+ HOST_WIDE_INT cfa_fb_offset;
+
+ /* APPLE LOCAL begin dwarf 4444941 */
+ if (TREE_PUBLIC (decl) && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+ && DECL_ABSTRACT_ORIGIN (decl))
+ add_AT_string (subr_die, DW_AT_MIPS_linkage_name,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ /* APPLE LOCAL end dwarf 4444941 */
+
+ if (!old_die || !get_AT (old_die, DW_AT_inline))
+ equate_decl_number_to_die (decl, subr_die);
+
+ if (!flag_reorder_blocks_and_partition)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
+ current_function_funcdef_no);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+ }
+ else
+ { /* Do nothing for now; maybe need to duplicate die, one for
+ hot section and ond for cold section, then use the hot/cold
+ section begin/end labels to generate the aranges... */
+ /*
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, hot_section_label);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, hot_section_end_label);
+ add_AT_lbl_id (subr_die, DW_AT_lo_user, unlikely_section_label);
+ add_AT_lbl_id (subr_die, DW_AT_hi_user, cold_section_end_label);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+ add_arange (decl, subr_die);
+ */
+ }
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* Add a reference to the FDE for this routine. */
+ add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
+#endif
+
+ cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
+
+ /* We define the "frame base" as the function's CFA. This is more
+ convenient for several reasons: (1) It's stable across the prologue
+ and epilogue, which makes it better than just a frame pointer,
+ (2) With dwarf3, there exists a one-byte encoding that allows us
+ to reference the .debug_frame data by proxy, but failing that,
+ (3) We can at least reuse the code inspection and interpretation
+ code that determines the CFA position at various points in the
+ function. */
+ /* ??? Use some command-line or configury switch to enable the use
+ of dwarf3 DW_OP_call_frame_cfa. At present there are no dwarf
+ consumers that understand it; fall back to "pure" dwarf2 and
+ convert the CFA data into a location list. */
+ {
+ dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
+ if (list->dw_loc_next)
+ add_AT_loc_list (subr_die, DW_AT_frame_base, list);
+ else
+ add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
+ }
+
+ /* Compute a displacement from the "steady-state frame pointer" to
+ the CFA. The former is what all stack slots and argument slots
+ will reference in the rtl; the later is what we've told the
+ debugger about. We'll need to adjust all frame_base references
+ by this displacement. */
+ compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
+
+ if (cfun->static_chain_decl)
+ add_AT_location_description (subr_die, DW_AT_static_link,
+ loc_descriptor_from_tree (cfun->static_chain_decl));
+ }
+
+ /* Now output descriptions of the arguments for this function. This gets
+ (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
+ for a FUNCTION_DECL doesn't indicate cases where there was a trailing
+ `...' at the end of the formal parameter list. In order to find out if
+ there was a trailing ellipsis or not, we must instead look at the type
+ associated with the FUNCTION_DECL. This will be a node of type
+ FUNCTION_TYPE. If the chain of type nodes hanging off of this
+ FUNCTION_TYPE node ends with a void_type_node then there should *not* be
+ an ellipsis at the end. */
+
+ /* In the case where we are describing a mere function declaration, all we
+ need to do here (and all we *can* do here) is to describe the *types* of
+ its formal parameters. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ ;
+ else if (declaration)
+ gen_formal_types_die (decl, subr_die);
+ else
+ {
+ /* Generate DIEs to represent all known formal parameters. */
+ tree arg_decls = DECL_ARGUMENTS (decl);
+ tree parm;
+
+ /* When generating DIEs, generate the unspecified_parameters DIE
+ instead if we come across the arg "__builtin_va_alist" */
+ 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);
+ }
+
+ /* Decide whether we need an unspecified_parameters DIE at the end.
+ There are 2 more cases to do this for: 1) the ansi ... declaration -
+ this is detectable when the end of the arg list is not a
+ void_type_node 2) an unprototyped function declaration (not a
+ definition). This just means that we have no info about the
+ parameters at all. */
+ fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ if (fn_arg_types != NULL)
+ {
+ /* This is the prototyped case, check for.... */
+ if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
+ gen_unspecified_parameters_die (decl, subr_die);
+ }
+ else if (DECL_INITIAL (decl) == NULL_TREE)
+ gen_unspecified_parameters_die (decl, subr_die);
+ }
+
+ /* Output Dwarf info for all of the stuff within the body of the function
+ (if it has one - it may be just a declaration). */
+ outer_scope = DECL_INITIAL (decl);
+
+ /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+ a function. This BLOCK actually represents the outermost binding contour
+ for the function, i.e. the contour in which the function's formal
+ parameters and labels get declared. Curiously, it appears that the front
+ end doesn't actually put the PARM_DECL nodes for the current function onto
+ the BLOCK_VARS list for this outer scope, but are strung off of the
+ DECL_ARGUMENTS list for the function instead.
+
+ The BLOCK_VARS list for the `outer_scope' does provide us with a list of
+ the LABEL_DECL nodes for the function however, and we output DWARF info
+ for those in decls_for_scope. Just within the `outer_scope' there will be
+ a BLOCK node representing the function's outermost pair of curly braces,
+ and any blocks used for the base and member initializers of a C++
+ constructor function. */
+ if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
+ {
+ /* Emit a DW_TAG_variable DIE for a named return value. */
+ if (DECL_NAME (DECL_RESULT (decl)))
+ gen_decl_die (DECL_RESULT (decl), subr_die);
+
+ current_function_has_inlines = 0;
+ decls_for_scope (outer_scope, subr_die, 0);
+
+#if 0 && defined (MIPS_DEBUGGING_INFO)
+ if (current_function_has_inlines)
+ {
+ add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
+ if (! comp_unit_has_inlines)
+ {
+ add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
+ comp_unit_has_inlines = 1;
+ }
+ }
+#endif
+ }
+ /* Add the calling convention attribute if requested. */
+ add_calling_convention_attribute (subr_die, TREE_TYPE (decl));
+
+ /* APPLE LOCAL begin radar 2338865 optimization notification */
+ if (optimize > 0)
+ add_AT_flag (subr_die, DW_AT_APPLE_optimized, 1);
+ /* APPLE LOCAL end radar 2338865 optimization notification */
+ /* APPLE LOCAL begin differentiate between arm & thumb. */
+#ifdef TARGET_ARM
+ /* APPLE LOCAL begin 7581650 DW_AT_APPLE_isa should use data1 encoding */
+ if (TARGET_THUMB)
+ add_AT_unsigned (subr_die, DW_AT_APPLE_isa, DW_ISA_ARM_thumb);
+ else if (TARGET_ARM)
+ add_AT_unsigned (subr_die, DW_AT_APPLE_isa, DW_ISA_ARM_arm);
+ /* APPLE LOCAL end 7581650 DW_AT_APPLE_isa should use data1 encoding */
+#endif
+ /* APPLE LOCAL end differentiate between arm & thumb. */
+ /* APPLE LOCAL confused diff */
+}
+/* APPLE LOCAL begin radar 6048397 handle block byref variables */
+
+/* Byref variables, in blocks, are declared by the programmer as
+ "SomeType VarName;", but the compiler creates a
+ __Block_byref_x_VarName struct, and gives the variable VarName
+ either the struct, or a pointer to the struct, as its type. This
+ is necessary for various behind-the-scenes things the compiler
+ needs to do with by-reference variables in blocks.
+
+ However, as far as the original *programmer* is concerned, the
+ variable should still have type 'SomeType', as originally declared.
+
+ The following function dives into the __Block_byref_x_VarName
+ struct to find the original type of the variable. This will be
+ passed back to the code generating the type for the Debug
+ Information Entry for the variable 'VarName'. 'VarName' will then
+ have the original type 'SomeType' in its debug information.
+
+ The original type 'SomeType' will be the type of the field named
+ 'VarName' inside the __Block_byref_x_VarName struct.
+
+ NOTE: In order for this to not completely fail on the debugger
+ side, the Debug Information Entry for the variable VarName needs to
+ have a DW_AT_location that tells the debugger how to unwind through
+ the pointers and __Block_byref_x_VarName struct to find the actual
+ value of the variable. The function
+ add_block_byref_var_location_attribute does this. */
+
+static tree
+find_block_byref_var_real_type (tree decl)
+{
+ tree block_struct = TREE_TYPE (decl);
+ const char *var_name ;
+ tree var_field;
+ bool found = false;
+ tree ret_type = NULL_TREE;
+
+
+ if ((! (DECL_NAME (decl)))
+ || (! IDENTIFIER_POINTER (DECL_NAME (decl))))
+ return ret_type;
+
+ if (!block_struct)
+ return ret_type;
+
+ /* Get the name of the variable whose real type we are trying to find. */
+
+ var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
+
+ /* If the type for the variable was pointer to __Block_byref_etc, then
+ dereference the pointer type to get the structure __Block_byref_etc. */
+
+ if (TREE_CODE (block_struct) == POINTER_TYPE)
+ block_struct = TREE_TYPE (block_struct);
+
+ /* If block_struct is NOT a __Block_byref_etc record, then something is
+ wrong, so we should bail out here. */
+
+ if (TREE_CODE (block_struct) != RECORD_TYPE)
+ return ret_type;
+
+ /* APPLE LOCAL begin radar 6237086 */
+ /* Look for a type name, and make sure it contains the __Block_byref_
+ substring. */
+
+ if (! TYPE_NAME (block_struct))
+ return ret_type;
+
+ if (TREE_CODE (TYPE_NAME (block_struct)) != IDENTIFIER_NODE
+ && TREE_CODE (TYPE_NAME (block_struct)) != TYPE_DECL)
+ return ret_type;
+
+ if (TREE_CODE (TYPE_NAME (block_struct)) == IDENTIFIER_NODE
+ && (strncmp (IDENTIFIER_POINTER (TYPE_NAME (block_struct)),
+ "__Block_byref_", 14) != 0))
+ return ret_type;
+ else if (TREE_CODE (TYPE_NAME (block_struct)) == TYPE_DECL
+ && ((! DECL_NAME (TYPE_NAME (block_struct)))
+ || (strncmp
+ (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (block_struct))),
+ "__Block_byref_", 14) != 0)))
+ return ret_type;
+ /* APPLE LOCAL end radar 6237086 */
+
+ /* We've got the record for a __Byref_block_etc; go through the fields
+ looking for one with the same name as the var_decl. */
+
+ var_field = TYPE_FIELDS (block_struct);
+
+ while (var_field && !found)
+ {
+ if (TREE_CODE (var_field) != FIELD_DECL)
+ return ret_type;
+ if (DECL_NAME (var_field)
+ && IDENTIFIER_POINTER (DECL_NAME (var_field))
+ && strcmp (IDENTIFIER_POINTER (DECL_NAME (var_field)), var_name) == 0)
+ {
+ /* We've found the right field. Return its type. */
+ ret_type = TREE_TYPE (var_field);
+ found = 1;
+ }
+ else
+ var_field = TREE_CHAIN (var_field);
+ }
+
+ return ret_type;
+}
+
+/* APPLE LOCAL begin radar 6237616 */
+/* Called from build_byref_var_location_expression, this function
+ checks to see if the starting location description is of type
+ DW_OP_regX (which, legally, cannot have anything added to it),
+ and if so, changes it to the equivalent DW_OP_bregX + 0, which
+ CAN legally have other stuff added to it. */
+
+static void
+blocks_fixup_location_description (dw_loc_descr_ref *main_descr)
+{
+ dw_loc_descr_ref old_descr;
+ dw_loc_descr_ref new_descr;
+ enum dwarf_location_atom new_op;
+ int regno;
+ unsigned int offset = 0;
+
+ old_descr = *main_descr;
+
+ if (old_descr->dw_loc_opc >= DW_OP_reg0
+ && old_descr->dw_loc_opc <= DW_OP_reg31)
+ {
+ regno = old_descr->dw_loc_opc - DW_OP_reg0;
+ new_op = DW_OP_breg0 + regno;
+ new_descr = new_loc_descr (new_op, offset, 0);
+ *main_descr = new_descr;
+ }
+}
+/* APPLE LOCAL end radar 6237616 */
+
+/* This function is a helper function for the function below,
+ add_block_byref_var_location_attribute. See comments there
+ for full description. */
+
+static void
+build_byref_var_location_expression (dw_loc_descr_ref *main_descr,
+ bool is_pointer,
+ int forwarding_field_offset,
+ int var_field_offset)
+{
+ dw_loc_descr_ref temp_descr;
+
+ /* APPLE LOCAL begin radar 6237616 */
+ /* Make sure main_descr is legal, to start with. */
+
+ blocks_fixup_location_description (main_descr);
+ /* APPLE LOCAL end radar 6237616 */
+
+ /* If we started with a pointer to the __Block_byref... struct, then
+ the first thing we need to do is dereference the pointer
+ (DW_OP_deref). */
+
+ if (is_pointer)
+ {
+ temp_descr = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (main_descr, temp_descr);
+ }
+
+ /* Next add the offset for the 'forwarding' field:
+ DW_OP_plus_uconst forwarding_field_offset
+ Note, there's no point in adding it if the offset is 0. */
+
+ if (forwarding_field_offset != 0)
+ {
+ temp_descr = new_loc_descr (DW_OP_plus_uconst, forwarding_field_offset,
+ 0);
+ add_loc_descr (main_descr, temp_descr);
+ }
+
+ /* Follow that pointer to find the *real* __Block_byref struct:
+ DW_OP_deref */
+
+ temp_descr = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (main_descr, temp_descr);
+
+ /* Now we've got the real __Block_byref struct, add the offset for
+ the variable's field to get the location of the actual variable:
+ DW_OP_plus_uconst var_field_offset
+ Again, there's no point in adding the offset if it is 0. */
+
+ if (var_field_offset != 0)
+ {
+ temp_descr = new_loc_descr (DW_OP_plus_uconst, var_field_offset, 0);
+ add_loc_descr (main_descr, temp_descr);
+ }
+}
+
+/* Byref variables, in blocks, are declared by the programmer as
+ "SomeType VarName;", but the compiler creates a
+ __Block_byref_x_VarName struct, and gives the variable VarName
+ either the struct, or a pointer to the struct, as its type. This
+ is necessary for various behind-the-scenes things the compiler
+ needs to do with by-reference variables in blocks.
+
+ However, as far as the original *programmer* is concerned, the
+ variable should still have type 'SomeType', as originally declared.
+
+ The function find_block_byref_var_real_type dives into the
+ __Block_byref_x_VarName struct to find the original type of the
+ variable, which is then assigned to the variable's Debug
+ Information Entry as its real type. So far, so good. However now
+ the debugger will expect the variable VarName to have the type
+ SomeType. So we need the location attribute for the variable to be
+ an expression that explains to the debugger how to navigate through
+ the pointers and struct to find the actual variable of type
+ SomeType.
+
+ The following function does just that. We start by getting
+ the "normal" location for the variable. This will be the location
+ of either the struct __Block_byref_x_VarName or the pointer to the
+ struct __Block_byref_x_VarName.
+
+ The struct will look something like:
+
+ struct __Block_byref_x_VarName {
+ struct __Block_byref_x_VarName *forwarding;
+ ... <various irrelevant fields>
+ SomeType VarName;
+ };
+
+ If we are given the struct directly (as our starting point) we
+ need to tell the debugger to:
+
+ 1). Add the offset of the forwarding field (do NOT assume the field
+ will always be as position 0).
+
+ 2). Follow that pointer to get the the real __Block_byref_x_VarName
+ struct to use (the real one may have been copied onto the heap).
+
+ 3). Add the offset for the field VarName, to find the actual variable.
+
+ If we started with a pointer to the struct, then we need to
+ derefernce (follow) that pointer first, before the other steps.
+ Translating this into DWARF ops, we will need to append the following
+ to the current location description for the variable:
+
+ DW_OP_deref -- optional, if we start with a pointer
+ DW_OP_plus_uconst <forward_fld_offset>
+ DW_OP_deref
+ DW_OP_plus_uconst <varName_fld_offset>
+
+ This function returns a boolean indicating whether or not it was
+ able to successfully create and add the location description. */
+
+static bool
+add_block_byref_var_location_attribute (dw_die_ref var_die, tree decl)
+{
+ tree block_struct = TREE_TYPE (decl);
+ const char *var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
+ tree var_field = NULL;
+ tree forwarding_field = NULL;
+ tree temp_field;
+ unsigned int forwarding_field_offset = 0;
+ unsigned int var_field_offset = 0;
+ bool is_pointer = false;
+ dw_loc_descr_ref descr;
+ var_loc_list *loc_list;
+
+ if (!block_struct)
+ return false;
+
+ if ((! DECL_NAME (decl))
+ || (! IDENTIFIER_POINTER (DECL_NAME (decl))))
+ return false;
+
+ /* Get the name of the variable whose location we are decoding. */
+
+ var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
+
+ if (TREE_CODE (block_struct) == POINTER_TYPE)
+ block_struct = TREE_TYPE (block_struct);
+
+ /* Verify that we have a record that is a __Block_byref_... */
+
+ if (TREE_CODE (block_struct) != RECORD_TYPE)
+ return false;
+
+ /* APPLE LOCAL begin radar 6237086 */
+ /* Look for a type name, and make sure it contains the __Block_byref_
+ substring. */
+
+ if (! TYPE_NAME (block_struct))
+ return false;
+
+ if (TREE_CODE (TYPE_NAME (block_struct)) != IDENTIFIER_NODE
+ && TREE_CODE (TYPE_NAME (block_struct)) != TYPE_DECL)
+ return false;
+
+ if (TREE_CODE (TYPE_NAME (block_struct)) == IDENTIFIER_NODE
+ && (strncmp (IDENTIFIER_POINTER (TYPE_NAME (block_struct)),
+ "__Block_byref_", 14) != 0))
+ return false;
+ else if (TREE_CODE (TYPE_NAME (block_struct)) == TYPE_DECL
+ && ((! DECL_NAME (TYPE_NAME (block_struct)))
+ || (strncmp
+ (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (block_struct))),
+ "__Block_byref_", 14) != 0)))
+ return false;
+ /* APPLE LOCAL end radar 6237086 */
+
+ /* Find the forwarding field and the variable field within
+ the struct. */
+
+ temp_field = TYPE_FIELDS (block_struct);
+
+ while (temp_field
+ && (!var_field || !forwarding_field))
+ {
+ if (TREE_CODE (temp_field) != FIELD_DECL)
+ return false;
+ if (DECL_NAME (temp_field)
+ && IDENTIFIER_POINTER (DECL_NAME (temp_field)))
+ {
+ if (strcmp (IDENTIFIER_POINTER (DECL_NAME (temp_field)),
+ var_name) == 0)
+ var_field = temp_field;
+ else if (strcmp (IDENTIFIER_POINTER (DECL_NAME (temp_field)),
+ "__forwarding") == 0)
+ forwarding_field = temp_field;
+ }
+
+ temp_field = TREE_CHAIN (temp_field);
+ }
+
+ /* If we didn't find both fields, we can't continue. */
+
+ if (!var_field || !forwarding_field)
+ return false;
+
+ /* Get the offsets of the fields within the struct. */
+
+ if (var_field)
+ var_field_offset = field_byte_offset (var_field);
+ if (forwarding_field)
+ forwarding_field_offset = field_byte_offset (forwarding_field);
+
+ /* Check to see if we start with a pointer we need to dereference,
+ or not. */
+
+ if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
+ is_pointer = true;
+
+ /* See if we possible have multiple locations for this variable. */
+ loc_list = lookup_decl_loc (decl);
+
+ /* If it truly has multiple locations, the first and last node will
+ differ. */
+ if (loc_list && loc_list->first != loc_list->last)
+ {
+ struct var_loc_node *node;
+ rtx varloc;
+ dw_loc_list_ref list;
+ const char *endname, *secname;
+
+ /* Build the first entry for the location list. */
+
+ node = loc_list->first;
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ secname = secname_for_decl (decl);
+
+ descr = loc_descriptor (varloc, STATUS_INITIALIZED);
+ build_byref_var_location_expression (&descr, is_pointer,
+ forwarding_field_offset,
+ var_field_offset);
+ list = new_loc_list (descr, node->label, node->next->label, secname, 1);
+ node = node->next;
+
+ for (; node->next; node = node->next)
+
+ /* Build the other entries for the location list, except the last. */
+
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ descr = loc_descriptor (varloc, STATUS_INITIALIZED);
+ build_byref_var_location_expression (&descr, is_pointer,
+ forwarding_field_offset,
+ var_field_offset);
+ add_loc_descr_to_loc_list (&list, descr, node->label,
+ node->next->label, secname);
+ }
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ /* Build the last entry for the location list. */
+
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ if (!current_function_decl)
+ endname = text_end_label;
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ endname = ggc_strdup (label_id);
+ }
+ descr = loc_descriptor (varloc, STATUS_INITIALIZED);
+ build_byref_var_location_expression (&descr, is_pointer,
+ forwarding_field_offset,
+ var_field_offset);
+ add_loc_descr_to_loc_list (&list, descr, node->label, endname,
+ secname);
+ }
+ add_AT_loc_list (var_die, DW_AT_location, list);
+ }
+ else
+ {
+ /* We are not dealing with a location list so... */
+
+ /* 'descr' starts with the base location of the __Block_byref_... struct,
+ or the pointer to the __Block_byref_... struct. */
+
+ descr = loc_descriptor_from_tree (decl);
+ if (!descr)
+ return false;
+
+ build_byref_var_location_expression (&descr, is_pointer,
+ forwarding_field_offset,
+ var_field_offset);
+
+ /* Finally, now that we've built up the location description to find the
+ actual value of the variable, add the location description to the
+ variable's die. */
+
+ add_AT_location_description (var_die, DW_AT_location, descr);
+ }
+
+ return true;
+}
+/* APPLE LOCAL end radar 6048397 handle block byref variables */
+
+/* Generate a DIE to represent a declared data object. */
+
+static void
+gen_variable_die (tree decl, dw_die_ref context_die)
+{
+ /* APPLE LOCAL begin radar 6048397 handle block byref variables */
+ bool is_block_byref_var = false;
+ tree decl_type = TREE_TYPE (decl);
+ /* APPLE LOCAL end radar 6048397 handle block byref variables */
+ tree origin = decl_ultimate_origin (decl);
+ dw_die_ref var_die = new_die (DW_TAG_variable, context_die, decl);
+
+ dw_die_ref old_die = lookup_decl_die (decl);
+ int declaration = (DECL_EXTERNAL (decl)
+ /* If DECL is COMDAT and has not actually been
+ emitted, we cannot take its address; there
+ might end up being no definition anywhere in
+ the program. For example, consider the C++
+ test case:
+
+ template <class T>
+ struct S { static const int i = 7; };
+
+ template <class T>
+ const int S<T>::i;
+
+ int f() { return S<int>::i; }
+
+ Here, S<int>::i is not DECL_EXTERNAL, but no
+ definition is required, so the compiler will
+ not emit a definition. */
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
+ || class_or_namespace_scope_p (context_die));
+
+ /* APPLE LOCAL begin radar 6048397 handle block byref variables */
+ /* Check to see if this variable is for a block passed-by-refernce
+ variable, in which case we need to do some special stuff for its
+ type and location. */
+ if (decl_type)
+ {
+ if (TREE_CODE (decl_type) == POINTER_TYPE)
+ decl_type = TREE_TYPE (decl_type);
+ /* APPLE LOCAL begin radar 6237086 */
+ if (decl_type
+ && TREE_CODE (decl_type) == RECORD_TYPE
+ && TYPE_NAME (decl_type))
+ {
+ if (TREE_CODE (TYPE_NAME (decl_type)) == IDENTIFIER_NODE
+ && strncmp (IDENTIFIER_POINTER (TYPE_NAME (decl_type)),
+ "__Block_byref_", 14) == 0)
+ is_block_byref_var = true;
+ else if (TREE_CODE (TYPE_NAME (decl_type)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (decl_type))
+ && IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl_type)))
+ && (strncmp
+ (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl_type))),
+ "__Block_byref_", 14) == 0))
+ is_block_byref_var = true;
+ else
+ is_block_byref_var = false;
+ }
+ /* APPLE LOCAL end radar 6237086 */
+ }
+ /* APPLE LOCAL end radar 6048397 handle block byref variables */
+ /* APPLE LOCAL begin radar 5964438 */
+ /* Don't try to add a reference to the abstract origin die if the
+ die hasn't been created. */
+ if ((origin != NULL) && lookup_decl_die (origin))
+ add_abstract_origin_attribute (var_die, origin);
+ /* APPLE LOCAL end radar 5964438 */
+
+ /* Loop unrolling can create multiple blocks that refer to the same
+ static variable, so we must test for the DW_AT_declaration flag.
+
+ ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
+ copy decls and set the DECL_ABSTRACT flag on them instead of
+ sharing them.
+
+ ??? Duplicated blocks have been rewritten to use .debug_ranges.
+
+ ??? The declare_in_namespace support causes us to get two DIEs for one
+ variable, both of which are declarations. We want to avoid considering
+ one to be a specification, so we must test that this DIE is not a
+ declaration. */
+ else if (old_die && TREE_STATIC (decl) && ! declaration
+ && get_AT_flag (old_die, DW_AT_declaration) == 1)
+ {
+ /* This is a definition of a C++ class level static. */
+ add_AT_specification (var_die, old_die);
+ if (DECL_NAME (decl))
+ {
+ expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+ struct dwarf_file_data * file_index = lookup_filename (s.file);
+
+ if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+ add_AT_file (var_die, DW_AT_decl_file, file_index);
+
+ if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
+
+ add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
+ }
+ }
+ else
+ {
+ add_name_and_src_coords_attributes (var_die, decl);
+ /* APPLE LOCAL begin radar 6048397 handle block byref variables */
+ if (is_block_byref_var)
+ {
+ /* Try to find the real type for the variable; if we can't find
+ it, fall back on the old behavior. */
+ tree real_type = NULL_TREE;
+ real_type = find_block_byref_var_real_type (decl);
+ if (real_type)
+ add_type_attribute (var_die, real_type, TREE_READONLY (decl),
+ TREE_THIS_VOLATILE (decl), context_die);
+ else
+ add_type_attribute (var_die, TREE_TYPE (decl), TREE_READONLY (decl),
+ TREE_THIS_VOLATILE (decl), context_die);
+ }
+ else
+ add_type_attribute (var_die, TREE_TYPE (decl), TREE_READONLY (decl),
+ TREE_THIS_VOLATILE (decl), context_die);
+ /* APPLE LOCAL end radar 6048397 handle block byref variables */
+
+ if (TREE_PUBLIC (decl))
+ add_AT_flag (var_die, DW_AT_external, 1);
+
+ if (DECL_ARTIFICIAL (decl))
+ add_AT_flag (var_die, DW_AT_artificial, 1);
+
+ if (TREE_PROTECTED (decl))
+ add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected);
+ else if (TREE_PRIVATE (decl))
+ add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private);
+ }
+
+ if (declaration)
+ add_AT_flag (var_die, DW_AT_declaration, 1);
+
+ if (DECL_ABSTRACT (decl) || declaration)
+ equate_decl_number_to_die (decl, var_die);
+
+ if (! declaration && ! DECL_ABSTRACT (decl))
+ {
+ /* APPLE LOCAL begin radar 6048397 handle block byref variables */
+ /* Try to build and add the location info for navigating through
+ a __Block_byref_... struct to find the real variable. If that
+ fails, fall back on the old behavior. */
+ bool loc_added = false;
+ if (is_block_byref_var)
+ loc_added = add_block_byref_var_location_attribute (var_die, decl);
+ if (!loc_added)
+ add_location_or_const_value_attribute (var_die, decl, DW_AT_location);
+ /* APPLE LOCAL end radar 6048397 handle block byref variables */
+ add_pubname (decl, var_die);
+ }
+ else
+ tree_add_const_value_attribute (var_die, decl);
+}
+
+/* Generate a DIE to represent a label identifier. */
+
+static void
+gen_label_die (tree decl, dw_die_ref context_die)
+{
+ tree origin = decl_ultimate_origin (decl);
+ dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+ rtx insn;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (origin != NULL)
+ add_abstract_origin_attribute (lbl_die, origin);
+ else
+ add_name_and_src_coords_attributes (lbl_die, decl);
+
+ if (DECL_ABSTRACT (decl))
+ equate_decl_number_to_die (decl, lbl_die);
+ else
+ {
+ insn = DECL_RTL_IF_SET (decl);
+
+ /* Deleted labels are programmer specified labels which have been
+ eliminated because of various optimizations. We still emit them
+ here so that it is possible to put breakpoints on them. */
+ if (insn
+ && (LABEL_P (insn)
+ || ((NOTE_P (insn)
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))))
+ {
+ /* When optimization is enabled (via -O) some parts of the compiler
+ (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
+ represent source-level labels which were explicitly declared by
+ the user. This really shouldn't be happening though, so catch
+ it if it ever does happen. */
+ gcc_assert (!INSN_DELETED_P (insn));
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
+ add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+ }
+ }
+}
+
+/* A helper function for gen_inlined_subroutine_die. Add source coordinate
+ attributes to the DIE for a block STMT, to describe where the inlined
+ function was called from. This is similar to add_src_coords_attributes. */
+
+static inline void
+add_call_src_coords_attributes (tree stmt, dw_die_ref die)
+{
+ expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
+
+ add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
+ add_AT_unsigned (die, DW_AT_call_line, s.line);
+}
+
+/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
+ Add low_pc and high_pc attributes to the DIE for a block STMT. */
+
+static inline void
+add_high_low_attributes (tree stmt, dw_die_ref die)
+{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (BLOCK_FRAGMENT_CHAIN (stmt))
+ {
+ tree chain;
+
+ add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
+
+ chain = BLOCK_FRAGMENT_CHAIN (stmt);
+ do
+ {
+ add_ranges (chain);
+ chain = BLOCK_FRAGMENT_CHAIN (chain);
+ }
+ while (chain);
+ add_ranges (NULL);
+ }
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_low_pc, label);
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_high_pc, label);
+ }
+}
+
+/* Generate a DIE for a lexical block. */
+
+static void
+gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+{
+ dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+
+ if (! BLOCK_ABSTRACT (stmt))
+ add_high_low_attributes (stmt, stmt_die);
+
+ decls_for_scope (stmt, stmt_die, depth);
+}
+
+/* Generate a DIE for an inlined subprogram. */
+
+static void
+gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
+{
+ tree decl = block_ultimate_origin (stmt);
+
+ /* Emit info for the abstract instance first, if we haven't yet. We
+ must emit this even if the block is abstract, otherwise when we
+ emit the block below (or elsewhere), we may end up trying to emit
+ a die whose origin die hasn't been emitted, and crashing. */
+ dwarf2out_abstract_function (decl);
+
+ if (! BLOCK_ABSTRACT (stmt))
+ {
+ dw_die_ref subr_die
+ = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
+
+ add_abstract_origin_attribute (subr_die, decl);
+ add_high_low_attributes (stmt, subr_die);
+ add_call_src_coords_attributes (stmt, subr_die);
+
+ decls_for_scope (stmt, subr_die, depth);
+ current_function_has_inlines = 1;
+ /* APPLE LOCAL radar 6275985 debug inlined section */
+ add_inlined_section_entry (subr_die);
+ }
+ else
+ /* We may get here if we're the outer block of function A that was
+ inlined into function B that was inlined into function C. When
+ generating debugging info for C, dwarf2out_abstract_function(B)
+ would mark all inlined blocks as abstract, including this one.
+ So, we wouldn't (and shouldn't) expect labels to be generated
+ for this one. Instead, just emit debugging info for
+ declarations within the block. This is particularly important
+ in the case of initializers of arguments passed from B to us:
+ if they're statement expressions containing declarations, we
+ wouldn't generate dies for their abstract variables, and then,
+ when generating dies for the real variables, we'd die (pun
+ intended :-) */
+ gen_lexical_block_die (stmt, context_die, depth);
+}
+
+/* Generate a DIE for a field in a record, or structure. */
+
+static void
+gen_field_die (tree decl, dw_die_ref context_die)
+{
+ dw_die_ref decl_die;
+
+ if (TREE_TYPE (decl) == error_mark_node)
+ return;
+
+ decl_die = new_die (DW_TAG_member, context_die, decl);
+ add_name_and_src_coords_attributes (decl_die, decl);
+ add_type_attribute (decl_die, member_declared_type (decl),
+ TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
+ context_die);
+
+ if (DECL_BIT_FIELD_TYPE (decl))
+ {
+ add_byte_size_attribute (decl_die, decl);
+ add_bit_size_attribute (decl_die, decl);
+ add_bit_offset_attribute (decl_die, decl);
+ }
+
+ if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
+ add_data_member_location_attribute (decl_die, decl);
+
+ if (DECL_ARTIFICIAL (decl))
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+
+ if (TREE_PROTECTED (decl))
+ add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
+ else if (TREE_PRIVATE (decl))
+ add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
+
+ /* Equate decl number to die, so that we can look up this decl later on. */
+ equate_decl_number_to_die (decl, decl_die);
+}
+
+#if 0
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+ Use modified_type_die instead.
+ We keep this code here just in case these types of DIEs may be needed to
+ represent certain things in other languages (e.g. Pascal) someday. */
+
+static void
+gen_pointer_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref ptr_die
+ = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die), type);
+
+ equate_type_number_to_die (type, ptr_die);
+ add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+}
+
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+ Use modified_type_die instead.
+ We keep this code here just in case these types of DIEs may be needed to
+ represent certain things in other languages (e.g. Pascal) someday. */
+
+static void
+gen_reference_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref ref_die
+ = new_die (DW_TAG_reference_type, scope_die_for (type, context_die), type);
+
+ equate_type_number_to_die (type, ref_die);
+ add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+}
+#endif
+
+/* Generate a DIE for a pointer to a member type. */
+
+static void
+gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref ptr_die
+ = new_die (DW_TAG_ptr_to_member_type,
+ scope_die_for (type, context_die), type);
+
+ equate_type_number_to_die (type, ptr_die);
+ add_AT_die_ref (ptr_die, DW_AT_containing_type,
+ lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
+ add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+}
+
+/* Generate the DIE for the compilation unit. */
+
+static dw_die_ref
+gen_compile_unit_die (const char *filename)
+{
+ dw_die_ref die;
+ char producer[250];
+ const char *language_string = lang_hooks.name;
+ int language;
+
+ die = new_die (DW_TAG_compile_unit, NULL, NULL);
+
+ if (filename)
+ {
+ add_name_attribute (die, filename);
+ /* Don't add cwd for <built-in>. */
+ if (filename[0] != DIR_SEPARATOR && filename[0] != '<')
+ add_comp_dir_attribute (die);
+ }
+
+ sprintf (producer, "%s %s", language_string, version_string);
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* The MIPS/SGI compilers place the 'cc' command line options in the producer
+ string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do
+ not appear in the producer string, the debugger reaches the conclusion
+ that the object file is stripped and has no debugging information.
+ To get the MIPS/SGI debugger to believe that there is debugging
+ information in the object file, we add a -g to the producer string. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ strcat (producer, " -g");
+#endif
+
+ add_AT_string (die, DW_AT_producer, producer);
+
+ if (strcmp (language_string, "GNU C++") == 0)
+ language = DW_LANG_C_plus_plus;
+ else if (strcmp (language_string, "GNU Ada") == 0)
+ language = DW_LANG_Ada95;
+ else if (strcmp (language_string, "GNU F77") == 0)
+ language = DW_LANG_Fortran77;
+ else if (strcmp (language_string, "GNU F95") == 0)
+ language = DW_LANG_Fortran95;
+ else if (strcmp (language_string, "GNU Pascal") == 0)
+ language = DW_LANG_Pascal83;
+ else if (strcmp (language_string, "GNU Java") == 0)
+ language = DW_LANG_Java;
+ else if (strcmp (language_string, "GNU Objective-C") == 0)
+ language = DW_LANG_ObjC;
+ else if (strcmp (language_string, "GNU Objective-C++") == 0)
+ language = DW_LANG_ObjC_plus_plus;
+ else
+ language = DW_LANG_C89;
+
+ add_AT_unsigned (die, DW_AT_language, language);
+ return die;
+}
+
+/* Generate the DIE for a base class. */
+
+static void
+gen_inheritance_die (tree binfo, tree access, dw_die_ref context_die)
+{
+ dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
+
+ add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
+ add_data_member_location_attribute (die, binfo);
+
+ if (BINFO_VIRTUAL_P (binfo))
+ add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+
+ if (access == access_public_node)
+ add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
+ else if (access == access_protected_node)
+ add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
+}
+
+/* Generate a DIE for a class member. */
+
+static void
+gen_member_die (tree type, dw_die_ref context_die)
+{
+ tree member;
+ tree binfo = TYPE_BINFO (type);
+ dw_die_ref child;
+
+ /* If this is not an incomplete type, output descriptions of each of its
+ members. Note that as we output the DIEs necessary to represent the
+ members of this record or union type, we will also be trying to output
+ DIEs to represent the *types* of those members. However the `type'
+ function (above) will specifically avoid generating type DIEs for member
+ types *within* the list of member DIEs for this (containing) type except
+ for those types (of members) which are explicitly marked as also being
+ members of this (containing) type themselves. The g++ front- end can
+ force any given type to be treated as a member of some other (containing)
+ type by setting the TYPE_CONTEXT of the given (member) type to point to
+ the TREE node representing the appropriate (containing) type. */
+
+ /* First output info about the base classes. */
+ if (binfo)
+ {
+ VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo);
+ int i;
+ tree base;
+
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); i++)
+ gen_inheritance_die (base,
+ (accesses ? VEC_index (tree, accesses, i)
+ : access_public_node), context_die);
+ }
+
+ /* Now output info about the data members and type members. */
+ for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
+ {
+ /* If we thought we were generating minimal debug info for TYPE
+ and then changed our minds, some of the member declarations
+ may have already been defined. Don't define them again, but
+ do put them in the right order. */
+
+ child = lookup_decl_die (member);
+ if (child)
+ splice_child_die (context_die, child);
+ else
+ gen_decl_die (member, context_die);
+ }
+
+ /* Now output info about the function members (if any). */
+ for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
+ {
+ /* Don't include clones in the member list. */
+ if (DECL_ABSTRACT_ORIGIN (member))
+ continue;
+
+ child = lookup_decl_die (member);
+ if (child)
+ splice_child_die (context_die, child);
+ else
+ gen_decl_die (member, context_die);
+ }
+}
+
+/* Generate a DIE for a structure or union type. If TYPE_DECL_SUPPRESS_DEBUG
+ is set, we pretend that the type was never defined, so we only get the
+ member DIEs needed by later specification DIEs. */
+
+static void
+gen_struct_or_union_type_die (tree type, dw_die_ref context_die)
+{
+ dw_die_ref type_die = lookup_type_die (type);
+ dw_die_ref scope_die = 0;
+ int nested = 0;
+ int complete = (TYPE_SIZE (type)
+ && (! TYPE_STUB_DECL (type)
+ || ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))));
+ int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace);
+
+ if (type_die && ! complete)
+ return;
+
+ if (TYPE_CONTEXT (type) != NULL_TREE
+ && (AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
+ || TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL))
+ nested = 1;
+
+ scope_die = scope_die_for (type, context_die);
+
+ if (! type_die || (nested && scope_die == comp_unit_die))
+ /* First occurrence of type or toplevel definition of nested class. */
+ {
+ dw_die_ref old_die = type_die;
+
+ type_die = new_die (TREE_CODE (type) == RECORD_TYPE
+ ? DW_TAG_structure_type : DW_TAG_union_type,
+ scope_die, type);
+ equate_type_number_to_die (type, type_die);
+ if (old_die)
+ add_AT_specification (type_die, old_die);
+ else
+ add_name_attribute (type_die, type_tag (type));
+
+ /* APPLE LOCAL begin radar 5811943 - Fix type of pointers to Blocks */
+ if (TYPE_BLOCK_IMPL_STRUCT (type))
+ add_AT_flag (type_die, DW_AT_APPLE_block, 1);
+ /* APPLE LOCAL end radar 5811943 - Fix type of pointers to Blocks */
+ /* APPLE LOCAL begin radar 6386976 */
+ if (TYPE_LANG_SPECIFIC (type)
+ && (type_die->die_tag == DW_TAG_structure_type)
+ && lang_hooks.types.is_runtime_specific_type (type))
+ {
+ if (is_objcxx ())
+ add_AT_unsigned (type_die, DW_AT_APPLE_runtime_class,
+ DW_LANG_ObjC_plus_plus);
+ else if (is_objc ())
+ add_AT_unsigned (type_die, DW_AT_APPLE_runtime_class,
+ DW_LANG_ObjC);
+ else if (is_cxx())
+ add_AT_unsigned (type_die, DW_AT_APPLE_runtime_class,
+ DW_LANG_C_plus_plus);
+ }
+ /* APPLE LOCAL end radar 6386976 */
+ }
+ else
+ remove_AT (type_die, DW_AT_declaration);
+
+ /* If this type has been completed, then give it a byte_size attribute and
+ then give a list of members. */
+ if (complete && !ns_decl)
+ {
+ /* Prevent infinite recursion in cases where the type of some member of
+ this type is expressed in terms of this type itself. */
+ TREE_ASM_WRITTEN (type) = 1;
+ add_byte_size_attribute (type_die, type);
+ if (TYPE_STUB_DECL (type) != NULL_TREE)
+ add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+
+ /* If the first reference to this type was as the return type of an
+ inline function, then it may not have a parent. Fix this now. */
+ 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 ();
+
+ /* GNU extension: Record what type our vtable lives in. */
+ 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);
+
+ /* We don't need to do this for function-local types. */
+ if (TYPE_STUB_DECL (type)
+ && ! decl_function_context (TYPE_STUB_DECL (type)))
+ VEC_safe_push (tree, gc, incomplete_types, type);
+ }
+
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ if (get_AT (type_die, DW_AT_name))
+ add_pubtype (type, type_die);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+}
+
+/* Generate a DIE for a subroutine _type_. */
+
+static void
+gen_subroutine_type_die (tree type, dw_die_ref context_die)
+{
+ tree return_type = TREE_TYPE (type);
+ dw_die_ref subr_die
+ = new_die (DW_TAG_subroutine_type,
+ scope_die_for (type, context_die), type);
+
+ equate_type_number_to_die (type, subr_die);
+ add_prototyped_attribute (subr_die, type);
+ add_type_attribute (subr_die, return_type, 0, 0, context_die);
+ gen_formal_types_die (type, subr_die);
+
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ if (get_AT (subr_die, DW_AT_name))
+ add_pubtype (type, subr_die);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+}
+
+/* Generate a DIE for a type definition. */
+
+static void
+gen_typedef_die (tree decl, dw_die_ref context_die)
+{
+ dw_die_ref type_die;
+ tree origin;
+ /* APPLE LOCAL pubtypes, radar 5619139 */
+ bool type_is_complete_p = true;
+
+ if (TREE_ASM_WRITTEN (decl))
+ return;
+
+ TREE_ASM_WRITTEN (decl) = 1;
+ type_die = new_die (DW_TAG_typedef, context_die, decl);
+ origin = decl_ultimate_origin (decl);
+ if (origin != NULL)
+ add_abstract_origin_attribute (type_die, origin);
+ else
+ {
+ tree type;
+
+ add_name_and_src_coords_attributes (type_die, decl);
+ if (DECL_ORIGINAL_TYPE (decl))
+ {
+ type = DECL_ORIGINAL_TYPE (decl);
+
+ gcc_assert (type != TREE_TYPE (decl));
+ equate_type_number_to_die (TREE_TYPE (decl), type_die);
+ }
+ else
+ type = TREE_TYPE (decl);
+
+ /* APPLE LOCAL begin pubtypes, radar 5619139 */
+ type_is_complete_p = COMPLETE_TYPE_P (type);
+ /* APPLE LOCAL end pubtypes, radar 5619139 */
+
+ 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);
+
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ /* Only add typedef type to pubtypes table if the type it is renaming
+ is fully defined in the current file. Radar 5619139 */
+ if (get_AT (type_die, DW_AT_name)
+ && type_is_complete_p)
+ add_pubtype (decl, type_die);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+}
+
+/* Generate a type description DIE. */
+
+static void
+gen_type_die (tree type, dw_die_ref context_die)
+{
+ int need_pop;
+
+ if (type == NULL_TREE || type == error_mark_node)
+ return;
+
+ if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+ {
+ if (TREE_ASM_WRITTEN (type))
+ return;
+
+ /* Prevent broken recursion; we can't hand off to the same type. */
+ gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
+
+ TREE_ASM_WRITTEN (type) = 1;
+ gen_decl_die (TYPE_NAME (type), context_die);
+ return;
+ }
+
+ /* We are going to output a DIE to represent the unqualified version
+ of this type (i.e. without any const or volatile qualifiers) so
+ get the main variant (i.e. the unqualified version) of this type
+ now. (Vectors are special because the debugging info is in the
+ cloned type itself). */
+ if (TREE_CODE (type) != VECTOR_TYPE)
+ type = type_main_variant (type);
+
+ if (TREE_ASM_WRITTEN (type))
+ return;
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ break;
+
+ /* APPLE LOCAL radar 5732232 - blocks */
+ case BLOCK_POINTER_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This
+ ensures that the gen_type_die recursion will terminate even if the
+ type is recursive. Recursive types are possible in Ada. */
+ /* ??? We could perhaps do this for all types before the switch
+ statement. */
+ TREE_ASM_WRITTEN (type) = 1;
+
+ /* For these types, all that is required is that we output a DIE (or a
+ set of DIEs) to represent the "basis" type. */
+ gen_type_die (TREE_TYPE (type), context_die);
+ break;
+
+ case OFFSET_TYPE:
+ /* This code is used for C++ pointer-to-data-member types.
+ Output a description of the relevant class type. */
+ gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die);
+
+ /* Output a description of the type of the object pointed to. */
+ gen_type_die (TREE_TYPE (type), context_die);
+
+ /* Now output a DIE to represent this pointer-to-data-member type
+ itself. */
+ gen_ptr_to_mbr_type_die (type, context_die);
+ break;
+
+ case FUNCTION_TYPE:
+ /* Force out return type (in case it wasn't forced out already). */
+ gen_type_die (TREE_TYPE (type), context_die);
+ gen_subroutine_type_die (type, context_die);
+ break;
+
+ case METHOD_TYPE:
+ /* Force out return type (in case it wasn't forced out already). */
+ gen_type_die (TREE_TYPE (type), context_die);
+ gen_subroutine_type_die (type, context_die);
+ break;
+
+ case ARRAY_TYPE:
+ gen_array_type_die (type, context_die);
+ break;
+
+ case VECTOR_TYPE:
+ gen_array_type_die (type, context_die);
+ break;
+
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ /* If this is a nested type whose containing class hasn't been written
+ out yet, writing it out will cover this one, too. This does not apply
+ to instantiations of member class templates; they need to be added to
+ the containing class as they are generated. FIXME: This hurts the
+ idea of combining type decls from multiple TUs, since we can't predict
+ what set of template instantiations we'll get. */
+ if (TYPE_CONTEXT (type)
+ && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
+ && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+ {
+ gen_type_die (TYPE_CONTEXT (type), context_die);
+
+ if (TREE_ASM_WRITTEN (type))
+ return;
+
+ /* If that failed, attach ourselves to the stub. */
+ push_decl_scope (TYPE_CONTEXT (type));
+ context_die = lookup_type_die (TYPE_CONTEXT (type));
+ need_pop = 1;
+ }
+ else
+ {
+ declare_in_namespace (type, context_die);
+ need_pop = 0;
+ }
+
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ /* This might have been written out by the call to
+ declare_in_namespace. */
+ if (!TREE_ASM_WRITTEN (type))
+ gen_enumeration_type_die (type, context_die);
+ }
+ else
+ gen_struct_or_union_type_die (type, context_die);
+
+ if (need_pop)
+ pop_decl_scope ();
+
+ /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
+ it up if it is ever completed. gen_*_type_die will set it for us
+ when appropriate. */
+ return;
+
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ /* No DIEs needed for fundamental types. */
+ break;
+
+ case LANG_TYPE:
+ /* No Dwarf representation currently defined. */
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ TREE_ASM_WRITTEN (type) = 1;
+}
+
+/* Generate a DIE for a tagged type instantiation. */
+
+static void
+gen_tagged_type_instantiation_die (tree type, dw_die_ref context_die)
+{
+ if (type == NULL_TREE || type == error_mark_node)
+ return;
+
+ /* We are going to output a DIE to represent the unqualified version of
+ this type (i.e. without any const or volatile qualifiers) so make sure
+ that we have the main variant (i.e. the unqualified version) of this
+ type now. */
+ gcc_assert (type == type_main_variant (type));
+
+ /* Do not check TREE_ASM_WRITTEN (type) as it may not be set if this is
+ an instance of an unresolved type. */
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ break;
+
+ case ENUMERAL_TYPE:
+ gen_inlined_enumeration_type_die (type, context_die);
+ break;
+
+ case RECORD_TYPE:
+ gen_inlined_structure_type_die (type, context_die);
+ break;
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ gen_inlined_union_type_die (type, context_die);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
+ things which are local to the given block. */
+
+static void
+gen_block_die (tree stmt, dw_die_ref context_die, int depth)
+{
+ int must_output_die = 0;
+ tree origin;
+ tree decl;
+ enum tree_code origin_code;
+
+ /* Ignore blocks that are NULL. */
+ if (stmt == NULL_TREE)
+ return;
+
+ /* If the block is one fragment of a non-contiguous block, do not
+ process the variables, since they will have been done by the
+ origin block. Do process subblocks. */
+ if (BLOCK_FRAGMENT_ORIGIN (stmt))
+ {
+ tree sub;
+
+ for (sub = BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
+ gen_block_die (sub, context_die, depth + 1);
+
+ return;
+ }
+
+ /* Determine the "ultimate origin" of this block. This block may be an
+ inlined instance of an inlined instance of inline function, so we have
+ to trace all of the way back through the origin chain to find out what
+ sort of node actually served as the original seed for the creation of
+ the current block. */
+ origin = block_ultimate_origin (stmt);
+ origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK;
+
+ /* Determine if we need to output any Dwarf DIEs at all to represent this
+ block. */
+ if (origin_code == FUNCTION_DECL)
+ /* The outer scopes for inlinings *must* always be represented. We
+ generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */
+ must_output_die = 1;
+ else
+ {
+ /* In the case where the current block represents an inlining of the
+ "body block" of an inline function, we must *NOT* output any DIE for
+ this block because we have already output a DIE to represent the whole
+ inlined function scope and the "body block" of any function doesn't
+ really represent a different scope according to ANSI C rules. So we
+ check here to make sure that this block does not represent a "body
+ block inlining" before trying to set the MUST_OUTPUT_DIE flag. */
+ if (! is_body_block (origin ? origin : stmt))
+ {
+ /* Determine if this block directly contains any "significant"
+ local declarations which we will need to output DIEs for. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ /* We are not in terse mode so *any* local declaration counts
+ as being a "significant" one. */
+ must_output_die = (BLOCK_VARS (stmt) != NULL
+ && (TREE_USED (stmt)
+ || TREE_ASM_WRITTEN (stmt)
+ || BLOCK_ABSTRACT (stmt)));
+ else
+ /* We are in terse mode, so only local (nested) function
+ definitions count as "significant" local declarations. */
+ 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;
+ }
+ }
+ }
+
+ /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
+ DIE for any block which contains no significant local declarations at
+ all. Rather, in such cases we just call `decls_for_scope' so that any
+ needed Dwarf info for any sub-blocks will get properly generated. Note
+ that in terse mode, our definition of what constitutes a "significant"
+ local declaration gets restricted to include only inlined function
+ instances and local (nested) function definitions. */
+ 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);
+}
+
+/* Generate all of the decls declared within a given scope and (recursively)
+ all of its sub-blocks. */
+
+static void
+decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
+{
+ tree decl;
+ tree subblocks;
+
+ /* Ignore NULL blocks. */
+ if (stmt == NULL_TREE)
+ return;
+
+ if (TREE_USED (stmt))
+ {
+ /* Output the DIEs to represent all of the data objects and typedefs
+ declared directly within this block but not within any nested
+ sub-blocks. Also, nested function and tag DIEs have been
+ generated with a parent of NULL; fix that up now. */
+ for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
+ {
+ dw_die_ref die;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ die = lookup_decl_die (decl);
+ else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
+ die = lookup_type_die (TREE_TYPE (decl));
+ else
+ die = NULL;
+
+ if (die != NULL && die->die_parent == NULL)
+ add_child_die (context_die, die);
+ /* Do not produce debug information for static variables since
+ these might be optimized out. We are called for these later
+ in cgraph_varpool_analyze_pending_decls. */
+ if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
+ ;
+ else
+ gen_decl_die (decl, context_die);
+ }
+ }
+
+ /* If we're at -g1, we're not interested in subblocks. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
+ /* Output the DIEs to represent all sub-blocks (and the items declared
+ therein) of this block. */
+ for (subblocks = BLOCK_SUBBLOCKS (stmt);
+ subblocks != NULL;
+ subblocks = BLOCK_CHAIN (subblocks))
+ gen_block_die (subblocks, context_die, depth + 1);
+}
+
+/* Is this a typedef we can avoid emitting? */
+
+static inline int
+is_redundant_typedef (tree decl)
+{
+ if (TYPE_DECL_IS_STUB (decl))
+ return 1;
+
+ if (DECL_ARTIFICIAL (decl)
+ && DECL_CONTEXT (decl)
+ && is_tagged_type (DECL_CONTEXT (decl))
+ && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+ && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+ /* Also ignore the artificial member typedef for the class name. */
+ return 1;
+
+ return 0;
+}
+
+/* Returns the DIE for decl. A DIE will always be returned. */
+
+static dw_die_ref
+force_decl_die (tree decl)
+{
+ dw_die_ref decl_die;
+ unsigned saved_external_flag;
+ tree save_fn = NULL_TREE;
+ decl_die = lookup_decl_die (decl);
+ if (!decl_die)
+ {
+ dw_die_ref context_die;
+ tree decl_context = DECL_CONTEXT (decl);
+ if (decl_context)
+ {
+ /* Find die that represents this context. */
+ if (TYPE_P (decl_context))
+ context_die = force_type_die (decl_context);
+ else
+ context_die = force_decl_die (decl_context);
+ }
+ else
+ context_die = comp_unit_die;
+
+ decl_die = lookup_decl_die (decl);
+ if (decl_die)
+ return decl_die;
+
+ switch (TREE_CODE (decl))
+ {
+ case FUNCTION_DECL:
+ /* Clear current_function_decl, so that gen_subprogram_die thinks
+ that this is a declaration. At this point, we just want to force
+ declaration die. */
+ save_fn = current_function_decl;
+ current_function_decl = NULL_TREE;
+ gen_subprogram_die (decl, context_die);
+ current_function_decl = save_fn;
+ break;
+
+ case VAR_DECL:
+ /* Set external flag to force declaration die. Restore it after
+ gen_decl_die() call. */
+ saved_external_flag = DECL_EXTERNAL (decl);
+ DECL_EXTERNAL (decl) = 1;
+ gen_decl_die (decl, context_die);
+ DECL_EXTERNAL (decl) = saved_external_flag;
+ break;
+
+ case NAMESPACE_DECL:
+ dwarf2out_decl (decl);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* We should be able to find the DIE now. */
+ if (!decl_die)
+ decl_die = lookup_decl_die (decl);
+ gcc_assert (decl_die);
+ }
+
+ return decl_die;
+}
+
+/* Returns the DIE for TYPE, that must not be a base type. A DIE is
+ always returned. */
+
+static dw_die_ref
+force_type_die (tree type)
+{
+ dw_die_ref type_die;
+
+ type_die = lookup_type_die (type);
+ if (!type_die)
+ {
+ dw_die_ref context_die;
+ if (TYPE_CONTEXT (type))
+ {
+ if (TYPE_P (TYPE_CONTEXT (type)))
+ context_die = force_type_die (TYPE_CONTEXT (type));
+ else
+ context_die = force_decl_die (TYPE_CONTEXT (type));
+ }
+ else
+ context_die = comp_unit_die;
+
+ type_die = lookup_type_die (type);
+ if (type_die)
+ return type_die;
+ gen_type_die (type, context_die);
+ type_die = lookup_type_die (type);
+ gcc_assert (type_die);
+ }
+ return type_die;
+}
+
+/* Force out any required namespaces to be able to output DECL,
+ and return the new context_die for it, if it's changed. */
+
+static dw_die_ref
+setup_namespace_context (tree thing, dw_die_ref context_die)
+{
+ tree context = (DECL_P (thing)
+ ? DECL_CONTEXT (thing) : TYPE_CONTEXT (thing));
+ if (context && TREE_CODE (context) == NAMESPACE_DECL)
+ /* Force out the namespace. */
+ context_die = force_decl_die (context);
+
+ return context_die;
+}
+
+/* Emit a declaration DIE for THING (which is either a DECL or a tagged
+ type) within its namespace, if appropriate.
+
+ For compatibility with older debuggers, namespace DIEs only contain
+ declarations; all definitions are emitted at CU scope. */
+
+static void
+declare_in_namespace (tree thing, dw_die_ref context_die)
+{
+ dw_die_ref ns_context;
+
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
+ /* If this decl is from an inlined function, then don't try to emit it in its
+ namespace, as we will get confused. It would have already been emitted
+ when the abstract instance of the inline function was emitted anyways. */
+ if (DECL_P (thing) && DECL_ABSTRACT_ORIGIN (thing))
+ return;
+
+ ns_context = setup_namespace_context (thing, context_die);
+
+ if (ns_context != context_die)
+ {
+ if (DECL_P (thing))
+ gen_decl_die (thing, ns_context);
+ else
+ gen_type_die (thing, ns_context);
+ }
+}
+
+/* Generate a DIE for a namespace or namespace alias. */
+
+static void
+gen_namespace_die (tree decl)
+{
+ dw_die_ref context_die = setup_namespace_context (decl, comp_unit_die);
+
+ /* Namespace aliases have a DECL_ABSTRACT_ORIGIN of the namespace
+ they are an alias of. */
+ if (DECL_ABSTRACT_ORIGIN (decl) == NULL)
+ {
+ /* Output a real namespace. */
+ dw_die_ref namespace_die
+ = new_die (DW_TAG_namespace, context_die, decl);
+ add_name_and_src_coords_attributes (namespace_die, decl);
+ equate_decl_number_to_die (decl, namespace_die);
+ }
+ else
+ {
+ /* Output a namespace alias. */
+
+ /* Force out the namespace we are an alias of, if necessary. */
+ dw_die_ref origin_die
+ = force_decl_die (DECL_ABSTRACT_ORIGIN (decl));
+
+ /* Now create the namespace alias DIE. */
+ dw_die_ref namespace_die
+ = new_die (DW_TAG_imported_declaration, context_die, decl);
+ add_name_and_src_coords_attributes (namespace_die, decl);
+ add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
+ equate_decl_number_to_die (decl, namespace_die);
+ }
+}
+
+/* Generate Dwarf debug information for a decl described by DECL. */
+
+static void
+gen_decl_die (tree decl, dw_die_ref context_die)
+{
+ tree origin;
+
+ if (DECL_P (decl) && DECL_IGNORED_P (decl))
+ return;
+
+ switch (TREE_CODE (decl))
+ {
+ case ERROR_MARK:
+ break;
+
+ case CONST_DECL:
+ /* The individual enumerators of an enum type get output when we output
+ the Dwarf representation of the relevant enum type itself. */
+ break;
+
+ case FUNCTION_DECL:
+ /* Don't output any DIEs to represent mere function declarations,
+ unless they are class members or explicit block externs. */
+ if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE
+ && (current_function_decl == NULL_TREE || DECL_ARTIFICIAL (decl)))
+ break;
+
+#if 0
+ /* FIXME */
+ /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
+ on local redeclarations of global functions. That seems broken. */
+ if (current_function_decl != decl)
+ /* This is only a declaration. */;
+#endif
+
+ /* If we're emitting a clone, emit info for the abstract instance. */
+ if (DECL_ORIGIN (decl) != decl)
+ dwarf2out_abstract_function (DECL_ABSTRACT_ORIGIN (decl));
+
+ /* If we're emitting an out-of-line copy of an inline function,
+ emit info for the abstract instance and set up to refer to it. */
+ else if (cgraph_function_possibly_inlined_p (decl)
+ && ! DECL_ABSTRACT (decl)
+ && ! class_or_namespace_scope_p (context_die)
+ /* dwarf2out_abstract_function won't emit a die if this is just
+ a declaration. We must avoid setting DECL_ABSTRACT_ORIGIN in
+ that case, because that works only if we have a die. */
+ && DECL_INITIAL (decl) != NULL_TREE)
+ {
+ dwarf2out_abstract_function (decl);
+ set_decl_origin_self (decl);
+ }
+
+ /* Otherwise we're emitting the primary DIE for this decl. */
+ else if (debug_info_level > DINFO_LEVEL_TERSE)
+ {
+ /* Before we describe the FUNCTION_DECL itself, make sure that we
+ have described its return type. */
+ gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
+
+ /* And its virtual context. */
+ if (DECL_VINDEX (decl) != NULL_TREE)
+ gen_type_die (DECL_CONTEXT (decl), context_die);
+
+ /* And its containing type. */
+ origin = decl_class_context (decl);
+ if (origin != NULL_TREE)
+ gen_type_die_for_member (origin, decl, context_die);
+
+ /* And its containing namespace. */
+ declare_in_namespace (decl, context_die);
+ }
+
+ /* Now output a DIE to represent the function itself. */
+ gen_subprogram_die (decl, context_die);
+ break;
+
+ case TYPE_DECL:
+ /* If we are in terse mode, don't generate any DIEs to represent any
+ actual typedefs. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ break;
+
+ /* In the special case of a TYPE_DECL node representing the declaration
+ of some type tag, if the given TYPE_DECL is marked as having been
+ instantiated from some other (original) TYPE_DECL node (e.g. one which
+ was generated within the original definition of an inline function) we
+ have to generate a special (abbreviated) DW_TAG_structure_type,
+ DW_TAG_union_type, or DW_TAG_enumeration_type DIE here. */
+ if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
+ {
+ gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
+ break;
+ }
+
+ if (is_redundant_typedef (decl))
+ gen_type_die (TREE_TYPE (decl), context_die);
+ else
+ /* Output a DIE to represent the typedef itself. */
+ gen_typedef_die (decl, context_die);
+ break;
+
+ case LABEL_DECL:
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ gen_label_die (decl, context_die);
+ break;
+
+ case VAR_DECL:
+ case RESULT_DECL:
+ /* If we are in terse mode, don't generate any DIEs to represent any
+ variable declarations or definitions. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ break;
+
+ /* Output any DIEs that are needed to specify the type of this data
+ object. */
+ gen_type_die (TREE_TYPE (decl), context_die);
+
+ /* And its containing type. */
+ origin = decl_class_context (decl);
+ if (origin != NULL_TREE)
+ gen_type_die_for_member (origin, decl, context_die);
+
+ /* And its containing namespace. */
+ declare_in_namespace (decl, context_die);
+
+ /* Now output the DIE to represent the data object itself. This gets
+ complicated because of the possibility that the VAR_DECL really
+ represents an inlined instance of a formal parameter for an inline
+ function. */
+ 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:
+ /* Ignore the nameless fields that are used to skip bits but handle C++
+ anonymous unions and structs. */
+ if (DECL_NAME (decl) != NULL_TREE
+ || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+ {
+ gen_type_die (member_declared_type (decl), context_die);
+ gen_field_die (decl, context_die);
+ }
+ break;
+
+ case PARM_DECL:
+ gen_type_die (TREE_TYPE (decl), context_die);
+ gen_formal_parameter_die (decl, context_die);
+ break;
+
+ case NAMESPACE_DECL:
+ gen_namespace_die (decl);
+ break;
+
+ default:
+ /* Probably some frontend-internal decl. Assume we don't care. */
+ gcc_assert ((int)TREE_CODE (decl) > NUM_TREE_CODES);
+ break;
+ }
+}
+
+/* Output debug information for global decl DECL. Called from toplev.c after
+ compilation proper has finished. */
+
+static void
+dwarf2out_global_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);
+}
+
+/* Output debug information for type decl DECL. Called from toplev.c
+ and from language front ends (to record built-in types). */
+static void
+dwarf2out_type_decl (tree decl, int local)
+{
+ if (!local)
+ dwarf2out_decl (decl);
+}
+
+/* Output debug information for imported module or decl. */
+
+static void
+dwarf2out_imported_module_or_decl (tree decl, tree context)
+{
+ dw_die_ref imported_die, at_import_die;
+ dw_die_ref scope_die;
+ expanded_location xloc;
+
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
+ gcc_assert (decl);
+
+ /* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
+ We need decl DIE for reference and scope die. First, get DIE for the decl
+ itself. */
+
+ /* Get the scope die for decl context. Use comp_unit_die for global module
+ or decl. If die is not found for non globals, force new die. */
+ if (!context)
+ scope_die = comp_unit_die;
+ else if (TYPE_P (context))
+ scope_die = force_type_die (context);
+ else
+ scope_die = force_decl_die (context);
+
+ /* For TYPE_DECL or CONST_DECL, lookup TREE_TYPE. */
+ if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
+ {
+ if (is_base_type (TREE_TYPE (decl)))
+ at_import_die = base_type_die (TREE_TYPE (decl));
+ else
+ at_import_die = force_type_die (TREE_TYPE (decl));
+ }
+ else
+ {
+ at_import_die = lookup_decl_die (decl);
+ if (!at_import_die)
+ {
+ /* If we're trying to avoid duplicate debug info, we may not have
+ emitted the member decl for this field. Emit it now. */
+ if (TREE_CODE (decl) == FIELD_DECL)
+ {
+ tree type = DECL_CONTEXT (decl);
+ dw_die_ref type_context_die;
+
+ if (TYPE_CONTEXT (type))
+ if (TYPE_P (TYPE_CONTEXT (type)))
+ type_context_die = force_type_die (TYPE_CONTEXT (type));
+ else
+ type_context_die = force_decl_die (TYPE_CONTEXT (type));
+ else
+ type_context_die = comp_unit_die;
+ gen_type_die_for_member (type, decl, type_context_die);
+ }
+ at_import_die = force_decl_die (decl);
+ }
+ }
+
+ /* OK, now we have DIEs for decl as well as scope. Emit imported die. */
+ if (TREE_CODE (decl) == NAMESPACE_DECL)
+ imported_die = new_die (DW_TAG_imported_module, scope_die, context);
+ else
+ imported_die = new_die (DW_TAG_imported_declaration, scope_die, context);
+
+ xloc = expand_location (input_location);
+ add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
+ add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
+ add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
+}
+
+/* Write the debugging output for DECL. */
+
+void
+dwarf2out_decl (tree decl)
+{
+ dw_die_ref context_die = comp_unit_die;
+
+ switch (TREE_CODE (decl))
+ {
+ case ERROR_MARK:
+ return;
+
+ case FUNCTION_DECL:
+ /* What we would really like to do here is to filter out all mere
+ file-scope declarations of file-scope functions which are never
+ referenced later within this translation unit (and keep all of ones
+ that *are* referenced later on) but we aren't clairvoyant, so we have
+ no idea which functions will be referenced in the future (i.e. later
+ on within the current translation unit). So here we just ignore all
+ file-scope function declarations which are not also definitions. If
+ and when the debugger needs to know something about these functions,
+ it will have to hunt around and find the DWARF information associated
+ with the definition of the function.
+
+ We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
+ nodes represent definitions and which ones represent mere
+ declarations. We have to check DECL_INITIAL instead. That's because
+ the C front-end supports some weird semantics for "extern inline"
+ function definitions. These can get inlined within the current
+ translation unit (and thus, we need to generate Dwarf info for their
+ abstract instances so that the Dwarf info for the concrete inlined
+ instances can have something to refer to) but the compiler never
+ generates any out-of-lines instances of such things (despite the fact
+ that they *are* definitions).
+
+ The important point is that the C front-end marks these "extern
+ inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
+ them anyway. Note that the C++ front-end also plays some similar games
+ for inline function definitions appearing within include files which
+ also contain `#pragma interface' pragmas. */
+ if (DECL_INITIAL (decl) == NULL_TREE)
+ return;
+
+ /* If we're a nested function, initially use a parent of NULL; if we're
+ a plain function, this will be fixed up in decls_for_scope. If
+ we're a method, it will be ignored, since we already have a DIE. */
+ if (decl_function_context (decl)
+ /* APPLE LOCAL blocks 5811952 - radar 6172148 */
+ && (! BLOCK_SYNTHESIZED_FUNC (decl))
+ /* But if we're in terse mode, we don't care about scope. */
+ && debug_info_level > DINFO_LEVEL_TERSE)
+ context_die = NULL;
+ break;
+
+ case VAR_DECL:
+ /* Ignore this VAR_DECL if it refers to a file-scope extern data object
+ declaration and if the declaration was never even referenced from
+ within this entire compilation unit. We suppress these DIEs in
+ order to save space in the .debug section (by eliminating entries
+ which are probably useless). Note that we must not suppress
+ block-local extern declarations (whether used or not) because that
+ would screw-up the debugger's name lookup mechanism and cause it to
+ miss things which really ought to be in scope at a given point. */
+ if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
+ return;
+
+ /* For local statics lookup proper context die. */
+ if (TREE_STATIC (decl) && decl_function_context (decl))
+ context_die = lookup_decl_die (DECL_CONTEXT (decl));
+
+ /* If we are in terse mode, don't generate any DIEs to represent any
+ variable declarations or definitions. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+ break;
+
+ case NAMESPACE_DECL:
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+ if (lookup_decl_die (decl) != NULL)
+ return;
+ break;
+
+ case TYPE_DECL:
+ /* Don't emit stubs for types unless they are needed by other DIEs. */
+ if (TYPE_DECL_SUPPRESS_DEBUG (decl))
+ return;
+
+ /* Don't bother trying to generate any DIEs to represent any of the
+ normal built-in types for the language we are compiling. */
+ if (DECL_IS_BUILTIN (decl))
+ {
+ /* OK, we need to generate one for `bool' so GDB knows what type
+ comparisons have. */
+ if (is_cxx ()
+ && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
+ && ! DECL_IGNORED_P (decl))
+ modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
+
+ return;
+ }
+
+ /* If we are in terse mode, don't generate any DIEs for types. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
+ /* If we're a function-scope tag, initially use a parent of NULL;
+ this will be fixed up in decls_for_scope. */
+ if (decl_function_context (decl))
+ context_die = NULL;
+
+ break;
+
+ default:
+ return;
+ }
+
+ gen_decl_die (decl, context_die);
+}
+
+/* Output a marker (i.e. a label) for the beginning of the generated code for
+ a lexical block. */
+
+static void
+dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
+ unsigned int blocknum)
+{
+ switch_to_section (current_function_section ());
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
+}
+
+/* Output a marker (i.e. a label) for the end of the generated code for a
+ lexical block. */
+
+static void
+dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
+{
+ switch_to_section (current_function_section ());
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
+}
+
+/* Returns nonzero if it is appropriate not to emit any debugging
+ information for BLOCK, because it doesn't contain any instructions.
+
+ Don't allow this for blocks with nested functions or local classes
+ as we would end up with orphans, and in the presence of scheduling
+ we may end up calling them anyway. */
+
+static bool
+dwarf2out_ignore_block (tree block)
+{
+ tree decl;
+
+ for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ || (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)))
+ return 0;
+
+ return 1;
+}
+
+/* Hash table routines for file_hash. */
+
+static int
+file_table_eq (const void *p1_p, const void *p2_p)
+{
+ const struct dwarf_file_data * p1 = p1_p;
+ const char * p2 = p2_p;
+ return strcmp (p1->filename, p2) == 0;
+}
+
+static hashval_t
+file_table_hash (const void *p_p)
+{
+ const struct dwarf_file_data * p = p_p;
+ return htab_hash_string (p->filename);
+}
+
+/* Lookup FILE_NAME (in the list of filenames that we know about here in
+ dwarf2out.c) and return its "index". The index of each (known) filename is
+ just a unique number which is associated with only that one filename. We
+ need such numbers for the sake of generating labels (in the .debug_sfnames
+ section) and references to those files numbers (in the .debug_srcinfo
+ and.debug_macinfo sections). If the filename given as an argument is not
+ found in our current list, add it to the list and assign it the next
+ available unique index number. In order to speed up searches, we remember
+ the index of the filename was looked up last. This handles the majority of
+ all searches. */
+
+static struct dwarf_file_data *
+lookup_filename (const char *file_name)
+{
+ void ** slot;
+ struct dwarf_file_data * created;
+
+ /* Check to see if the file name that was searched on the previous
+ call matches this file name. If so, return the index. */
+ if (file_table_last_lookup
+ && (file_name == file_table_last_lookup->filename
+ || strcmp (file_table_last_lookup->filename, file_name) == 0))
+ return file_table_last_lookup;
+
+ /* Didn't match the previous lookup, search the table. */
+ slot = htab_find_slot_with_hash (file_table, file_name,
+ htab_hash_string (file_name), INSERT);
+ if (*slot)
+ return *slot;
+
+ created = ggc_alloc (sizeof (struct dwarf_file_data));
+ created->filename = file_name;
+ created->emitted_number = 0;
+ *slot = created;
+ return created;
+}
+
+/* If the assembler will construct the file table, then translate the compiler
+ internal file table number into the assembler file table number, and emit
+ a .file directive if we haven't already emitted one yet. The file table
+ numbers are different because we prune debug info for unused variables and
+ types, which may include filenames. */
+
+static int
+maybe_emit_file (struct dwarf_file_data * fd)
+{
+ if (! fd->emitted_number)
+ {
+ if (last_emitted_file)
+ fd->emitted_number = last_emitted_file->emitted_number + 1;
+ else
+ fd->emitted_number = 1;
+ last_emitted_file = fd;
+
+ if (DWARF2_ASM_LINE_DEBUG_INFO)
+ {
+ fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
+ output_quoted_string (asm_out_file, fd->filename);
+ fputc ('\n', asm_out_file);
+ }
+ }
+
+ return fd->emitted_number;
+}
+
+/* Called by the final INSN scan whenever we see a var location. We
+ use it to drop labels in the right places, and throw the location in
+ our lookup table. */
+
+static void
+dwarf2out_var_location (rtx loc_note)
+{
+ char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
+ struct var_loc_node *newloc;
+ rtx prev_insn;
+ static rtx last_insn;
+ static const char *last_label;
+ tree decl;
+
+ if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
+ return;
+ prev_insn = PREV_INSN (loc_note);
+
+ newloc = ggc_alloc_cleared (sizeof (struct var_loc_node));
+ /* If the insn we processed last time is the previous insn
+ and it is also a var location note, use the label we emitted
+ last time. */
+ if (last_insn != NULL_RTX
+ && last_insn == prev_insn
+ && NOTE_P (prev_insn)
+ && NOTE_LINE_NUMBER (prev_insn) == NOTE_INSN_VAR_LOCATION)
+ {
+ newloc->label = last_label;
+ }
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num);
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
+ loclabel_num++;
+ newloc->label = ggc_strdup (loclabel);
+ }
+ newloc->var_loc_note = loc_note;
+ newloc->next = NULL;
+
+ if (cfun && in_cold_section_p)
+ newloc->section_label = cfun->cold_section_label;
+ else
+ newloc->section_label = text_section_label;
+
+ last_insn = loc_note;
+ last_label = newloc->label;
+ decl = NOTE_VAR_LOCATION_DECL (loc_note);
+ add_var_loc_to_decl (decl, newloc);
+}
+
+/* We need to reset the locations at the beginning of each
+ function. We can't do this in the end_function hook, because the
+ declarations that use the locations won't have been output when
+ that hook is called. Also compute have_multiple_function_sections here. */
+
+static void
+dwarf2out_begin_function (tree fun)
+{
+ htab_empty (decl_loc_table);
+
+ if (function_section (fun) != text_section)
+ have_multiple_function_sections = true;
+}
+
+/* Output a label to mark the beginning of a source code line entry
+ and record information relating to this source line, in
+ 'line_info_table' for later output of the .debug_line section. */
+
+static void
+dwarf2out_source_line (unsigned int line, const char *filename)
+{
+ if (debug_info_level >= DINFO_LEVEL_NORMAL
+ && line != 0)
+ {
+ int file_num = maybe_emit_file (lookup_filename (filename));
+
+ switch_to_section (current_function_section ());
+
+ /* If 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)
+ {
+ /* Emit the .loc directive understood by GNU as. */
+ fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
+
+ /* Indicate that line number info exists. */
+ line_info_table_in_use++;
+ }
+ else if (function_section (current_function_decl) != text_section)
+ {
+ dw_separate_line_info_ref line_info;
+ targetm.asm_out.internal_label (asm_out_file,
+ SEPARATE_LINE_CODE_LABEL,
+ separate_line_info_table_in_use);
+
+ /* Expand the line info table if necessary. */
+ if (separate_line_info_table_in_use
+ == separate_line_info_table_allocated)
+ {
+ separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
+ separate_line_info_table
+ = ggc_realloc (separate_line_info_table,
+ separate_line_info_table_allocated
+ * sizeof (dw_separate_line_info_entry));
+ memset (separate_line_info_table
+ + separate_line_info_table_in_use,
+ 0,
+ (LINE_INFO_TABLE_INCREMENT
+ * sizeof (dw_separate_line_info_entry)));
+ }
+
+ /* Add the new entry at the end of the line_info_table. */
+ line_info
+ = &separate_line_info_table[separate_line_info_table_in_use++];
+ line_info->dw_file_num = file_num;
+ line_info->dw_line_num = line;
+ line_info->function = current_function_funcdef_no;
+ }
+ else
+ {
+ dw_line_info_ref line_info;
+
+ targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
+ line_info_table_in_use);
+
+ /* Expand the line info table if necessary. */
+ if (line_info_table_in_use == line_info_table_allocated)
+ {
+ line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
+ line_info_table
+ = ggc_realloc (line_info_table,
+ (line_info_table_allocated
+ * sizeof (dw_line_info_entry)));
+ memset (line_info_table + line_info_table_in_use, 0,
+ LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
+ }
+
+ /* Add the new entry at the end of the line_info_table. */
+ line_info = &line_info_table[line_info_table_in_use++];
+ line_info->dw_file_num = file_num;
+ line_info->dw_line_num = line;
+ }
+ }
+}
+
+/* APPLE LOCAL begin opt diary */
+/* Emit od_msg. */
+static void
+dwarf2out_od_msg (dw_die_ref die, HOST_WIDE_INT value)
+{
+ add_AT_int (die, DW_AT_GNU_OD_msg, value);
+}
+
+
+/* Emit od_category. */
+static void
+dwarf2out_od_category (dw_die_ref die, HOST_WIDE_INT value)
+{
+ add_AT_int (die, DW_AT_GNU_OD_category, value);
+}
+
+/* Record optimization diary version number. */
+
+static void
+dwarf2out_od_version (void)
+{
+ if (flag_opt_diary)
+ add_AT_unsigned (comp_unit_die, DW_AT_GNU_OD_version, 1);
+}
+
+/* Generate od_entry */
+static dw_die_ref
+gen_new_od_entry_die (dw_die_ref parent)
+{
+ return new_die (DW_TAG_GNU_OD_entry, parent ? parent : comp_unit_die, NULL);
+}
+
+static void
+dwarf2out_od_entry (enum debug_od_msg msg, expanded_location l)
+{
+ dw_die_ref entry_die = gen_new_od_entry_die (NULL);
+
+ dwarf2out_od_msg (entry_die, msg);
+ add_src_coords_attributes_locus (entry_die, l);
+
+ switch (msg)
+ {
+ case OD_msg_loop_vectorized:
+ dwarf2out_od_category (entry_die, OD_report | OD_action);
+ break;
+ case OD_msg_loop_not_vectorized:
+ dwarf2out_od_category (entry_die, OD_report);
+ break;
+ case OD_msg_loop_vectorized_using_versioning:
+ dwarf2out_od_category (entry_die, OD_report | OD_action);
+ break;
+ case OD_msg_loop_vectorized_using_peeling:
+ dwarf2out_od_category (entry_die, OD_report | OD_action);
+ break;
+ case OD_msg_loop_not_vectorized_multiple_exits:
+ dwarf2out_od_category (entry_die, OD_report);
+ break;
+ case OD_msg_loop_not_vectorized_bad_data_ref:
+ dwarf2out_od_category (entry_die, OD_report | OD_hint);
+ break;
+ case OD_msg_loop_not_vectorized_unsupported_ops:
+ dwarf2out_od_category (entry_die, OD_report | OD_limit);
+ break;
+ case OD_msg_loop_not_vectorized_data_dep:
+ dwarf2out_od_category (entry_die, OD_report | OD_hint);
+ break;
+ default:
+ break;
+ }
+}
+/* APPLE LOCAL end opt diary */
+/* Record the beginning of a new source file. */
+
+static void
+dwarf2out_start_source_file (unsigned int lineno, const char *filename)
+{
+ if (flag_eliminate_dwarf2_dups)
+ {
+ /* Record the beginning of the file for break_out_includes. */
+ dw_die_ref bincl_die;
+
+ bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die, NULL);
+ add_AT_string (bincl_die, DW_AT_name, filename);
+ }
+
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ int file_num = maybe_emit_file (lookup_filename (filename));
+
+ switch_to_section (debug_macinfo_section);
+ dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+ dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
+ lineno);
+
+ dw2_asm_output_data_uleb128 (file_num, "file %s", filename);
+ }
+}
+
+/* Record the end of a source file. */
+
+static void
+dwarf2out_end_source_file (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, NULL);
+
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ switch_to_section (debug_macinfo_section);
+ dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+ }
+}
+
+/* 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. */
+
+static void
+dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
+ const char *buffer ATTRIBUTE_UNUSED)
+{
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ switch_to_section (debug_macinfo_section);
+ dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
+ dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
+ dw2_asm_output_nstring (buffer, -1, "The macro");
+ }
+}
+
+/* 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. */
+
+static void
+dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
+ const char *buffer ATTRIBUTE_UNUSED)
+{
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ switch_to_section (debug_macinfo_section);
+ dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
+ dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
+ dw2_asm_output_nstring (buffer, -1, "The macro");
+ }
+}
+
+/* Set up for Dwarf output at the start of compilation. */
+
+static void
+dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
+{
+ /* Allocate the file_table. */
+ file_table = htab_create_ggc (50, file_table_hash,
+ file_table_eq, NULL);
+
+ /* Allocate the decl_die_table. */
+ decl_die_table = htab_create_ggc (10, decl_die_table_hash,
+ decl_die_table_eq, NULL);
+
+ /* Allocate the decl_loc_table. */
+ decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
+ decl_loc_table_eq, NULL);
+
+ /* Allocate the initial hunk of the decl_scope_table. */
+ decl_scope_table = VEC_alloc (tree, gc, 256);
+
+ /* Allocate the initial hunk of the abbrev_die_table. */
+ abbrev_die_table = ggc_alloc_cleared (ABBREV_DIE_TABLE_INCREMENT
+ * sizeof (dw_die_ref));
+ abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
+ /* Zero-th entry is allocated, but unused. */
+ abbrev_die_table_in_use = 1;
+
+ /* Allocate the initial hunk of the line_info_table. */
+ line_info_table = ggc_alloc_cleared (LINE_INFO_TABLE_INCREMENT
+ * sizeof (dw_line_info_entry));
+ line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
+
+ /* Zero-th entry is allocated, but unused. */
+ line_info_table_in_use = 1;
+
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ /* Allocate the pubtypes and pubnames vectors. */
+
+ pubname_table = VEC_alloc (pubname_entry, gc, 32);
+ pubtype_table = VEC_alloc (pubname_entry, gc, 32);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+ /* APPLE LOCAL radar 6275985 debug inlined section */
+ debug_inlined_table = VEC_alloc (inlined_entry, gc, 32);
+
+ /* Generate the initial DIE for the .debug section. Note that the (string)
+ value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
+ will (typically) be a relative pathname and that this pathname should be
+ taken as being relative to the directory from which the compiler was
+ invoked when the given (base) source file was compiled. We will fill
+ in this value in dwarf2out_finish. */
+ comp_unit_die = gen_compile_unit_die (NULL);
+
+ incomplete_types = VEC_alloc (tree, gc, 64);
+
+ used_rtx_array = VEC_alloc (rtx, gc, 32);
+
+ debug_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_line_section = get_section (DEBUG_LINE_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+ SECTION_DEBUG, NULL);
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+#ifdef DEBUG_PUBTYPES_SECTION
+ debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ SECTION_DEBUG, NULL);
+#endif
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+ /* APPLE LOCAL begin radar 6275985 debug inlined section */
+#ifdef DEBUG_INLINED_SECTION
+ debug_inlined_section = get_section (DEBUG_INLINED_SECTION,
+ SECTION_DEBUG, NULL);
+#endif
+ /* APPLE LOCAL end radar 6275985 debug inlined section */
+ debug_str_section = get_section (DEBUG_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
+ debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+
+ ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
+ DEBUG_ABBREV_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
+ COLD_TEXT_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
+
+ ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
+ DEBUG_INFO_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
+ DEBUG_LINE_SECTION_LABEL, 0);
+ ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
+ DEBUG_RANGES_SECTION_LABEL, 0);
+ switch_to_section (debug_abbrev_section);
+ ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
+ switch_to_section (debug_info_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
+ switch_to_section (debug_line_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
+
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ switch_to_section (debug_macinfo_section);
+ ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
+ DEBUG_MACINFO_SECTION_LABEL, 0);
+ ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+ }
+
+ switch_to_section (text_section);
+ ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
+ /* APPLE LOCAL opt diary */
+ dwarf2out_od_version ();
+ if (flag_reorder_blocks_and_partition)
+ {
+ switch_to_section (unlikely_text_section ());
+ ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
+ }
+}
+
+/* A helper function for dwarf2out_finish called through
+ ht_forall. Emit one queued .debug_str string. */
+
+static int
+output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
+{
+ struct indirect_string_node *node = (struct indirect_string_node *) *h;
+
+ if (node->form == DW_FORM_strp)
+ {
+ switch_to_section (debug_str_section);
+ ASM_OUTPUT_LABEL (asm_out_file, node->label);
+ assemble_string (node->str, strlen (node->str) + 1);
+ }
+
+ return 1;
+}
+
+#if ENABLE_ASSERT_CHECKING
+/* Verify that all marks are clear. */
+
+static void
+verify_marks_clear (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ gcc_assert (! die->die_mark);
+ FOR_EACH_CHILD (die, c, verify_marks_clear (c));
+}
+#endif /* ENABLE_ASSERT_CHECKING */
+
+/* Clear the marks for a die and its children.
+ Be cool if the mark isn't set. */
+
+static void
+prune_unmark_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ if (die->die_mark)
+ die->die_mark = 0;
+ FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
+}
+
+/* Given DIE that we're marking as used, find any other dies
+ it references as attributes and mark them as used. */
+
+static void
+prune_unused_types_walk_attribs (dw_die_ref die)
+{
+ dw_attr_ref a;
+ unsigned ix;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ {
+ if (a->dw_attr_val.val_class == dw_val_class_die_ref)
+ {
+ /* A reference to another DIE.
+ Make sure that it will get emitted. */
+ prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
+ }
+ /* Set the string's refcount to 0 so that prune_unused_types_mark
+ accounts properly for it. */
+ if (AT_class (a) == dw_val_class_str)
+ a->dw_attr_val.v.val_str->refcount = 0;
+ }
+}
+
+
+/* Mark DIE as being used. If DOKIDS is true, then walk down
+ to DIE's children. */
+
+static void
+prune_unused_types_mark (dw_die_ref die, int dokids)
+{
+ dw_die_ref c;
+
+ if (die->die_mark == 0)
+ {
+ /* We haven't done this node yet. Mark it as used. */
+ die->die_mark = 1;
+
+ /* We also have to mark its parents as used.
+ (But we don't want to mark our parents' kids due to this.) */
+ if (die->die_parent)
+ prune_unused_types_mark (die->die_parent, 0);
+
+ /* Mark any referenced nodes. */
+ prune_unused_types_walk_attribs (die);
+
+ /* If this node is a specification,
+ also mark the definition, if it exists. */
+ if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
+ prune_unused_types_mark (die->die_definition, 1);
+ }
+
+ if (dokids && die->die_mark != 2)
+ {
+ /* We need to walk the children, but haven't done so yet.
+ Remember that we've walked the kids. */
+ die->die_mark = 2;
+
+ /* If this is an array type, we need to make sure our
+ kids get marked, even if they're types. */
+ if (die->die_tag == DW_TAG_array_type)
+ FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
+ else
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
+ }
+}
+
+
+/* Walk the tree DIE and mark types that we actually use. */
+
+static void
+prune_unused_types_walk (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ /* Don't do anything if this node is already marked. */
+ if (die->die_mark)
+ return;
+
+ switch (die->die_tag) {
+ case DW_TAG_const_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
+ case DW_TAG_array_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ case DW_TAG_friend:
+ case DW_TAG_variant_part:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_string_type:
+ case DW_TAG_set_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_file_type:
+ if (die->die_perennial_p)
+ break;
+
+ /* It's a type node --- don't mark it. */
+ return;
+
+ default:
+ /* Mark everything else. */
+ break;
+ }
+
+ die->die_mark = 1;
+
+ /* Now, mark any dies referenced from here. */
+ prune_unused_types_walk_attribs (die);
+
+ /* Mark children. */
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
+}
+
+/* Increment the string counts on strings referred to from DIE's
+ attributes. */
+
+static void
+prune_unused_types_update_strings (dw_die_ref die)
+{
+ dw_attr_ref a;
+ unsigned ix;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_str)
+ {
+ struct indirect_string_node *s = a->dw_attr_val.v.val_str;
+ s->refcount++;
+ /* Avoid unnecessarily putting strings that are used less than
+ twice in the hash table. */
+ /* APPLE LOCAL begin radar 6275985 debug inlined section */
+ /* We always want function names to go into the hash table. */
+ if ((s->refcount
+ == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
+ || s->is_fn_name)
+ {
+ void ** slot;
+ slot = htab_find_slot_with_hash (debug_str_hash, s->str,
+ htab_hash_string (s->str),
+ INSERT);
+ if (*slot == NULL)
+ *slot = s;
+ /* APPLE LOCAL end radar 6275985 debug inlined section */
+ }
+ }
+}
+
+/* Remove from the tree DIE any dies that aren't marked. */
+
+static void
+prune_unused_types_prune (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ gcc_assert (die->die_mark);
+ prune_unused_types_update_strings (die);
+
+ if (! die->die_child)
+ return;
+
+ c = die->die_child;
+ do {
+ dw_die_ref prev = c;
+ for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
+ if (c == die->die_child)
+ {
+ /* No marked children between 'prev' and the end of the list. */
+ if (prev == c)
+ /* No marked children at all. */
+ die->die_child = NULL;
+ else
+ {
+ prev->die_sib = c->die_sib;
+ die->die_child = prev;
+ }
+ return;
+ }
+
+ if (c != prev->die_sib)
+ prev->die_sib = c;
+ prune_unused_types_prune (c);
+ } while (c != die->die_child);
+}
+
+/* APPLE LOCAL begin radar 6476836 */
+/* If an inlined subroutine occurs in a struct or class that's going
+ to be eliminated, we need to mark it as dead so it doesn't get
+ output in the inlined debug section. */
+
+static void
+prune_unused_types_cleanup_inlining (dw_die_ref die, bool should_be_dead)
+{
+ dw_die_ref c;
+
+ /* Mark inlined subroutine die as dead if appropriate. */
+
+ if (die->die_tag == DW_TAG_inlined_subroutine
+ && should_be_dead)
+ die->dead = 1;
+
+ /* If a struct or class is not marked, then any inlined subroutine
+ descendant of it ought to be marked as dead. */
+
+ if (die->die_tag == DW_TAG_class_type
+ || die->die_tag == DW_TAG_structure_type)
+ {
+ if (die->die_mark)
+ should_be_dead = 0;
+ else
+ should_be_dead = 1;
+ }
+
+ /* Call function recursively walking the die tree. */
+
+ FOR_EACH_CHILD (die, c,
+ prune_unused_types_cleanup_inlining (c, should_be_dead));
+}
+/* APPLE LOCAL end radar 6476836 */
+
+/* Remove dies representing declarations that we never use. */
+
+static void
+prune_unused_types (void)
+{
+ unsigned int i;
+ limbo_die_node *node;
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ pubname_ref pub;
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+#if ENABLE_ASSERT_CHECKING
+ /* All the marks should already be clear. */
+ verify_marks_clear (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ verify_marks_clear (node->die);
+#endif /* ENABLE_ASSERT_CHECKING */
+
+ /* Set the mark on nodes that are actually used. */
+ prune_unused_types_walk (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ prune_unused_types_walk (node->die);
+
+ /* Also set the mark on nodes referenced from the
+ pubname_table or arange_table. */
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ for (i = 0; VEC_iterate (pubname_entry, pubname_table, i, pub); i++)
+ prune_unused_types_mark (pub->die, 1);
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+ for (i = 0; i < arange_table_in_use; i++)
+ prune_unused_types_mark (arange_table[i], 1);
+
+ /* Get rid of nodes that aren't marked; and update the string counts. */
+ if (debug_str_hash)
+ htab_empty (debug_str_hash);
+ /* APPLE LOCAL radar 6476836 */
+ prune_unused_types_cleanup_inlining (comp_unit_die, false);
+ prune_unused_types_prune (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ /* APPLE LOCAL begin radar 6476836 */
+ {
+ prune_unused_types_cleanup_inlining (node->die, false);
+ prune_unused_types_prune (node->die);
+ }
+ /* APPLE LOCAL end radar 6476836 */
+
+ /* Leave the marks clear. */
+ prune_unmark_dies (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ prune_unmark_dies (node->die);
+}
+
+/* Set the parameter to true if there are any relative pathnames in
+ the file table. */
+static int
+file_table_relative_p (void ** slot, void *param)
+{
+ bool *p = param;
+ struct dwarf_file_data *d = *slot;
+ if (d->emitted_number && d->filename[0] != DIR_SEPARATOR)
+ {
+ *p = true;
+ return 0;
+ }
+ return 1;
+}
+
+/* Output stuff that dwarf requires at the end of every file,
+ and generate the DWARF-2 debugging info. */
+
+static void
+dwarf2out_finish (const char *filename)
+{
+ limbo_die_node *node, *next_node;
+ dw_die_ref die = 0;
+
+ /* Add the name for the main input file now. We delayed this from
+ dwarf2out_init to avoid complications with PCH. */
+ add_name_attribute (comp_unit_die, filename);
+ /* APPLE LOCAL Radar 5645155 */
+ maybe_emit_file (lookup_filename (filename));
+ if (filename[0] != DIR_SEPARATOR)
+ add_comp_dir_attribute (comp_unit_die);
+ else if (get_AT (comp_unit_die, DW_AT_comp_dir) == NULL)
+ {
+ bool p = false;
+ htab_traverse (file_table, file_table_relative_p, &p);
+ if (p)
+ add_comp_dir_attribute (comp_unit_die);
+ }
+
+ /* APPLE LOCAL begin radar 6386976 */
+ if (flag_objc_abi > 0)
+ add_AT_unsigned (comp_unit_die, DW_AT_APPLE_major_runtime_vers,
+ flag_objc_abi);
+ /* APPLE LOCAL end radar 6386976 */
+ /* APPLE LOCAL begin option verifier 4957887 */
+ /* Add the options for this compilation now, so that the options
+ are from the final compilation not the PCH.
+ Do this only when the undocumented RC_DEBUG_OPTIONS
+ environment variable is set to a nonempty string.
+ This is intended only for internal Apple use. */
+ {
+ char * debugopt = getenv("RC_DEBUG_OPTIONS");
+ if (debugopt && debugopt[0])
+ add_AT_string (comp_unit_die, DW_AT_APPLE_flags, get_arguments());
+ }
+ /* APPLE LOCAL end option verifier 4957887 */
+
+ /* APPLE LOCAL begin radar 2338865 optimization notification */
+ if (optimize > 0)
+ add_AT_flag (comp_unit_die, DW_AT_APPLE_optimized, 1);
+ /* APPLE LOCAL end radar 2338865 optimization notification */
+
+ /* Traverse the limbo die list, and add parent/child links. The only
+ dies without parents that should be here are concrete instances of
+ inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
+ For concrete instances, we can get the parent die from the abstract
+ instance. */
+ for (node = limbo_die_list; node; node = next_node)
+ {
+ next_node = node->next;
+ die = node->die;
+
+ if (die->die_parent == NULL)
+ {
+ dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+ if (origin)
+ add_child_die (origin->die_parent, die);
+ else if (die == comp_unit_die)
+ ;
+ else if (errorcount > 0 || sorrycount > 0)
+ /* It's OK to be confused by errors in the input. */
+ add_child_die (comp_unit_die, die);
+ else
+ {
+ /* In certain situations, the lexical block containing a
+ nested function can be optimized away, which results
+ in the nested function die being orphaned. Likewise
+ with the return type of that nested function. Force
+ this to be a child of the containing function.
+
+ It may happen that even the containing function got fully
+ inlined and optimized out. In that case we are lost and
+ assign the empty child. This should not be big issue as
+ the function is likely unreachable too. */
+ tree context = NULL_TREE;
+
+ gcc_assert (node->created_for);
+
+ if (DECL_P (node->created_for))
+ context = DECL_CONTEXT (node->created_for);
+ else if (TYPE_P (node->created_for))
+ context = TYPE_CONTEXT (node->created_for);
+
+ gcc_assert (context
+ && (TREE_CODE (context) == FUNCTION_DECL
+ || TREE_CODE (context) == NAMESPACE_DECL));
+
+ origin = lookup_decl_die (context);
+ if (origin)
+ add_child_die (origin, die);
+ else
+ add_child_die (comp_unit_die, die);
+ }
+ }
+ }
+
+ limbo_die_list = NULL;
+
+ /* Walk through the list of incomplete types again, trying once more to
+ emit full debugging info for them. */
+ retry_incomplete_types ();
+
+ if (flag_eliminate_unused_debug_types)
+ prune_unused_types ();
+
+ /* Generate separate CUs for each of the include files we've seen.
+ They will go into limbo_die_list. */
+ if (flag_eliminate_dwarf2_dups)
+ break_out_includes (comp_unit_die);
+
+ /* Traverse the DIE's and add add sibling attributes to those DIE's
+ that have children. */
+ add_sibling_attributes (comp_unit_die);
+ for (node = limbo_die_list; node; node = node->next)
+ add_sibling_attributes (node->die);
+
+ /* Output a terminator label for the .text section. */
+ switch_to_section (text_section);
+ targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
+ if (flag_reorder_blocks_and_partition)
+ {
+ switch_to_section (unlikely_text_section ());
+ targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
+ }
+
+ /* We can only use the low/high_pc attributes if all of the code was
+ in .text. */
+ if (!have_multiple_function_sections)
+ {
+ add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
+ add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
+ }
+
+ /* If it wasn't, we need to give .debug_loc and .debug_ranges an appropriate
+ "base address". Use zero so that these addresses become absolute. */
+ else if (have_location_lists || ranges_table_in_use)
+ add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
+
+ /* Output location list section if necessary. */
+ if (have_location_lists)
+ {
+ /* Output the location lists info. */
+ switch_to_section (debug_loc_section);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
+ DEBUG_LOC_SECTION_LABEL, 0);
+ ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+ output_location_lists (die);
+ }
+
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ add_AT_lineptr (comp_unit_die, DW_AT_stmt_list,
+ debug_line_section_label);
+
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ add_AT_macptr (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
+
+ /* Output all of the compilation units. We put the main one last so that
+ the offsets are available to output_pubnames. */
+ for (node = limbo_die_list; node; node = node->next)
+ output_comp_unit (node->die, 0);
+
+ output_comp_unit (comp_unit_die, 0);
+
+ /* Output the abbreviation table. */
+ switch_to_section (debug_abbrev_section);
+ output_abbrev_section ();
+
+ /* Output public names table if necessary. */
+ /* APPLE LOCAL begin pubtypes, approved for 4.3 4535968 */
+ if (! VEC_empty (pubname_entry, pubname_table))
+ {
+ switch_to_section (debug_pubnames_section);
+ output_pubnames (pubname_table);
+ }
+
+#ifdef DEBUG_PUBTYPES_SECTION
+ /* Output public types table if necessary. */
+ if (! VEC_empty (pubname_entry, pubtype_table))
+ {
+ switch_to_section (debug_pubtypes_section);
+ output_pubnames (pubtype_table);
+ }
+#endif
+ /* APPLE LOCAL end pubtypes, approved for 4.3 4535968 */
+
+ /* APPLE LOCAL begin radar 6275985 debug inlined section */
+#ifdef DEBUG_INLINED_SECTION
+ /* Output debug section containing info about inlined subroutines */
+ if (! VEC_empty (inlined_entry, debug_inlined_table))
+ {
+ switch_to_section (debug_inlined_section);
+ output_debug_inlined_section (debug_inlined_table);
+ }
+#endif
+ /* APPLE LOCAL end radar 6275985 debug inlined section */
+
+ /* Output the address range information. We only put functions in the arange
+ table, so don't write it out if we don't have any. */
+ if (fde_table_in_use)
+ {
+ switch_to_section (debug_aranges_section);
+ output_aranges ();
+ }
+
+ /* Output ranges section if necessary. */
+ if (ranges_table_in_use)
+ {
+ switch_to_section (debug_ranges_section);
+ ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
+ output_ranges ();
+ }
+
+ /* 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. This is done late so that any filenames
+ used by the debug_info section are marked as 'used'. */
+ if (! DWARF2_ASM_LINE_DEBUG_INFO)
+ {
+ switch_to_section (debug_line_section);
+ output_line_info ();
+ }
+
+ /* Have to end the macro section. */
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ {
+ switch_to_section (debug_macinfo_section);
+ dw2_asm_output_data (1, 0, "End compilation unit");
+ }
+
+ /* If we emitted any DW_FORM_strp form attribute, output the string
+ table too. */
+ if (debug_str_hash)
+ htab_traverse (debug_str_hash, output_indirect_string, NULL);
+}
+#else
+
+/* This should never be used, but its address is needed for comparisons. */
+const struct gcc_debug_hooks dwarf2_debug_hooks;
+
+#endif /* DWARF2_DEBUGGING_INFO */
+
+#include "gt-dwarf2out.h"