blob: 4727859c4d85f84107153037e924265d7ba83086 [file] [log] [blame]
/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992-2015 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 3, 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 COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* 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. */
/* 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 */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "hash-set.h"
#include "machmode.h"
#include "vec.h"
#include "double-int.h"
#include "input.h"
#include "alias.h"
#include "symtab.h"
#include "wide-int.h"
#include "inchash.h"
#include "real.h"
#include "tree.h"
#include "fold-const.h"
#include "stringpool.h"
#include "stor-layout.h"
#include "varasm.h"
#include "hashtab.h"
#include "hard-reg-set.h"
#include "function.h"
#include "emit-rtl.h"
#include "hash-table.h"
#include "version.h"
#include "flags.h"
#include "regs.h"
#include "rtlhash.h"
#include "insn-config.h"
#include "reload.h"
#include "output.h"
#include "statistics.h"
#include "fixed-value.h"
#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
#include "stmt.h"
#include "expr.h"
#include "except.h"
#include "dwarf2.h"
#include "dwarf2out.h"
#include "dwarf2asm.h"
#include "toplev.h"
#include "md5.h"
#include "tm_p.h"
#include "diagnostic.h"
#include "tree-pretty-print.h"
#include "debug.h"
#include "target.h"
#include "common/common-target.h"
#include "langhooks.h"
#include "hash-map.h"
#include "is-a.h"
#include "plugin-api.h"
#include "ipa-ref.h"
#include "cgraph.h"
#include "ira.h"
#include "lra.h"
#include "dumpfile.h"
#include "opts.h"
#include "tree-dfa.h"
#include "gdb/gdb-index.h"
#include "rtl-iter.h"
static void dwarf2out_source_line (unsigned int, const char *, int, bool);
static rtx_insn *last_var_location_insn;
static rtx_insn *cached_next_real_insn;
static void dwarf2out_decl (tree);
#ifdef VMS_DEBUGGING_INFO
int vms_file_stats_name (const char *, long long *, long *, char *, int *);
/* Define this macro to be a nonzero value if the directory specifications
which are output in the debug info should end with a separator. */
#define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 1
/* Define this macro to evaluate to a nonzero value if GCC should refrain
from generating indirect strings in DWARF2 debug information, for instance
if your target is stuck with an old version of GDB that is unable to
process them properly or uses VMS Debug. */
#define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 1
#else
#define DWARF2_DIR_SHOULD_END_WITH_SEPARATOR 0
#define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
#endif
/* ??? Poison these here until it can be done generically. They've been
totally replaced in this file; make sure it stays that way. */
#undef DWARF2_UNWIND_INFO
#undef DWARF2_FRAME_INFO
#if (GCC_VERSION >= 3000)
#pragma GCC poison DWARF2_UNWIND_INFO DWARF2_FRAME_INFO
#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, va_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, va_gc> *because we want to tell the garbage collector about
it. */
static GTY(()) vec<tree, va_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, va_gc> *decl_scope_table;
/* Pointers to various DWARF2 sections. */
static GTY(()) section *debug_info_section;
static GTY(()) section *debug_skeleton_info_section;
static GTY(()) section *debug_abbrev_section;
static GTY(()) section *debug_skeleton_abbrev_section;
static GTY(()) section *debug_aranges_section;
static GTY(()) section *debug_addr_section;
static GTY(()) section *debug_macinfo_section;
static GTY(()) section *debug_line_section;
static GTY(()) section *debug_skeleton_line_section;
static GTY(()) section *debug_loc_section;
static GTY(()) section *debug_pubnames_section;
static GTY(()) section *debug_pubtypes_section;
static GTY(()) section *debug_str_section;
static GTY(()) section *debug_str_dwo_section;
static GTY(()) section *debug_str_offsets_section;
static GTY(()) section *debug_ranges_section;
static GTY(()) section *debug_frame_section;
/* Maximum size (in bytes) of an artificially generated label. */
#define MAX_ARTIFICIAL_LABEL_BYTES 30
/* 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
/* Round SIZE up to the nearest BOUNDARY. */
#define DWARF_ROUND(SIZE,BOUNDARY) \
((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
/* 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 vector for a table that contains frame description
information for each routine. */
#define NOT_INDEXED (-1U)
#define NO_INDEX_ASSIGNED (-2U)
static GTY(()) vec<dw_fde_ref, va_gc> *fde_vec;
struct GTY((for_user)) indirect_string_node {
const char *str;
unsigned int refcount;
enum dwarf_form form;
char *label;
unsigned int index;
};
struct indirect_string_hasher : ggc_hasher<indirect_string_node *>
{
typedef const char *compare_type;
static hashval_t hash (indirect_string_node *);
static bool equal (indirect_string_node *, const char *);
};
static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash;
/* With split_debug_info, both the comp_dir and dwo_name go in the
main object file, rather than the dwo, similar to the force_direct
parameter elsewhere but with additional complications:
1) The string is needed in both the main object file and the dwo.
That is, the comp_dir and dwo_name will appear in both places.
2) Strings can use three forms: DW_FORM_string, DW_FORM_strp or
DW_FORM_GNU_str_index.
3) GCC chooses the form to use late, depending on the size and
reference count.
Rather than forcing the all debug string handling functions and
callers to deal with these complications, simply use a separate,
special-cased string table for any attribute that should go in the
main object file. This limits the complexity to just the places
that need it. */
static GTY (()) hash_table<indirect_string_hasher> *skeleton_debug_str_hash;
static GTY(()) int dw2_string_counter;
/* True if the compilation unit places functions in more than one section. */
static GTY(()) bool have_multiple_function_sections = false;
/* Whether the default text and cold text sections have been used at all. */
static GTY(()) bool text_section_used = false;
static GTY(()) bool cold_text_section_used = false;
/* The default cold text section. */
static GTY(()) section *cold_text_section;
/* The DIE for C++14 'auto' in a function return type. */
static GTY(()) dw_die_ref auto_die;
/* The DIE for C++14 'decltype(auto)' in a function return type. */
static GTY(()) dw_die_ref decltype_auto_die;
/* Forward declarations for functions defined in this file. */
static char *stripattributes (const char *);
static void output_call_frame_info (int);
static void dwarf2out_note_section_used (void);
/* Personality decl of current unit. Used only when assembler does not support
personality CFI. */
static GTY(()) rtx current_unit_personality;
/* 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 PROLOGUE_END_LABEL
#define PROLOGUE_END_LABEL "LPE"
#endif
#ifndef EPILOGUE_BEGIN_LABEL
#define EPILOGUE_BEGIN_LABEL "LEB"
#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"
/* Match the base name of a file to the base name of a compilation unit. */
static int
matches_main_base (const char *path)
{
/* Cache the last query. */
static const char *last_path = NULL;
static int last_match = 0;
if (path != last_path)
{
const char *base;
int length = base_of_path (path, &base);
last_path = path;
last_match = (length == main_input_baselength
&& memcmp (base, main_input_basename, length) == 0);
}
return last_match;
}
#ifdef DEBUG_DEBUG_STRUCT
static int
dump_struct_debug (tree type, enum debug_info_usage usage,
enum debug_struct_file criterion, int generic,
int matches, int result)
{
/* Find the type name. */
tree type_decl = TYPE_STUB_DECL (type);
tree t = type_decl;
const char *name = 0;
if (TREE_CODE (t) == TYPE_DECL)
t = DECL_NAME (t);
if (t)
name = IDENTIFIER_POINTER (t);
fprintf (stderr, " struct %d %s %s %s %s %d %p %s\n",
criterion,
DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
matches ? "bas" : "hdr",
generic ? "gen" : "ord",
usage == DINFO_USAGE_DFN ? ";" :
usage == DINFO_USAGE_DIR_USE ? "." : "*",
result,
(void*) type_decl, name);
return result;
}
#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
dump_struct_debug (type, usage, criterion, generic, matches, result)
#else
#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
(result)
#endif
/* Get the number of HOST_WIDE_INTs needed to represent the precision
of the number. Some constants have a large uniform precision, so
we get the precision needed for the actual value of the number. */
static unsigned int
get_full_len (const wide_int &op)
{
int prec = wi::min_precision (op, UNSIGNED);
return ((prec + HOST_BITS_PER_WIDE_INT - 1)
/ HOST_BITS_PER_WIDE_INT);
}
static bool
should_emit_struct_debug (tree type, enum debug_info_usage usage)
{
enum debug_struct_file criterion;
tree type_decl;
bool generic = lang_hooks.types.generic_p (type);
if (generic)
criterion = debug_struct_generic[usage];
else
criterion = debug_struct_ordinary[usage];
if (criterion == DINFO_STRUCT_FILE_NONE)
return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
if (criterion == DINFO_STRUCT_FILE_ANY)
return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
type_decl = TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type));
if (type_decl != NULL)
{
if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
}
return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
}
/* 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;
}
/* Switch [BACK] to eh_frame_section. If we don't have an eh_frame_section,
switch to the data section instead, and write out a synthetic start label
for collect2 the first time around. */
static void
switch_to_eh_frame_section (bool back)
{
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 /* EH_FRAME_SECTION_NAME */
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);
if (!back)
{
label = get_file_function_name ("F");
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
targetm.asm_out.globalize_label (asm_out_file,
IDENTIFIER_POINTER (label));
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
}
}
}
/* Switch [BACK] to the eh or debug frame table section, depending on
FOR_EH. */
static void
switch_to_frame_table_section (int for_eh, bool back)
{
if (for_eh)
switch_to_eh_frame_section (back);
else
{
if (!debug_frame_section)
debug_frame_section = get_section (DEBUG_FRAME_SECTION,
SECTION_DEBUG, NULL);
switch_to_section (debug_frame_section);
}
}
/* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */
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:
case DW_CFA_remember_state:
case DW_CFA_restore_state:
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:
case DW_CFA_restore_extended:
case DW_CFA_undefined:
case DW_CFA_same_value:
case DW_CFA_def_cfa_register:
case DW_CFA_register:
case DW_CFA_expression:
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:
return dw_cfi_oprnd_loc;
default:
gcc_unreachable ();
}
}
/* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */
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;
case DW_CFA_expression:
return dw_cfi_oprnd_loc;
default:
return dw_cfi_oprnd_unused;
}
}
/* Output one FDE. */
static void
output_fde (dw_fde_ref fde, bool for_eh, bool second,
char *section_start_label, int fde_encoding, char *augmentation,
bool any_lsda_needed, int lsda_encoding)
{
const char *begin, *end;
static unsigned int j;
char l1[20], l2[20];
targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
/* empty */ 0);
targetm.asm_out.internal_label (asm_out_file, FDE_LABEL,
for_eh + j);
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + j);
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + j);
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");
begin = second ? fde->dw_fde_second_begin : fde->dw_fde_begin;
end = second ? fde->dw_fde_second_end : fde->dw_fde_end;
if (for_eh)
{
rtx sym_ref = gen_rtx_SYMBOL_REF (Pmode, begin);
SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref, false,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
end, begin, "FDE address range");
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, begin, "FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, 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, second ? "LLSDAC" : "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 = begin;
{
size_t from, until, i;
from = 0;
until = vec_safe_length (fde->dw_fde_cfi);
if (fde->dw_fde_second_begin == NULL)
;
else if (!second)
until = fde->dw_fde_switch_cfi_index;
else
from = fde->dw_fde_switch_cfi_index;
for (i = from; i < until; i++)
output_cfi ((*fde->dw_fde_cfi)[i], fde, for_eh);
}
/* If we are to emit a ref/link from function bodies to their frame tables,
do it now. This is typically performed to make sure that tables
associated with functions are dragged with them and not discarded in
garbage collecting links. We need to do this on a per function basis to
cope with -ffunction-sections. */
#ifdef ASM_OUTPUT_DWARF_TABLE_REF
/* Switch to the function section, emit the ref to the tables, and
switch *back* into the table section. */
switch_to_section (function_section (fde->decl));
ASM_OUTPUT_DWARF_TABLE_REF (section_start_label);
switch_to_frame_table_section (for_eh, true);
#endif
/* 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);
j += 2;
}
/* Return true if frame description entry FDE is needed for EH. */
static bool
fde_needed_for_eh_p (dw_fde_ref fde)
{
if (flag_asynchronous_unwind_tables)
return true;
if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde->decl))
return true;
if (fde->uses_eh_lsda)
return true;
/* If exceptions are enabled, we have collected nothrow info. */
if (flag_exceptions && (fde->all_throwers_are_sibcalls || fde->nothrow))
return false;
return true;
}
/* 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;
rtx personality = NULL;
int dw_cie_version;
/* Don't emit a CIE if there won't be any FDEs. */
if (!fde_vec)
return;
/* Nothing to do if the assembler's doing it all. */
if (dwarf2out_do_cfi_asm ())
return;
/* If we don't have any functions we'll want to unwind out of, don't emit
any EH unwind information. 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, an explicit specialization doesn't. */
if (for_eh)
{
bool any_eh_needed = false;
FOR_EACH_VEC_ELT (*fde_vec, i, fde)
{
if (fde->uses_eh_lsda)
any_eh_needed = any_lsda_needed = true;
else if (fde_needed_for_eh_p (fde))
any_eh_needed = true;
else if (TARGET_USES_WEAK_UNWIND_INFO)
targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, 1, 1);
}
if (!any_eh_needed)
return;
}
/* We're going to be generating comments, so turn on app. */
if (flag_debug_asm)
app_enable ();
/* Switch to the proper frame section, first time. */
switch_to_frame_table_section (for_eh, false);
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");
/* Use the CIE version 3 for DWARF3; allow DWARF2 to continue to
use CIE version 1, unless that would produce incorrect results
due to overflowing the return register column. */
return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh);
dw_cie_version = 1;
if (return_reg >= 256 || dwarf_version > 2)
dw_cie_version = 3;
dw2_asm_output_data (1, dw_cie_version, "CIE Version");
augmentation[0] = 0;
augmentation_size = 0;
personality = current_unit_personality;
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 (personality)
{
*p++ = 'P';
augmentation_size += 1 + size_of_encoded_value (per_encoding);
assemble_external_libcall (personality);
}
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 (personality && 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");
if (dw_cie_version >= 4)
{
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "CIE Address Size");
dw2_asm_output_data (1, 0, "CIE Segment Size");
}
dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
"CIE Data Alignment Factor");
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 (personality)
{
dw2_asm_output_data (1, per_encoding, "Personality (%s)",
eh_data_format_name (per_encoding));
dw2_asm_output_encoded_addr_rtx (per_encoding,
personality,
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_EACH_VEC_ELT (*cie_cfi_vec, i, cfi)
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_EACH_VEC_ELT (*fde_vec, i, fde)
{
unsigned int k;
/* Don't emit EH unwind info for leaf functions that don't need it. */
if (for_eh && !fde_needed_for_eh_p (fde))
continue;
for (k = 0; k < (fde->dw_fde_second_begin ? 2 : 1); k++)
output_fde (fde, for_eh, k, section_start_label, fde_encoding,
augmentation, any_lsda_needed, lsda_encoding);
}
if (for_eh && targetm.terminate_dw2_eh_frame_info)
dw2_asm_output_data (4, 0, "End of Table");
/* Turn off app to make assembly quicker. */
if (flag_debug_asm)
app_disable ();
}
/* Emit .cfi_startproc and .cfi_personality/.cfi_lsda if needed. */
static void
dwarf2out_do_cfi_startproc (bool second)
{
int enc;
rtx ref;
rtx personality = get_personality_function (current_function_decl);
fprintf (asm_out_file, "\t.cfi_startproc\n");
if (personality)
{
enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
ref = personality;
/* ??? The GAS support isn't entirely consistent. We have to
handle indirect support ourselves, but PC-relative is done
in the assembler. Further, the assembler can't handle any
of the weirder relocation types. */
if (enc & DW_EH_PE_indirect)
ref = dw2_force_const_mem (ref, true);
fprintf (asm_out_file, "\t.cfi_personality %#x,", enc);
output_addr_const (asm_out_file, ref);
fputc ('\n', asm_out_file);
}
if (crtl->uses_eh_lsda)
{
char lab[20];
enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
ASM_GENERATE_INTERNAL_LABEL (lab, second ? "LLSDAC" : "LLSDA",
current_function_funcdef_no);
ref = gen_rtx_SYMBOL_REF (Pmode, lab);
SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
if (enc & DW_EH_PE_indirect)
ref = dw2_force_const_mem (ref, true);
fprintf (asm_out_file, "\t.cfi_lsda %#x,", enc);
output_addr_const (asm_out_file, ref);
fputc ('\n', asm_out_file);
}
}
/* Allocate CURRENT_FDE. Immediately initialize all we can, noting that
this allocation may be done before pass_final. */
dw_fde_ref
dwarf2out_alloc_current_fde (void)
{
dw_fde_ref fde;
fde = ggc_cleared_alloc<dw_fde_node> ();
fde->decl = current_function_decl;
fde->funcdef_number = current_function_funcdef_no;
fde->fde_index = vec_safe_length (fde_vec);
fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
fde->uses_eh_lsda = crtl->uses_eh_lsda;
fde->nothrow = crtl->nothrow;
fde->drap_reg = INVALID_REGNUM;
fde->vdrap_reg = INVALID_REGNUM;
/* Record the FDE associated with this function. */
cfun->fde = fde;
vec_safe_push (fde_vec, fde);
return fde;
}
/* 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;
section *fnsec;
bool do_frame;
current_function_func_begin_label = NULL;
do_frame = dwarf2out_do_frame ();
/* ??? 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 (!do_frame
&& (!flag_exceptions
|| targetm_common.except_unwind_info (&global_options) == UI_SJLJ))
return;
fnsec = function_section (current_function_decl);
switch_to_section (fnsec);
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;
/* We can elide the fde allocation if we're not emitting debug info. */
if (!do_frame)
return;
/* Cater to the various TARGET_ASM_OUTPUT_MI_THUNK implementations that
emit insns as rtx but bypass the bulk of rest_of_compilation, which
would include pass_dwarf2_frame. If we've not created the FDE yet,
do so now. */
fde = cfun->fde;
if (fde == NULL)
fde = dwarf2out_alloc_current_fde ();
/* Initialize the bits of CURRENT_FDE that were not available earlier. */
fde->dw_fde_begin = dup_label;
fde->dw_fde_current_label = dup_label;
fde->in_std_section = (fnsec == text_section
|| (cold_text_section && fnsec == cold_text_section));
/* 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, 0, true);
#endif
if (dwarf2out_do_cfi_asm ())
dwarf2out_do_cfi_startproc (false);
else
{
rtx personality = get_personality_function (current_function_decl);
if (!current_unit_personality)
current_unit_personality = personality;
/* We cannot keep a current personality per function as without CFI
asm, at the point where we emit the CFI data, there is no current
function anymore. */
if (personality && current_unit_personality != personality)
sorry ("multiple EH personalities are supported only with assemblers "
"supporting .cfi_personality directive");
}
}
/* Output a marker (i.e. a label) for the end of the generated code
for a function prologue. This gets called *after* the prologue code has
been generated. */
void
dwarf2out_vms_end_prologue (unsigned int line ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED)
{
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, PROLOGUE_END_LABEL,
current_function_funcdef_no);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, PROLOGUE_END_LABEL,
current_function_funcdef_no);
cfun->fde->dw_fde_vms_end_prologue = xstrdup (label);
}
/* Output a marker (i.e. a label) for the beginning of the generated code
for a function epilogue. This gets called *before* the prologue code has
been generated. */
void
dwarf2out_vms_begin_epilogue (unsigned int line ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED)
{
dw_fde_ref fde = cfun->fde;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
if (fde->dw_fde_vms_begin_epilogue)
return;
/* Output a label to mark the endpoint of the code generated for this
function. */
ASM_GENERATE_INTERNAL_LABEL (label, EPILOGUE_BEGIN_LABEL,
current_function_funcdef_no);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, EPILOGUE_BEGIN_LABEL,
current_function_funcdef_no);
fde->dw_fde_vms_begin_epilogue = xstrdup (label);
}
/* 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];
last_var_location_insn = NULL;
cached_next_real_insn = NULL;
if (dwarf2out_do_cfi_asm ())
fprintf (asm_out_file, "\t.cfi_endproc\n");
/* 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 = cfun->fde;
gcc_assert (fde != NULL);
if (fde->dw_fde_second_begin == NULL)
fde->dw_fde_end = xstrdup (label);
}
void
dwarf2out_frame_finish (void)
{
/* Output call frame information. */
if (targetm.debug_unwind_info () == UI_DWARF2)
output_call_frame_info (0);
/* Output another copy for the unwinder. */
if ((flag_unwind_tables || flag_exceptions)
&& targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
output_call_frame_info (1);
}
/* Note that the current function section is being used for code. */
static void
dwarf2out_note_section_used (void)
{
section *sec = current_function_section ();
if (sec == text_section)
text_section_used = true;
else if (sec == cold_text_section)
cold_text_section_used = true;
}
static void var_location_switch_text_section (void);
static void set_cur_line_info_table (section *);
void
dwarf2out_switch_text_section (void)
{
section *sect;
dw_fde_ref fde = cfun->fde;
gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL);
if (!in_cold_section_p)
{
fde->dw_fde_end = crtl->subsections.cold_section_end_label;
fde->dw_fde_second_begin = crtl->subsections.hot_section_label;
fde->dw_fde_second_end = crtl->subsections.hot_section_end_label;
}
else
{
fde->dw_fde_end = crtl->subsections.hot_section_end_label;
fde->dw_fde_second_begin = crtl->subsections.cold_section_label;
fde->dw_fde_second_end = crtl->subsections.cold_section_end_label;
}
have_multiple_function_sections = true;
/* There is no need to mark used sections when not debugging. */
if (cold_text_section != NULL)
dwarf2out_note_section_used ();
if (dwarf2out_do_cfi_asm ())
fprintf (asm_out_file, "\t.cfi_endproc\n");
/* Now do the real section switch. */
sect = current_function_section ();
switch_to_section (sect);
fde->second_in_std_section
= (sect == text_section
|| (cold_text_section && sect == cold_text_section));
if (dwarf2out_do_cfi_asm ())
dwarf2out_do_cfi_startproc (true);
var_location_switch_text_section ();
if (cold_text_section != NULL)
set_cur_line_info_table (sect);
}
/* And now, the subset of the debugging information support code necessary
for emitting location expressions. */
/* Data about a single source file. */
struct GTY((for_user)) dwarf_file_data {
const char * filename;
int emitted_number;
};
typedef struct GTY(()) deferred_locations_struct
{
tree variable;
dw_die_ref die;
} deferred_locations;
static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
/* Describe an entry into the .debug_addr section. */
enum ate_kind {
ate_kind_rtx,
ate_kind_rtx_dtprel,
ate_kind_label
};
typedef struct GTY((for_user)) addr_table_entry_struct {
enum ate_kind kind;
unsigned int refcount;
unsigned int index;
union addr_table_entry_struct_union
{
rtx GTY ((tag ("0"))) rtl;
char * GTY ((tag ("1"))) label;
}
GTY ((desc ("%1.kind"))) addr;
}
addr_table_entry;
/* 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 GTY(()) dw_loc_list_struct {
dw_loc_list_ref dw_loc_next;
const char *begin; /* Label and addr_entry for start of range */
addr_table_entry *begin_entry;
const char *end; /* Label for end 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;
hashval_t hash;
/* True if all addresses in this and subsequent lists are known to be
resolved. */
bool resolved_addr;
/* True if this list has been replaced by dw_loc_next. */
bool replaced;
bool emitted;
/* True if the range should be emitted even if begin and end
are the same. */
bool force;
} dw_loc_list_node;
static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
/* Convert a DWARF stack opcode into its string name. */
static const char *
dwarf_stack_op_name (unsigned int op)
{
const char *name = get_DW_OP_name (op);
if (name != NULL)
return name;
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_cleared_alloc<dw_loc_descr_node> ();
descr->dw_loc_opc = op;
descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
descr->dw_loc_oprnd1.val_entry = NULL;
descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
descr->dw_loc_oprnd2.val_entry = NULL;
descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
return descr;
}
/* Return a pointer to a newly allocated location description for
REG and OFFSET. */
static inline dw_loc_descr_ref
new_reg_loc_descr (unsigned int reg, unsigned HOST_WIDE_INT offset)
{
if (reg <= 31)
return new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + reg),
offset, 0);
else
return new_loc_descr (DW_OP_bregx, reg, offset);
}
/* 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;
}
/* Compare two location operands for exact equality. */
static bool
dw_val_equal_p (dw_val_node *a, dw_val_node *b)
{
if (a->val_class != b->val_class)
return false;
switch (a->val_class)
{
case dw_val_class_none:
return true;
case dw_val_class_addr:
return rtx_equal_p (a->v.val_addr, b->v.val_addr);
case dw_val_class_offset:
case dw_val_class_unsigned_const:
case dw_val_class_const:
case dw_val_class_range_list:
case dw_val_class_lineptr:
case dw_val_class_macptr:
/* These are all HOST_WIDE_INT, signed or unsigned. */
return a->v.val_unsigned == b->v.val_unsigned;
case dw_val_class_loc:
return a->v.val_loc == b->v.val_loc;
case dw_val_class_loc_list:
return a->v.val_loc_list == b->v.val_loc_list;
case dw_val_class_die_ref:
return a->v.val_die_ref.die == b->v.val_die_ref.die;
case dw_val_class_fde_ref:
return a->v.val_fde_index == b->v.val_fde_index;
case dw_val_class_lbl_id:
case dw_val_class_high_pc:
return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
case dw_val_class_str:
return a->v.val_str == b->v.val_str;
case dw_val_class_flag:
return a->v.val_flag == b->v.val_flag;
case dw_val_class_file:
return a->v.val_file == b->v.val_file;
case dw_val_class_decl_ref:
return a->v.val_decl_ref == b->v.val_decl_ref;
case dw_val_class_const_double:
return (a->v.val_double.high == b->v.val_double.high
&& a->v.val_double.low == b->v.val_double.low);
case dw_val_class_wide_int:
return *a->v.val_wide == *b->v.val_wide;
case dw_val_class_vec:
{
size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length;
return (a_len == b_len
&& !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len));
}
case dw_val_class_data8:
return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0;
case dw_val_class_vms_delta:
return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)
&& !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));
}
gcc_unreachable ();
}
/* Compare two location atoms for exact equality. */
static bool
loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b)
{
if (a->dw_loc_opc != b->dw_loc_opc)
return false;
/* ??? This is only ever set for DW_OP_constNu, for N equal to the
address size, but since we always allocate cleared storage it
should be zero for other types of locations. */
if (a->dtprel != b->dtprel)
return false;
return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1)
&& dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2));
}
/* Compare two complete location expressions for exact equality. */
bool
loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
{
while (1)
{
if (a == b)
return true;
if (a == NULL || b == NULL)
return false;
if (!loc_descr_equal_p_1 (a, b))
return false;
a = a->dw_loc_next;
b = b->dw_loc_next;
}
}
/* Add a constant OFFSET to a location expression. */
static void
loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset)
{
dw_loc_descr_ref loc;
HOST_WIDE_INT *p;
gcc_assert (*list_head != NULL);
if (!offset)
return;
/* Find the end of the chain. */
for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
;
p = NULL;
if (loc->dw_loc_opc == DW_OP_fbreg
|| (loc->dw_loc_opc >= DW_OP_breg0 && loc->dw_loc_opc <= DW_OP_breg31))
p = &loc->dw_loc_oprnd1.v.val_int;
else if (loc->dw_loc_opc == DW_OP_bregx)
p = &loc->dw_loc_oprnd2.v.val_int;
/* If the last operation is fbreg, breg{0..31,x}, optimize by adjusting its
offset. Don't optimize if an signed integer overflow would happen. */
if (p != NULL
&& ((offset > 0 && *p <= INTTYPE_MAXIMUM (HOST_WIDE_INT) - offset)
|| (offset < 0 && *p >= INTTYPE_MINIMUM (HOST_WIDE_INT) - offset)))
*p += offset;
else if (offset > 0)
loc->dw_loc_next = new_loc_descr (DW_OP_plus_uconst, offset, 0);
else
{
loc->dw_loc_next = int_loc_descriptor (-offset);
add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_minus, 0, 0));
}
}
/* Add a constant OFFSET to a location list. */
static void
loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
{
dw_loc_list_ref d;
for (d = list_head; d != NULL; d = d->dw_loc_next)
loc_descr_plus_const (&d->expr, offset);
}
#define DWARF_REF_SIZE \
(dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
static unsigned long int get_base_type_offset (dw_die_ref);
/* 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:
size += DWARF2_ADDR_SIZE;
break;
case DW_OP_GNU_addr_index:
case DW_OP_GNU_const_index:
gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
size += size_of_uleb128 (loc->dw_loc_oprnd1.val_entry->index);
break;
case DW_OP_const1u:
case DW_OP_const1s:
size += 1;
break;
case DW_OP_const2u:
case DW_OP_const2s:
size += 2;
break;
case DW_OP_const4u:
case DW_OP_const4s:
size += 4;
break;
case DW_OP_const8u:
case DW_OP_const8s:
size += 8;
break;
case DW_OP_constu:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_consts:
size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
break;
case DW_OP_pick:
size += 1;
break;
case DW_OP_plus_uconst:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_skip:
case DW_OP_bra:
size += 2;
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
break;
case DW_OP_regx:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_fbreg:
size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
break;
case DW_OP_bregx:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
break;
case DW_OP_piece:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break;
case DW_OP_bit_piece:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
size += size_of_uleb128 (loc->dw_loc_oprnd2.v.val_unsigned);
break;
case DW_OP_deref_size:
case DW_OP_xderef_size:
size += 1;
break;
case DW_OP_call2:
size += 2;
break;
case DW_OP_call4:
size += 4;
break;
case DW_OP_call_ref:
size += DWARF_REF_SIZE;
break;
case DW_OP_implicit_value:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+ loc->dw_loc_oprnd1.v.val_unsigned;
break;
case DW_OP_GNU_implicit_pointer:
size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
break;
case DW_OP_GNU_entry_value:
{
unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc);
size += size_of_uleb128 (op_size) + op_size;
break;
}
case DW_OP_GNU_const_type:
{
unsigned long o
= get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
size += size_of_uleb128 (o) + 1;
switch (loc->dw_loc_oprnd2.val_class)
{
case dw_val_class_vec:
size += loc->dw_loc_oprnd2.v.val_vec.length
* loc->dw_loc_oprnd2.v.val_vec.elt_size;
break;
case dw_val_class_const:
size += HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT;
break;
case dw_val_class_const_double:
size += HOST_BITS_PER_DOUBLE_INT / BITS_PER_UNIT;
break;
case dw_val_class_wide_int:
size += (get_full_len (*loc->dw_loc_oprnd2.v.val_wide)
* HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
break;
default:
gcc_unreachable ();
}
break;
}
case DW_OP_GNU_regval_type:
{
unsigned long o
= get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die);
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+ size_of_uleb128 (o);
}
break;
case DW_OP_GNU_deref_type:
{
unsigned long o
= get_base_type_offset (loc->dw_loc_oprnd2.v.val_die_ref.die);
size += 1 + size_of_uleb128 (o);
}
break;
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
else
{
unsigned long o
= get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
size += size_of_uleb128 (o);
}
break;
case DW_OP_GNU_parameter_ref:
size += 4;
break;
default:
break;
}
return size;
}
/* Return the size of a series of location descriptors. */
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;
}
static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
static void get_ref_die_offset_label (char *, dw_die_ref);
static unsigned long int get_ref_die_offset (dw_die_ref);
/* Output location description stack opcode's operands (if any).
The for_eh_or_skip parameter controls whether register numbers are
converted using DWARF2_FRAME_REG_OUT, which is needed in the case that
hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind
info). This should be suppressed for the cases that have not been converted
(i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */
static void
output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
{
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_const2u:
case DW_OP_const2s:
dw2_asm_output_data (2, val1->v.val_int, NULL);
break;
case DW_OP_const4u:
if (loc->dtprel)
{
gcc_assert (targetm.asm_out.output_dwarf_dtprel);
targetm.asm_out.output_dwarf_dtprel (asm_out_file, 4,
val1->v.val_addr);
fputc ('\n', asm_out_file);
break;
}
/* FALLTHRU */
case DW_OP_const4s:
dw2_asm_output_data (4, val1->v.val_int, NULL);
break;
case DW_OP_const8u:
if (loc->dtprel)
{
gcc_assert (targetm.asm_out.output_dwarf_dtprel);
targetm.asm_out.output_dwarf_dtprel (asm_out_file, 8,
val1->v.val_addr);
fputc ('\n', asm_out_file);
break;
}
/* FALLTHRU */
case DW_OP_const8s:
gcc_assert (HOST_BITS_PER_WIDE_INT >= 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;
case DW_OP_implicit_value:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
switch (val2->val_class)
{
case dw_val_class_const:
dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
break;
case dw_val_class_vec:
{
unsigned int elt_size = val2->v.val_vec.elt_size;
unsigned int len = val2->v.val_vec.length;
unsigned int i;
unsigned char *p;
if (elt_size > sizeof (HOST_WIDE_INT))
{
elt_size /= 2;
len *= 2;
}
for (i = 0, p = val2->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_const_double:
{
unsigned HOST_WIDE_INT first, second;
if (WORDS_BIG_ENDIAN)
{
first = val2->v.val_double.high;
second = val2->v.val_double.low;
}
else
{
first = val2->v.val_double.low;
second = val2->v.val_double.high;
}
dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
first, NULL);
dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
second, NULL);
}
break;
case dw_val_class_wide_int:
{
int i;
int len = get_full_len (*val2->v.val_wide);
if (WORDS_BIG_ENDIAN)
for (i = len - 1; i >= 0; --i)
dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
val2->v.val_wide->elt (i), NULL);
else
for (i = 0; i < len; ++i)
dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
val2->v.val_wide->elt (i), NULL);
}
break;
case dw_val_class_addr:
gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
break;
default:
gcc_unreachable ();
}
break;
#else
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:
case DW_OP_implicit_value:
/* 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:
{
unsigned r = val1->v.val_unsigned;
if (for_eh_or_skip >= 0)
r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
gcc_assert (size_of_uleb128 (r)
== size_of_uleb128 (val1->v.val_unsigned));
dw2_asm_output_data_uleb128 (r, NULL);
}
break;
case DW_OP_fbreg:
dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
break;
case DW_OP_bregx:
{
unsigned r = val1->v.val_unsigned;
if (for_eh_or_skip >= 0)
r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
gcc_assert (size_of_uleb128 (r)
== size_of_uleb128 (val1->v.val_unsigned));
dw2_asm_output_data_uleb128 (r, NULL);
dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
}
break;
case DW_OP_piece:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
break;
case DW_OP_bit_piece:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
dw2_asm_output_data_uleb128 (val2->v.val_unsigned, NULL);
break;
case DW_OP_deref_size:
case DW_OP_xderef_size:
dw2_asm_output_data (1, val1->v.val_int, NULL);
break;
case DW_OP_addr:
if (loc->dtprel)
{
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 ();
}
else
{
#ifdef DWARF2_DEBUGGING_INFO
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
#else
gcc_unreachable ();
#endif
}
break;
case DW_OP_GNU_addr_index:
case DW_OP_GNU_const_index:
gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_entry->index,
"(index into .debug_addr)");
break;
case DW_OP_GNU_implicit_pointer:
{
char label[MAX_ARTIFICIAL_LABEL_BYTES
+ HOST_BITS_PER_WIDE_INT / 2 + 2];
gcc_assert (val1->val_class == dw_val_class_die_ref);
get_ref_die_offset_label (label, val1->v.val_die_ref.die);
dw2_asm_output_offset (DWARF_REF_SIZE, label, debug_info_section, NULL);
dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
}
break;
case DW_OP_GNU_entry_value:
dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL);
output_loc_sequence (val1->v.val_loc, for_eh_or_skip);
break;
case DW_OP_GNU_const_type:
{
unsigned long o = get_base_type_offset (val1->v.val_die_ref.die), l;
gcc_assert (o);
dw2_asm_output_data_uleb128 (o, NULL);
switch (val2->val_class)
{
case dw_val_class_const:
l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
dw2_asm_output_data (1, l, NULL);
dw2_asm_output_data (l, val2->v.val_int, NULL);
break;
case dw_val_class_vec:
{
unsigned int elt_size = val2->v.val_vec.elt_size;
unsigned int len = val2->v.val_vec.length;
unsigned int i;
unsigned char *p;
l = len * elt_size;
dw2_asm_output_data (1, l, NULL);
if (elt_size > sizeof (HOST_WIDE_INT))
{
elt_size /= 2;
len *= 2;
}
for (i = 0, p = val2->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_const_double:
{
unsigned HOST_WIDE_INT first, second;
l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
dw2_asm_output_data (1, 2 * l, NULL);
if (WORDS_BIG_ENDIAN)
{
first = val2->v.val_double.high;
second = val2->v.val_double.low;
}
else
{
first = val2->v.val_double.low;
second = val2->v.val_double.high;
}
dw2_asm_output_data (l, first, NULL);
dw2_asm_output_data (l, second, NULL);
}
break;
case dw_val_class_wide_int:
{
int i;
int len = get_full_len (*val2->v.val_wide);
l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
dw2_asm_output_data (1, len * l, NULL);
if (WORDS_BIG_ENDIAN)
for (i = len - 1; i >= 0; --i)
dw2_asm_output_data (l, val2->v.val_wide->elt (i), NULL);
else
for (i = 0; i < len; ++i)
dw2_asm_output_data (l, val2->v.val_wide->elt (i), NULL);
}
break;
default:
gcc_unreachable ();
}
}
break;
case DW_OP_GNU_regval_type:
{
unsigned r = val1->v.val_unsigned;
unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
gcc_assert (o);
if (for_eh_or_skip >= 0)
{
r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
gcc_assert (size_of_uleb128 (r)
== size_of_uleb128 (val1->v.val_unsigned));
}
dw2_asm_output_data_uleb128 (r, NULL);
dw2_asm_output_data_uleb128 (o, NULL);
}
break;
case DW_OP_GNU_deref_type:
{
unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
gcc_assert (o);
dw2_asm_output_data (1, val1->v.val_int, NULL);
dw2_asm_output_data_uleb128 (o, NULL);
}
break;
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
else
{
unsigned long o = get_base_type_offset (val1->v.val_die_ref.die);
gcc_assert (o);
dw2_asm_output_data_uleb128 (o, NULL);
}
break;
case DW_OP_GNU_parameter_ref:
{
unsigned long o;
gcc_assert (val1->val_class == dw_val_class_die_ref);
o = get_ref_die_offset (val1->v.val_die_ref.die);
dw2_asm_output_data (4, o, NULL);
}
break;
default:
/* Other codes have no operands. */
break;
}
}
/* Output a sequence of location operations.
The for_eh_or_skip parameter controls whether register numbers are
converted using DWARF2_FRAME_REG_OUT, which is needed in the case that
hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind
info). This should be suppressed for the cases that have not been converted
(i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */
void
output_loc_sequence (dw_loc_descr_ref loc, int for_eh_or_skip)
{
for (; loc != NULL; loc = loc->dw_loc_next)
{
enum dwarf_location_atom opc = loc->dw_loc_opc;
/* Output the opcode. */
if (for_eh_or_skip >= 0
&& opc >= DW_OP_breg0 && opc <= DW_OP_breg31)
{
unsigned r = (opc - DW_OP_breg0);
r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
gcc_assert (r <= 31);
opc = (enum dwarf_location_atom) (DW_OP_breg0 + r);
}
else if (for_eh_or_skip >= 0
&& opc >= DW_OP_reg0 && opc <= DW_OP_reg31)
{
unsigned r = (opc - DW_OP_reg0);
r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip);
gcc_assert (r <= 31);
opc = (enum dwarf_location_atom) (DW_OP_reg0 + r);
}
dw2_asm_output_data (1, opc,
"%s", dwarf_stack_op_name (opc));
/* Output the operand(s) (if any). */
output_loc_operands (loc, for_eh_or_skip);
}
}
/* Output location description stack opcode's operands (if any).
The output is single bytes on a line, suitable for .cfi_escape. */
static void
output_loc_operands_raw (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)
{
case DW_OP_addr:
case DW_OP_GNU_addr_index:
case DW_OP_GNU_const_index:
case DW_OP_implicit_value:
/* We cannot output addresses in .cfi_escape, only bytes. */
gcc_unreachable ();
case DW_OP_const1u:
case DW_OP_const1s:
case DW_OP_pick:
case DW_OP_deref_size:
case DW_OP_xderef_size:
fputc (',', asm_out_file);
dw2_asm_output_data_raw (1, val1->v.val_int);
break;
case DW_OP_const2u:
case DW_OP_const2s:
fputc (',', asm_out_file);
dw2_asm_output_data_raw (2, val1->v.val_int);
break;
case DW_OP_const4u:
case DW_OP_const4s:
fputc (',', asm_out_file);
dw2_asm_output_data_raw (4, val1->v.val_int);
break;
case DW_OP_const8u:
case DW_OP_const8s:
gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
fputc (',', asm_out_file);
dw2_asm_output_data_raw (8, val1->v.val_int);
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);
fputc (',', asm_out_file);
dw2_asm_output_data_raw (2, offset);
}
break;
case DW_OP_regx:
{
unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1);
gcc_assert (size_of_uleb128 (r)
== size_of_uleb128 (val1->v.val_unsigned));
fputc (',', asm_out_file);
dw2_asm_output_data_uleb128_raw (r);
}
break;
case DW_OP_constu:
case DW_OP_plus_uconst:
case DW_OP_piece:
fputc (',', asm_out_file);
dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
break;
case DW_OP_bit_piece:
fputc (',', asm_out_file);
dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
dw2_asm_output_data_uleb128_raw (val2->v.val_unsigned);
break;
case DW_OP_consts:
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:
case DW_OP_fbreg:
fputc (',', asm_out_file);
dw2_asm_output_data_sleb128_raw (val1->v.val_int);
break;
case DW_OP_bregx:
{
unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1);
gcc_assert (size_of_uleb128 (r)
== size_of_uleb128 (val1->v.val_unsigned));
fputc (',', asm_out_file);
dw2_asm_output_data_uleb128_raw (r);
fputc (',', asm_out_file);
dw2_asm_output_data_sleb128_raw (val2->v.val_int);
}
break;
case DW_OP_GNU_implicit_pointer:
case DW_OP_GNU_entry_value:
case DW_OP_GNU_const_type:
case DW_OP_GNU_regval_type:
case DW_OP_GNU_deref_type:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
case DW_OP_GNU_parameter_ref:
gcc_unreachable ();
break;
default:
/* Other codes have no operands. */
break;
}
}
void
output_loc_sequence_raw (dw_loc_descr_ref loc)
{
while (1)
{
enum dwarf_location_atom opc = loc->dw_loc_opc;
/* Output the opcode. */
if (opc >= DW_OP_breg0 && opc <= DW_OP_breg31)
{
unsigned r = (opc - DW_OP_breg0);
r = DWARF2_FRAME_REG_OUT (r, 1);
gcc_assert (r <= 31);
opc = (enum dwarf_location_atom) (DW_OP_breg0 + r);
}
else if (opc >= DW_OP_reg0 && opc <= DW_OP_reg31)
{
unsigned r = (opc - DW_OP_reg0);
r = DWARF2_FRAME_REG_OUT (r, 1);
gcc_assert (r <= 31);
opc = (enum dwarf_location_atom) (DW_OP_reg0 + r);
}
/* Output the opcode. */
fprintf (asm_out_file, "%#x", opc);
output_loc_operands_raw (loc);
if (!loc->dw_loc_next)
break;
loc = loc->dw_loc_next;
fputc (',', asm_out_file);
}
}
/* This function builds a dwarf location descriptor sequence from a
dw_cfa_location, adding the given OFFSET to the result of the
expression. */
struct dw_loc_descr_node *
build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
{
struct dw_loc_descr_node *head, *tmp;
offset += cfa->offset;
if (cfa->indirect)
{
head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
head->dw_loc_oprnd1.val_class = dw_val_class_const;
head->dw_loc_oprnd1.val_entry = NULL;
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
head = new_reg_loc_descr (cfa->reg, offset);
return head;
}
/* This function builds a dwarf location descriptor sequence for
the address at OFFSET from the CFA when stack is aligned to
ALIGNMENT byte. */
struct dw_loc_descr_node *
build_cfa_aligned_loc (dw_cfa_location *cfa,
HOST_WIDE_INT offset, HOST_WIDE_INT alignment)
{
struct dw_loc_descr_node *head;
unsigned int dwarf_fp
= DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
/* When CFA is defined as FP+OFFSET, emulate stack alignment. */
if (cfa->reg == HARD_FRAME_POINTER_REGNUM && cfa->indirect == 0)
{
head = new_reg_loc_descr (dwarf_fp, 0);
add_loc_descr (&head, int_loc_descriptor (alignment));
add_loc_descr (&head, new_loc_descr (DW_OP_and, 0, 0));
loc_descr_plus_const (&head, offset);
}
else
head = new_reg_loc_descr (dwarf_fp, offset);
return head;
}
/* And now, the support for symbolic debugging information. */
/* .debug_str support. */
static void dwarf2out_init (const char *);
static void dwarf2out_finish (const char *);
static void dwarf2out_assembly_start (void);
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_function_decl (tree);
static void dwarf2out_begin_block (unsigned, unsigned);
static void dwarf2out_end_block (unsigned, unsigned);
static bool dwarf2out_ignore_block (const_tree);
static void dwarf2out_global_decl (tree);
static void dwarf2out_type_decl (tree, int);
static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
dw_die_ref);
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx_insn *);
static void dwarf2out_begin_function (tree);
static void dwarf2out_end_function (unsigned int);
static void dwarf2out_register_main_translation_unit (tree unit);
static void dwarf2out_set_name (tree, tree);
/* The debug hooks structure. */
const struct gcc_debug_hooks dwarf2_debug_hooks =
{
dwarf2out_init,
dwarf2out_finish,
dwarf2out_assembly_start,
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,
#if VMS_DEBUGGING_INFO
dwarf2out_vms_end_prologue,
dwarf2out_vms_begin_epilogue,
#else
debug_nothing_int_charstar,
debug_nothing_int_charstar,
#endif
dwarf2out_end_epilogue,
dwarf2out_begin_function,
dwarf2out_end_function, /* end_function */
dwarf2out_register_main_translation_unit,
dwarf2out_function_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_code_label, /* label */
debug_nothing_int, /* handle_pch */
dwarf2out_var_location,
dwarf2out_switch_text_section,
dwarf2out_set_name,
1, /* start_end_main_source_file */
TYPE_SYMTAB_IS_DIE /* tree_type_symtab_field */
};
/* 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. */
/* Whether to put type DIEs into their own section .debug_types instead
of making them part of the .debug_info section. Only supported for
Dwarf V4 or higher and the user didn't disable them through
-fno-debug-types-section. It is more efficient to put them in a
separate comdat sections since the linker will then be able to
remove duplicates. But not all tools support .debug_types sections
yet. */
#define use_debug_types (dwarf_version >= 4 && flag_debug_types_section)
/* 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 pubname_struct *pubname_ref;
typedef struct dw_ranges_struct *dw_ranges_ref;
typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref;
typedef struct comdat_type_struct *comdat_type_node_ref;
/* The entries in the line_info table more-or-less mirror the opcodes
that are used in the real dwarf line table. Arrays of these entries
are collected per section when DWARF2_ASM_LINE_DEBUG_INFO is not
supported. */
enum dw_line_info_opcode {
/* Emit DW_LNE_set_address; the operand is the label index. */
LI_set_address,
/* Emit a row to the matrix with the given line. This may be done
via any combination of DW_LNS_copy, DW_LNS_advance_line, and
special opcodes. */
LI_set_line,
/* Emit a DW_LNS_set_file. */
LI_set_file,
/* Emit a DW_LNS_set_column. */
LI_set_column,
/* Emit a DW_LNS_negate_stmt; the operand is ignored. */
LI_negate_stmt,
/* Emit a DW_LNS_set_prologue_end/epilogue_begin; the operand is ignored. */
LI_set_prologue_end,
LI_set_epilogue_begin,
/* Emit a DW_LNE_set_discriminator. */
LI_set_discriminator
};
typedef struct GTY(()) dw_line_info_struct {
enum dw_line_info_opcode opcode;
unsigned int val;
} dw_line_info_entry;
typedef struct GTY(()) dw_line_info_table_struct {
/* The label that marks the end of this section. */
const char *end_label;
/* The values for the last row of the matrix, as collected in the table.
These are used to minimize the changes to the next row. */
unsigned int file_num;
unsigned int line_num;
unsigned int column_num;
int discrim_num;
bool is_stmt;
bool in_use;
vec<dw_line_info_entry, va_gc> *entries;
} dw_line_info_table;
typedef dw_line_info_table *dw_line_info_table_p;
/* 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 GTY(()) dw_attr_struct {
enum dwarf_attribute dw_attr;
dw_val_node dw_attr_val;
}
dw_attr_node;
/* 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 GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
union die_symbol_or_type_node
{
const char * GTY ((tag ("0"))) die_symbol;
comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
}
GTY ((desc ("%0.comdat_type_p"))) die_id;
vec<dw_attr_node, va_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;
unsigned int decl_id;
enum dwarf_tag die_tag;
/* Die is used and must not be pruned as unused. */
BOOL_BITFIELD die_perennial_p : 1;
BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
/* Lots of spare bits. */
}
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 GTY(()) pubname_struct {
dw_die_ref die;
const char *name;
}
pubname_entry;
struct GTY(()) dw_ranges_struct {
/* If this is positive, it's a block number, otherwise it's a
bitwise-negated index into dw_ranges_by_label. */
int num;
};
/* A structure to hold a macinfo entry. */
typedef struct GTY(()) macinfo_struct {
unsigned char code;
unsigned HOST_WIDE_INT lineno;
const char *info;
}
macinfo_entry;
struct GTY(()) dw_ranges_by_label_struct {
const char *begin;
const char *end;
};
/* The comdat type node structure. */
typedef struct GTY(()) comdat_type_struct
{
dw_die_ref root_die;
dw_die_ref type_die;
dw_die_ref skeleton_die;
char signature[DWARF_TYPE_SIGNATURE_SIZE];
struct comdat_type_struct *next;
}
comdat_type_node;
/* The limbo die list structure. */
typedef struct GTY(()) limbo_die_struct {
dw_die_ref die;
tree created_for;
struct limbo_die_struct *next;
}
limbo_die_node;
typedef struct skeleton_chain_struct
{
dw_die_ref old_die;
dw_die_ref new_die;
struct skeleton_chain_struct *parent;
}
skeleton_chain_node;
/* Define a macro which returns nonzero for a TYPE_DECL which was
implicitly generated for a type.
Note that, unlike the C 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 C++ 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. Likewise with the Ada
front-end, but for each type, tagged or not. */
#define TYPE_DECL_IS_STUB(decl) \
(DECL_NAME (decl) == NULL_TREE \
|| (DECL_ARTIFICIAL (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 the DWARF comdat type unit header. */
#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \
(DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \
+ DWARF_OFFSET_SIZE)
/* Fixed size portion of public names info. */
#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
/* 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 ((int)DW_LNS_set_isa + 1)
/* 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
/* Maximum number of operations per instruction bundle. */
#ifndef DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN
#define DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN 1
#endif
/* 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;
/* Record the root of the DIE's built for the current compilation unit. */
static GTY(()) dw_die_ref single_comp_unit_die;
/* A list of type DIEs that have been separated into comdat sections. */
static GTY(()) comdat_type_node *comdat_type_list;
/* A list of DIEs with a NULL parent waiting to be relocated. */
static GTY(()) limbo_die_node *limbo_die_list;
/* A list of DIEs for which we may have to generate
DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set. */
static GTY(()) limbo_die_node *deferred_asm_name;
struct dwarf_file_hasher : ggc_hasher<dwarf_file_data *>
{
typedef const char *compare_type;
static hashval_t hash (dwarf_file_data *);
static bool equal (dwarf_file_data *, const char *);
};
/* Filenames referenced by this compilation unit. */
static GTY(()) hash_table<dwarf_file_hasher> *file_table;
struct decl_die_hasher : ggc_hasher<die_node *>
{
typedef tree compare_type;
static hashval_t hash (die_node *);
static bool equal (die_node *, tree);
};
/* 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 (()) hash_table<decl_die_hasher> *decl_die_table;
struct block_die_hasher : ggc_hasher<die_struct *>
{
static hashval_t hash (die_struct *);
static bool equal (die_struct *, die_struct *);
};
/* A hash table of references to DIE's that describe COMMON blocks.
The key is DECL_UID() ^ die_parent. */
static GTY (()) hash_table<block_die_hasher> *common_block_die_table;
typedef struct GTY(()) die_arg_entry_struct {
dw_die_ref die;
tree arg;
} die_arg_entry;
/* Node of the variable location list. */
struct GTY ((chain_next ("%h.next"))) var_loc_node {
/* Either NOTE_INSN_VAR_LOCATION, or, for SRA optimized variables,
EXPR_LIST chain. For small bitsizes, bitsize is encoded
in mode of the EXPR_LIST node and first EXPR_LIST operand
is either NOTE_INSN_VAR_LOCATION for a piece with a known
location or NULL for padding. For larger bitsizes,
mode is 0 and first operand is a CONCAT with bitsize
as first CONCAT operand and NOTE_INSN_VAR_LOCATION resp.
NULL as second operand. */
rtx GTY (()) loc;
const char * GTY (()) label;
struct var_loc_node * GTY (()) next;
};
/* Variable location list. */
struct GTY ((for_user)) var_loc_list_def {
struct var_loc_node * GTY (()) first;
/* Pointer to the last but one or last element of the
chained list. If the list is empty, both first and
last are NULL, if the list contains just one node
or the last node certainly is not redundant, it points
to the last node, otherwise points to the last but one.
Do not mark it for GC because it is marked through the chain. */
struct var_loc_node * GTY ((skip ("%h"))) last;
/* Pointer to the last element before section switch,
if NULL, either sections weren't switched or first
is after section switch. */
struct var_loc_node * GTY ((skip ("%h"))) last_before_switch;
/* DECL_UID of the variable decl. */
unsigned int decl_id;
};
typedef struct var_loc_list_def var_loc_list;
/* Call argument location list. */
struct GTY ((chain_next ("%h.next"))) call_arg_loc_node {
rtx GTY (()) call_arg_loc_note;
const char * GTY (()) label;
tree GTY (()) block;
bool tail_call_p;
rtx GTY (()) symbol_ref;
struct call_arg_loc_node * GTY (()) next;
};
struct decl_loc_hasher : ggc_hasher<var_loc_list *>
{
typedef const_tree compare_type;
static hashval_t hash (var_loc_list *);
static bool equal (var_loc_list *, const_tree);
};
/* Table of decl location linked lists. */
static GTY (()) hash_table<decl_loc_hasher> *decl_loc_table;
/* Head and tail of call_arg_loc chain. */
static GTY (()) struct call_arg_loc_node *call_arg_locations;
static struct call_arg_loc_node *call_arg_loc_last;
/* Number of call sites in the current function. */
static int call_site_count = -1;
/* Number of tail call sites in the current function. */
static int tail_call_site_count = -1;
/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
DIEs. */
static vec<dw_die_ref> block_map;
/* A cached location list. */
struct GTY ((for_user)) cached_dw_loc_list_def {
/* The DECL_UID of the decl that this entry describes. */
unsigned int decl_id;
/* The cached location list. */
dw_loc_list_ref loc_list;
};
typedef struct cached_dw_loc_list_def cached_dw_loc_list;
struct dw_loc_list_hasher : ggc_hasher<cached_dw_loc_list *>
{
typedef const_tree compare_type;
static hashval_t hash (cached_dw_loc_list *);
static bool equal (cached_dw_loc_list *, const_tree);
};
/* Table of cached location lists. */
static GTY (()) hash_table<dw_loc_list_hasher> *cached_dw_loc_list_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 global counter for generating labels for line number data. */
static unsigned int line_info_label_num;
/* The current table to which we should emit line number information
for the current function. This will be set up at the beginning of
assembly for the function. */
static dw_line_info_table *cur_line_info_table;
/* The two default tables of line number info. */
static GTY(()) dw_line_info_table *text_section_line_info;
static GTY(()) dw_line_info_table *cold_text_section_line_info;
/* The set of all non-default tables of line number info. */
static GTY(()) vec<dw_line_info_table_p, va_gc> *separate_line_info;
/* A flag to tell pubnames/types export if there is an info section to
refer to. */
static bool info_section_emitted;
/* A pointer to the base of a table that contains a list of publicly
accessible names. */
static GTY (()) vec<pubname_entry, va_gc> *pubname_table;
/* A pointer to the base of a table that contains a list of publicly
accessible types. */
static GTY (()) vec<pubname_entry, va_gc> *pubtype_table;
/* A pointer to the base of a table that contains a list of macro
defines/undefines (and file start/end markers). */
static GTY (()) vec<macinfo_entry, va_gc> *macinfo_table;
/* True if .debug_macinfo or .debug_macros section is going to be
emitted. */
#define have_macinfo \
(debug_info_level >= DINFO_LEVEL_VERBOSE \
&& !macinfo_table->is_empty ())
/* 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;
/* Array of pairs of labels referenced in ranges_table. */
static GTY ((length ("ranges_by_label_allocated")))
dw_ranges_by_label_ref ranges_by_label;
/* Number of elements currently allocated for ranges_by_label. */
static GTY(()) unsigned ranges_by_label_allocated;
/* Number of elements in ranges_by_label currently in use. */
static GTY(()) unsigned ranges_by_label_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;
/* Unique label counter for point-of-call tables. */
static GTY(()) unsigned int poc_label_num;
/* 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;
static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
/* Instances of generic types for which we need to generate debug
info that describe their generic parameters and arguments. That
generation needs to happen once all types are properly laid out so
we do it at the end of compilation. */
static GTY(()) vec<tree, va_gc> *generic_type_instances;
/* Offset from the "steady-state frame pointer" to the frame base,
within the current function. */
static HOST_WIDE_INT frame_pointer_fb_offset;
static bool frame_pointer_fb_offset_valid;
static vec<dw_die_ref> base_types;
/* Flags to represent a set of attribute classes for attributes that represent
a scalar value (bounds, pointers, ...). */
enum dw_scalar_form
{
dw_scalar_form_constant = 0x01,
dw_scalar_form_exprloc = 0x02,
dw_scalar_form_reference = 0x04
};
/* Forward declarations for functions defined in this file. */
static int is_pseudo_reg (const_rtx);
static tree type_main_variant (tree);
static int is_tagged_type (const_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 (const_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 inline unsigned int AT_index (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_double (dw_die_ref, enum dwarf_attribute,
HOST_WIDE_INT, unsigned HOST_WIDE_INT);
static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
unsigned int, unsigned char *);
static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *);
static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
static inline const char *AT_string (dw_attr_ref);
static enum dwarf_form 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 addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
static void remove_addr_table_entry (addr_table_entry *);
static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
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, bool);
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_cxx (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 dw_die_ref strip_naming_typedef (tree, dw_die_ref);
static dw_die_ref lookup_type_die_strip_naming_typedef (tree);
static void equate_type_number_to_die (tree, dw_die_ref);
static dw_die_ref lookup_decl_die (tree);
static var_loc_list *lookup_decl_loc (const_tree);
static void equate_decl_number_to_die (tree, dw_die_ref);
static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, 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 void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *);
static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *);
static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *);
static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref,
struct md5_ctx *, int *);
struct checksum_attributes;
static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref);
static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *);
static void checksum_die_context (dw_die_ref, struct md5_ctx *);
static void generate_type_signature (dw_die_ref, comdat_type_node *);
static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
static int same_dw_val_p (const dw_val_node *, const 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 inline bool is_template_instantiation (dw_die_ref);
static void assign_symbol_names (dw_die_ref);
static void break_out_includes (dw_die_ref);
static int is_declaration_die (dw_die_ref);
static int should_move_die_to_comdat (dw_die_ref);
static dw_die_ref clone_as_declaration (dw_die_ref);
static dw_die_ref clone_die (dw_die_ref);
static dw_die_ref clone_tree (dw_die_ref);
static dw_die_ref copy_declaration_context (dw_die_ref, dw_die_ref);
static void generate_skeleton_ancestor_tree (skeleton_chain_node *);
static void generate_skeleton_bottom_up (skeleton_chain_node *);
static dw_die_ref generate_skeleton (dw_die_ref);
static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref,
dw_die_ref,
dw_die_ref);
static void break_out_comdat_types (dw_die_ref);
static void copy_decls_for_unworthy_types (dw_die_ref);
static void add_sibling_attributes (dw_die_ref);
static void output_location_lists (dw_die_ref);
static int constant_size (unsigned HOST_WIDE_INT);
static unsigned long size_of_die (dw_die_ref);
static void calc_die_sizes (dw_die_ref);
static void calc_base_type_die_sizes (void);
static void mark_dies (dw_die_ref);
static void unmark_dies (dw_die_ref);
static void unmark_all_dies (dw_die_ref);
static unsigned long size_of_pubnames (vec<pubname_entry, va_gc> *);
static unsigned long size_of_aranges (void);
static enum dwarf_form value_format