/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
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 "tree.h"
#include "version.h"
#include "flags.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "insn-config.h"
#include "reload.h"
#include "function.h"
#include "output.h"
#include "expr.h"
#include "libfuncs.h"
#include "except.h"
#include "dwarf2.h"
#include "dwarf2out.h"
#include "dwarf2asm.h"
#include "toplev.h"
#include "ggc.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 "hashtab.h"
#include "cgraph.h"
#include "input.h"
#include "gimple.h"
#include "tree-pass.h"
#include "tree-flow.h"
#include "cfglayout.h"
#include "opts.h"
static void dwarf2out_source_line (unsigned int, const char *, int, bool);
static rtx last_var_location_insn;
static rtx cached_next_real_insn;
#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,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;
static GTY(()) section *debug_pubtypes_section;
static GTY(()) section *debug_str_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
DEF_VEC_P (dw_fde_ref);
DEF_VEC_ALLOC_P (dw_fde_ref, gc);
/* A vector for a table that contains frame description
information for each routine. */
static GTY(()) VEC(dw_fde_ref, gc) *fde_vec;
struct GTY(()) indirect_string_node {
const char *str;
unsigned int refcount;
enum dwarf_form form;
char *label;
};
static GTY ((param_is (struct indirect_string_node))) htab_t 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;
/* 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
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 (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_length (dw_cfi_ref, 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 (VEC_index (dw_cfi_ref, 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 == NULL)
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 (dw_fde_ref, 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 (dw_cfi_ref, 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 (dw_fde_ref, 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");
#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 ();
}
/* 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_alloc_cleared_dw_fde_node ();
fde->decl = current_function_decl;
fde->funcdef_number = current_function_funcdef_no;
fde->fde_index = VEC_length (dw_fde_ref, 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 (dw_fde_ref, gc, 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_TARGET))
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_RTX;
cached_next_real_insn = NULL_RTX;
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 ();
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(()) dwarf_file_data {
const char * filename;
int emitted_number;
};
typedef struct GTY(()) deferred_locations_struct
{
tree variable;
dw_die_ref die;
} deferred_locations;
DEF_VEC_O(deferred_locations);
DEF_VEC_ALLOC_O(deferred_locations,gc);
static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
DEF_VEC_P(dw_die_ref);
DEF_VEC_ALLOC_P(dw_die_ref,heap);
/* 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 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;
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)
{
switch (op)
{
case DW_OP_addr:
return "DW_OP_addr";
case DW_OP_deref:
return "DW_OP_deref";
case DW_OP_const1u:
return "DW_OP_const1u";
case DW_OP_const1s:
return "DW_OP_const1s";
case DW_OP_const2u:
return "DW_OP_const2u";
case DW_OP_const2s:
return "DW_OP_const2s";
case DW_OP_const4u:
return "DW_OP_const4u";
case DW_OP_const4s:
return "DW_OP_const4s";
case DW_OP_const8u:
return "DW_OP_const8u";
case DW_OP_const8s:
return "DW_OP_const8s";
case DW_OP_constu:
return "DW_OP_constu";
case DW_OP_consts:
return "DW_OP_consts";
case DW_OP_dup:
return "DW_OP_dup";
case DW_OP_drop:
return "DW_OP_drop";
case DW_OP_over:
return "DW_OP_over";
case DW_OP_pick:
return "DW_OP_pick";
case DW_OP_swap:
return "DW_OP_swap";
case DW_OP_rot:
return "DW_OP_rot";
case DW_OP_xderef:
return "DW_OP_xderef";
case DW_OP_abs:
return "DW_OP_abs";
case DW_OP_and:
return "DW_OP_and";
case DW_OP_div:
return "DW_OP_div";
case DW_OP_minus:
return "DW_OP_minus";
case DW_OP_mod:
return "DW_OP_mod";
case DW_OP_mul:
return "DW_OP_mul";
case DW_OP_neg:
return "DW_OP_neg";
case DW_OP_not:
return "DW_OP_not";
case DW_OP_or:
return "DW_OP_or";
case DW_OP_plus:
return "DW_OP_plus";
case DW_OP_plus_uconst:
return "DW_OP_plus_uconst";
case DW_OP_shl:
return "DW_OP_shl";
case DW_OP_shr:
return "DW_OP_shr";
case DW_OP_shra:
return "DW_OP_shra";
case DW_OP_xor:
return "DW_OP_xor";
case DW_OP_bra:
return "DW_OP_bra";
case DW_OP_eq:
return "DW_OP_eq";
case DW_OP_ge:
return "DW_OP_ge";
case DW_OP_gt:
return "DW_OP_gt";
case DW_OP_le:
return "DW_OP_le";
case DW_OP_lt:
return "DW_OP_lt";
case DW_OP_ne:
return "DW_OP_ne";
case DW_OP_skip:
return "DW_OP_skip";
case DW_OP_lit0:
return "DW_OP_lit0";
case DW_OP_lit1:
return "DW_OP_lit1";
case DW_OP_lit2:
return "DW_OP_lit2";
case DW_OP_lit3:
return "DW_OP_lit3";
case DW_OP_lit4:
return "DW_OP_lit4";
case DW_OP_lit5:
return "DW_OP_lit5";
case DW_OP_lit6:
return "DW_OP_lit6";
case DW_OP_lit7:
return "DW_OP_lit7";
case DW_OP_lit8:
return "DW_OP_lit8";
case DW_OP_lit9:
return "DW_OP_lit9";
case DW_OP_lit10:
return "DW_OP_lit10";
case DW_OP_lit11:
return "DW_OP_lit11";
case DW_OP_lit12:
return "DW_OP_lit12";
case DW_OP_lit13:
return "DW_OP_lit13";
case DW_OP_lit14:
return "DW_OP_lit14";
case DW_OP_lit15:
return "DW_OP_lit15";
case DW_OP_lit16:
return "DW_OP_lit16";
case DW_OP_lit17:
return "DW_OP_lit17";
case DW_OP_lit18:
return "DW_OP_lit18";
case DW_OP_lit19:
return "DW_OP_lit19";
case DW_OP_lit20:
return "DW_OP_lit20";
case DW_OP_lit21:
return "DW_OP_lit21";
case DW_OP_lit22:
return "DW_OP_lit22";
case DW_OP_lit23:
return "DW_OP_lit23";
case DW_OP_lit24:
return "DW_OP_lit24";
case DW_OP_lit25:
return "DW_OP_lit25";
case DW_OP_lit26:
return "DW_OP_lit26";
case DW_OP_lit27:
return "DW_OP_lit27";
case DW_OP_lit28:
return "DW_OP_lit28";
case DW_OP_lit29:
return "DW_OP_lit29";
case DW_OP_lit30:
return "DW_OP_lit30";
case DW_OP_lit31:
return "DW_OP_lit31";
case DW_OP_reg0:
return "DW_OP_reg0";
case DW_OP_reg1:
return "DW_OP_reg1";
case DW_OP_reg2:
return "DW_OP_reg2";
case DW_OP_reg3:
return "DW_OP_reg3";
case DW_OP_reg4:
return "DW_OP_reg4";
case DW_OP_reg5:
return "DW_OP_reg5";
case DW_OP_reg6:
return "DW_OP_reg6";
case DW_OP_reg7:
return "DW_OP_reg7";
case DW_OP_reg8:
return "DW_OP_reg8";
case DW_OP_reg9:
return "DW_OP_reg9";
case DW_OP_reg10:
return "DW_OP_reg10";
case DW_OP_reg11:
return "DW_OP_reg11";
case DW_OP_reg12:
return "DW_OP_reg12";
case DW_OP_reg13:
return "DW_OP_reg13";
case DW_OP_reg14:
return "DW_OP_reg14";
case DW_OP_reg15:
return "DW_OP_reg15";
case DW_OP_reg16:
return "DW_OP_reg16";
case DW_OP_reg17:
return "DW_OP_reg17";
case DW_OP_reg18:
return "DW_OP_reg18";
case DW_OP_reg19:
return "DW_OP_reg19";
case DW_OP_reg20:
return "DW_OP_reg20";
case DW_OP_reg21:
return "DW_OP_reg21";
case DW_OP_reg22:
return "DW_OP_reg22";
case DW_OP_reg23:
return "DW_OP_reg23";
case DW_OP_reg24:
return "DW_OP_reg24";
case DW_OP_reg25:
return "DW_OP_reg25";
case DW_OP_reg26:
return "DW_OP_reg26";
case DW_OP_reg27:
return "DW_OP_reg27";
case DW_OP_reg28:
|