blob: 9876750e4f9f0f91d44c3b333e8195d10b287729 [file] [log] [blame]
/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992-2021 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 "target.h"
#include "function.h"
#include "rtl.h"
#include "tree.h"
#include "memmodel.h"
#include "tm_p.h"
#include "stringpool.h"
#include "insn-config.h"
#include "ira.h"
#include "cgraph.h"
#include "diagnostic.h"
#include "fold-const.h"
#include "stor-layout.h"
#include "varasm.h"
#include "version.h"
#include "flags.h"
#include "rtlhash.h"
#include "reload.h"
#include "output.h"
#include "expr.h"
#include "dwarf2out.h"
#include "dwarf2ctf.h"
#include "dwarf2asm.h"
#include "toplev.h"
#include "md5.h"
#include "tree-pretty-print.h"
#include "print-rtl.h"
#include "debug.h"
#include "common/common-target.h"
#include "langhooks.h"
#include "lra.h"
#include "dumpfile.h"
#include "opts.h"
#include "tree-dfa.h"
#include "gdb/gdb-index.h"
#include "rtl-iter.h"
#include "stringpool.h"
#include "attribs.h"
#include "file-prefix-map.h" /* remap_debug_filename() */
static void dwarf2out_source_line (unsigned int, 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);
static bool is_redundant_typedef (const_tree);
#ifndef XCOFF_DEBUGGING_INFO
#define XCOFF_DEBUGGING_INFO 0
#endif
#ifndef HAVE_XCOFF_DWARF_EXTRAS
#define HAVE_XCOFF_DWARF_EXTRAS 0
#endif
#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;
/* 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 const char *debug_macinfo_section_name;
static unsigned macinfo_label_base = 1;
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_line_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_ranges_dwo_section;
static GTY(()) section *debug_frame_section;
/* Maximum size (in bytes) of an artificially generated label. */
#define MAX_ARTIFICIAL_LABEL_BYTES 40
/* 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
#ifndef DWARF_INITIAL_LENGTH_SIZE_STR
#define DWARF_INITIAL_LENGTH_SIZE_STR (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_ptr_hash<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;
static GTY (()) hash_table<indirect_string_hasher> *debug_line_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 four forms: DW_FORM_string, DW_FORM_strp,
DW_FORM_line_strp or DW_FORM_strx/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;
/* The default cold text section. */
static GTY(()) section *cold_text_section;
/* True if currently in text section. */
static GTY(()) bool in_text_section_p = false;
/* Last debug-on location in corresponding section. */
static GTY(()) const char *last_text_label;
static GTY(()) const char *last_cold_label;
/* Mark debug-on/off locations per section.
NULL means the section is not used at all. */
static GTY(()) vec<const char *, va_gc> *switch_text_ranges;
static GTY(()) vec<const char *, va_gc> *switch_cold_ranges;
/* 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 void output_call_frame_info (int);
/* Personality decl of current unit. Used only when assembler does not support
personality CFI. */
static GTY(()) rtx current_unit_personality;
/* Whether an eh_frame section is required. */
static GTY(()) bool do_eh_frame = false;
/* .debug_rnglists next index. */
static unsigned int rnglist_idx;
/* 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_SECOND_SECT_LABEL
#define FUNC_SECOND_SECT_LABEL "LFSB"
#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. */
static unsigned int
get_full_len (const wide_int &op)
{
int prec = wi::get_precision (op);
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)
{
if (debug_info_level <= DINFO_LEVEL_TERSE)
return false;
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);
}
/* 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 ATTRIBUTE_UNUSED)
{
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;
#ifdef EH_FRAME_SECTION_NAME
eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
#else
eh_frame_section = ((flags == SECTION_WRITE)
? data_section : readonly_data_section);
#endif /* EH_FRAME_SECTION_NAME */
}
switch_to_section (eh_frame_section);
#ifdef EH_FRAME_THROUGH_COLLECT2
/* We have no special eh_frame section. Emit special labels to guide
collect2. */
if (!back)
{
tree 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));
}
#endif
}
/* 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:
case DW_CFA_val_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:
case DW_CFA_val_expression:
return dw_cfi_oprnd_loc;
case DW_CFA_def_cfa_expression:
return dw_cfi_oprnd_cfa_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[MAX_ARTIFICIAL_LABEL_BYTES], l2[MAX_ARTIFICIAL_LABEL_BYTES];
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 (!XCOFF_DEBUGGING_INFO || 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,
"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[MAX_ARTIFICIAL_LABEL_BYTES], l2[MAX_ARTIFICIAL_LABEL_BYTES];
char section_start_label[MAX_ARTIFICIAL_LABEL_BYTES];
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 (!XCOFF_DEBUGGING_INFO || 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;
fprintf (asm_out_file, "\t.cfi_startproc\n");
targetm.asm_out.post_cfi_startproc (asm_out_file, current_function_decl);
/* .cfi_personality and .cfi_lsda are only relevant to DWARF2
eh unwinders. */
if (targetm_common.except_unwind_info (&global_options) != UI_DWARF2)
return;
rtx personality = get_personality_function (current_function_decl);
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)
{
if (targetm.asm_out.make_eh_symbol_indirect != NULL)
ref = targetm.asm_out.make_eh_symbol_indirect (ref, true);
else
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[MAX_ARTIFICIAL_LABEL_BYTES];
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)
{
if (targetm.asm_out.make_eh_symbol_indirect != NULL)
ref = targetm.asm_out.make_eh_symbol_indirect (ref, true);
else
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,
unsigned int column 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 FDE allocation if we're not emitting frame unwind info. */
if (!do_frame)
return;
/* Unlike the debug version, the EH version of frame unwind info is a per-
function setting so we need to record whether we need it for the unit. */
do_eh_frame |= dwarf2out_do_eh_frame ();
/* 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));
fde->ignored_debug = DECL_IGNORED_P (current_function_decl);
in_text_section_p = fnsec == 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, column, 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);
}
/* Mark the ranges of non-debug subsections in the std text sections. */
static void
mark_ignored_debug_section (dw_fde_ref fde, bool second)
{
bool std_section;
const char *begin_label, *end_label;
const char **last_end_label;
vec<const char *, va_gc> **switch_ranges;
if (second)
{
std_section = fde->second_in_std_section;
begin_label = fde->dw_fde_second_begin;
end_label = fde->dw_fde_second_end;
}
else
{
std_section = fde->in_std_section;
begin_label = fde->dw_fde_begin;
end_label = fde->dw_fde_end;
}
if (!std_section)
return;
if (in_text_section_p)
{
last_end_label = &last_text_label;
switch_ranges = &switch_text_ranges;
}
else
{
last_end_label = &last_cold_label;
switch_ranges = &switch_cold_ranges;
}
if (fde->ignored_debug)
{
if (*switch_ranges && !(vec_safe_length (*switch_ranges) & 1))
vec_safe_push (*switch_ranges, *last_end_label);
}
else
{
*last_end_label = end_label;
if (!*switch_ranges)
vec_alloc (*switch_ranges, 16);
else if (vec_safe_length (*switch_ranges) & 1)
vec_safe_push (*switch_ranges, begin_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);
mark_ignored_debug_section (fde, fde->dw_fde_second_begin != NULL);
}
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 (do_eh_frame)
output_call_frame_info (1);
}
static void var_location_switch_text_section (void);
static void set_cur_line_info_table (section *);
void
dwarf2out_switch_text_section (void)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
section *sect;
dw_fde_ref fde = cfun->fde;
gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_SECOND_SECT_LABEL,
current_function_funcdef_no);
fde->dw_fde_second_begin = ggc_strdup (label);
if (!in_cold_section_p)
{
fde->dw_fde_end = crtl->subsections.cold_section_end_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_end = crtl->subsections.cold_section_end_label;
}
have_multiple_function_sections = true;
if (dwarf2out_do_cfi_asm ())
fprintf (asm_out_file, "\t.cfi_endproc\n");
mark_ignored_debug_section (fde, false);
/* 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));
in_text_section_p = sect == 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. */
/* Describe an entry into the .debug_addr section. */
enum ate_kind {
ate_kind_rtx,
ate_kind_rtx_dtprel,
ate_kind_label
};
struct GTY((for_user)) addr_table_entry {
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;
};
typedef unsigned int var_loc_view;
/* 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 */
addr_table_entry *end_entry;
char *ll_symbol; /* Label for beginning of location list.
Only on head of list. */
char *vl_symbol; /* Label for beginning of view list. Ditto. */
const char *section; /* Section this loclist is relative to */
dw_loc_descr_ref expr;
var_loc_view vbegin, vend;
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;
/* True if it has been emitted into .debug_loc* / .debug_loclists*
section. */
unsigned char emitted : 1;
/* True if hash field is index rather than hash value. */
unsigned char num_assigned : 1;
/* True if .debug_loclists.dwo offset has been emitted for it already. */
unsigned char offset_emitted : 1;
/* True if note_variable_value_in_expr has been called on it. */
unsigned char noted_variable_value : 1;
/* 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 (poly_int64);
static dw_loc_descr_ref uint_loc_descriptor (unsigned 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 TRUE iff we're to output location view lists as a separate
attribute next to the location lists, as an extension compatible
with DWARF 2 and above. */
static inline bool
dwarf2out_locviews_in_attribute ()
{
return debug_variable_location_views == 1;
}
/* Return TRUE iff we're to output location view lists as part of the
location lists, as proposed for standardization after DWARF 5. */
static inline bool
dwarf2out_locviews_in_loclist ()
{
#ifndef DW_LLE_view_pair
return false;
#else
return debug_variable_location_views == -1;
#endif
}
/* 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;
}
/* 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_unsigned_const_implicit:
case dw_val_class_const_implicit:
case dw_val_class_range_list:
/* 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_view_list:
return a->v.val_view_list == b->v.val_view_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_symview:
return strcmp (a->v.val_symbolic_view, b->v.val_symbolic_view) == 0;
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
case dw_val_class_loclistsptr:
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:
case dw_val_class_file_implicit:
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.lbl2, b->v.val_vms_delta.lbl2));
case dw_val_class_discr_value:
return (a->v.val_discr_value.pos == b->v.val_discr_value.pos
&& a->v.val_discr_value.v.uval == b->v.val_discr_value.v.uval);
case dw_val_class_discr_list:
/* It makes no sense comparing two discriminant value lists. */
return false;
}
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 POLY_OFFSET to a location expression. */
static void
loc_descr_plus_const (dw_loc_descr_ref *list_head, poly_int64 poly_offset)
{
dw_loc_descr_ref loc;
HOST_WIDE_INT *p;
gcc_assert (*list_head != NULL);
if (known_eq (poly_offset, 0))
return;
/* Find the end of the chain. */
for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next)
;
HOST_WIDE_INT offset;
if (!poly_offset.is_constant (&offset))
{
loc->dw_loc_next = int_loc_descriptor (poly_offset);
add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_plus, 0, 0));
return;
}
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
= uint_loc_descriptor (-(unsigned HOST_WIDE_INT) offset);
add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_minus, 0, 0));
}
}
/* 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, poly_int64 offset)
{
HOST_WIDE_INT const_offset;
if (offset.is_constant (&const_offset))
{
if (reg <= 31)
return new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + reg),
const_offset, 0);
else
return new_loc_descr (DW_OP_bregx, reg, const_offset);
}
else
{
dw_loc_descr_ref ret = new_reg_loc_descr (reg, 0);
loc_descr_plus_const (&ret, offset);
return ret;
}
}
/* Add a constant OFFSET to a location list. */
static void
loc_list_plus_const (dw_loc_list_ref list_head, poly_int64 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)
/* The number of bits that can be encoded by largest DW_FORM_dataN.
In DWARF4 and earlier it is DW_FORM_data8 with 64 bits, in DWARF5
DW_FORM_data16 with 128 bits. */
#define DWARF_LARGEST_DATA_FORM_BITS \
(dwarf_version >= 5 ? 128 : 64)
/* Utility inline function for construction of ops that were GNU extension
before DWARF 5. */
static inline enum dwarf_location_atom
dwarf_OP (enum dwarf_location_atom op)
{
switch (op)
{
case DW_OP_implicit_pointer:
if (dwarf_version < 5)
return DW_OP_GNU_implicit_pointer;
break;
case DW_OP_entry_value:
if (dwarf_version < 5)
return DW_OP_GNU_entry_value;
break;
case DW_OP_const_type:
if (dwarf_version < 5)
return DW_OP_GNU_const_type;
break;
case DW_OP_regval_type:
if (dwarf_version < 5)
return DW_OP_GNU_regval_type;
break;
case DW_OP_deref_type:
if (dwarf_version < 5)
return DW_OP_GNU_deref_type;
break;
case DW_OP_convert:
if (dwarf_version < 5)
return DW_OP_GNU_convert;
break;
case DW_OP_reinterpret:
if (dwarf_version < 5)
return DW_OP_GNU_reinterpret;
break;
case DW_OP_addrx:
if (dwarf_version < 5)
return DW_OP_GNU_addr_index;
break;
case DW_OP_constx:
if (dwarf_version < 5)
return DW_OP_GNU_const_index;
break;
default:
break;
}
return op;
}
/* Similarly for attributes. */
static inline enum dwarf_attribute
dwarf_AT (enum dwarf_attribute at)
{
switch (at)
{
case DW_AT_call_return_pc:
if (dwarf_version < 5)
return DW_AT_low_pc;
break;
case DW_AT_call_tail_call:
if (dwarf_version < 5)
return DW_AT_GNU_tail_call;
break;
case DW_AT_call_origin:
if (dwarf_version < 5)
return DW_AT_abstract_origin;
break;
case DW_AT_call_target:
if (dwarf_version < 5)
return DW_AT_GNU_call_site_target;
break;
case DW_AT_call_target_clobbered:
if (dwarf_version < 5)
return DW_AT_GNU_call_site_target_clobbered;
break;
case DW_AT_call_parameter:
if (dwarf_version < 5)
return DW_AT_abstract_origin;
break;
case DW_AT_call_value:
if (dwarf_version < 5)
return DW_AT_GNU_call_site_value;
break;
case DW_AT_call_data_value:
if (dwarf_version < 5)
return DW_AT_GNU_call_site_data_value;
break;
case DW_AT_call_all_calls:
if (dwarf_version < 5)
return DW_AT_GNU_all_call_sites;
break;
case DW_AT_call_all_tail_calls:
if (dwarf_version < 5)
return DW_AT_GNU_all_tail_call_sites;
break;
case DW_AT_dwo_name:
if (dwarf_version < 5)
return DW_AT_GNU_dwo_name;
break;
case DW_AT_addr_base:
if (dwarf_version < 5)
return DW_AT_GNU_addr_base;
break;
default:
break;
}
return at;
}
/* And similarly for tags. */
static inline enum dwarf_tag
dwarf_TAG (enum dwarf_tag tag)
{
switch (tag)
{
case DW_TAG_call_site:
if (dwarf_version < 5)
return DW_TAG_GNU_call_site;
break;
case DW_TAG_call_site_parameter:
if (dwarf_version < 5)
return DW_TAG_GNU_call_site_parameter;
break;
default:
break;
}
return tag;
}
/* And similarly for forms. */
static inline enum dwarf_form
dwarf_FORM (enum dwarf_form form)
{
switch (form)
{
case DW_FORM_addrx:
if (dwarf_version < 5)
return DW_FORM_GNU_addr_index;
break;
case DW_FORM_strx:
if (dwarf_version < 5)
return DW_FORM_GNU_str_index;
break;
default:
break;
}
return form;
}
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_addrx:
case DW_OP_GNU_const_index:
case DW_OP_constx:
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:
case DW_OP_GNU_variable_value:
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_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
break;
case DW_OP_entry_value:
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_const_type:
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_regval_type:
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_deref_type:
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_convert:
case DW_OP_reinterpret:
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;
}
/* Return the size of the value in a DW_AT_discr_value attribute. */
static int
size_of_discr_value (dw_discr_value *discr_value)
{
if (discr_value->pos)
return size_of_uleb128 (discr_value->v.uval);
else
return size_of_sleb128 (discr_value->v.sval);
}
/* Return the size of the value in a DW_AT_discr_list attribute. */
static int
size_of_discr_list (dw_discr_list_ref discr_list)
{
int size = 0;
for (dw_discr_list_ref list = discr_list;
list != NULL;
list = list->dw_discr_next)
{
/* One byte for the discriminant value descriptor, and then one or two
LEB128 numbers, depending on whether it's a single case label or a
range label. */
size += 1;
size += size_of_discr_value (&list->dw_discr_lower_bound);
if (list->dw_discr_range != 0)
size += size_of_discr_value (&list->dw_discr_upper_bound);
}
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 = (unsigned char *) 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_addrx:
case DW_OP_GNU_const_index:
case DW_OP_constx:
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_call2:
case DW_OP_call4:
{
unsigned long die_offset
= get_ref_die_offset (val1->v.val_die_ref.die);
/* Make sure the offset has been computed and that we can encode it as
an operand. */
gcc_assert (die_offset > 0
&& die_offset <= (loc->dw_loc_opc == DW_OP_call2
? 0xffff
: 0xffffffff));
dw2_asm_output_data ((loc->dw_loc_opc == DW_OP_call2) ? 2 : 4,
die_offset, NULL);
}
break;
case DW_OP_call_ref:
case DW_OP_GNU_variable_value:
{
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);
}
break;
case DW_OP_implicit_pointer:
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_entry_value:
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_const_type:
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 = (unsigned char *) 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_regval_type:
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_deref_type:
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_convert:
case DW_OP_reinterpret:
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_addrx:
case DW_OP_GNU_const_index:
case DW_OP_constx:
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_implicit_pointer:
case DW_OP_entry_value:
case DW_OP_const_type:
case DW_OP_regval_type:
case DW_OP_deref_type:
case DW_OP_convert:
case DW_OP_reinterpret:
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, poly_int64 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);
loc_descr_plus_const (&head, offset);
}
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,
poly_int64 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_early_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_set_ignored_loc (unsigned, unsigned, const char *);
static void dwarf2out_early_global_decl (tree);
static void dwarf2out_late_global_decl (tree);
static void dwarf2out_type_decl (tree, int);
static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool, bool);
static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
dw_die_ref);