|  | /* Output dbx-format symbol table information from GNU compiler. | 
|  | Copyright (C) 1987-2022 Free Software Foundation, Inc. | 
|  |  | 
|  | 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/>.  */ | 
|  |  | 
|  |  | 
|  | /* Output dbx-format symbol table data. | 
|  | This consists of many symbol table entries, each of them | 
|  | a .stabs assembler pseudo-op with four operands: | 
|  | a "name" which is really a description of one symbol and its type, | 
|  | a "code", which is a symbol defined in stab.h whose name starts with N_, | 
|  | an unused operand always 0, | 
|  | and a "value" which is an address or an offset. | 
|  | The name is enclosed in doublequote characters. | 
|  |  | 
|  | Each function, variable, typedef, and structure tag | 
|  | has a symbol table entry to define it. | 
|  | The beginning and end of each level of name scoping within | 
|  | a function are also marked by special symbol table entries. | 
|  |  | 
|  | The "name" consists of the symbol name, a colon, a kind-of-symbol letter, | 
|  | and a data type number.  The data type number may be followed by | 
|  | "=" and a type definition; normally this will happen the first time | 
|  | the type number is mentioned.  The type definition may refer to | 
|  | other types by number, and those type numbers may be followed | 
|  | by "=" and nested definitions. | 
|  |  | 
|  | This can make the "name" quite long. | 
|  | When a name is more than 80 characters, we split the .stabs pseudo-op | 
|  | into two .stabs pseudo-ops, both sharing the same "code" and "value". | 
|  | The first one is marked as continued with a double-backslash at the | 
|  | end of its "name". | 
|  |  | 
|  | The kind-of-symbol letter distinguished function names from global | 
|  | variables from file-scope variables from parameters from auto | 
|  | variables in memory from typedef names from register variables. | 
|  | See `dbxout_symbol'. | 
|  |  | 
|  | The "code" is mostly redundant with the kind-of-symbol letter | 
|  | that goes in the "name", but not entirely: for symbols located | 
|  | in static storage, the "code" says which segment the address is in, | 
|  | which controls how it is relocated. | 
|  |  | 
|  | The "value" for a symbol in static storage | 
|  | is the core address of the symbol (actually, the assembler | 
|  | label for the symbol).  For a symbol located in a stack slot | 
|  | it is the stack offset; for one in a register, the register number. | 
|  | For a typedef symbol, it is zero. | 
|  |  | 
|  | If DEBUG_SYMS_TEXT is defined, all debugging symbols must be | 
|  | output while in the text section. | 
|  |  | 
|  | For more on data type definitions, see `dbxout_type'.  */ | 
|  |  | 
|  | #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 "emit-rtl.h" | 
|  | #include "cgraph.h" | 
|  | #include "diagnostic-core.h" | 
|  | #include "fold-const.h" | 
|  | #include "varasm.h" | 
|  | #include "stor-layout.h" | 
|  | #include "reload.h" | 
|  | #include "output.h" | 
|  | #include "dbxout.h" | 
|  | #include "toplev.h" | 
|  | #include "debug.h" | 
|  | #include "common/common-target.h" | 
|  | #include "langhooks.h" | 
|  | #include "expr.h" | 
|  | #include "file-prefix-map.h" /* remap_debug_filename()  */ | 
|  | #include "flags.h" | 
|  |  | 
|  | #ifdef XCOFF_DEBUGGING_INFO | 
|  | #include "xcoffout.h" | 
|  | #endif | 
|  |  | 
|  | #ifndef ASM_STABS_OP | 
|  | # ifdef XCOFF_DEBUGGING_INFO | 
|  | #  define ASM_STABS_OP "\t.stabx\t" | 
|  | # else | 
|  | #  define ASM_STABS_OP "\t.stabs\t" | 
|  | # endif | 
|  | #endif | 
|  |  | 
|  | #ifndef ASM_STABN_OP | 
|  | #define ASM_STABN_OP "\t.stabn\t" | 
|  | #endif | 
|  |  | 
|  | #ifndef ASM_STABD_OP | 
|  | #define ASM_STABD_OP "\t.stabd\t" | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_TYPE_DECL_STABS_CODE | 
|  | #define DBX_TYPE_DECL_STABS_CODE N_LSYM | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_STATIC_CONST_VAR_CODE | 
|  | #define DBX_STATIC_CONST_VAR_CODE N_FUN | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_REGPARM_STABS_CODE | 
|  | #define DBX_REGPARM_STABS_CODE N_RSYM | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_REGPARM_STABS_LETTER | 
|  | #define DBX_REGPARM_STABS_LETTER 'P' | 
|  | #endif | 
|  |  | 
|  | #ifndef NO_DBX_FUNCTION_END | 
|  | #define NO_DBX_FUNCTION_END 0 | 
|  | #endif | 
|  |  | 
|  | #ifndef NO_DBX_BNSYM_ENSYM | 
|  | #define NO_DBX_BNSYM_ENSYM 0 | 
|  | #endif | 
|  |  | 
|  | #ifndef NO_DBX_MAIN_SOURCE_DIRECTORY | 
|  | #define NO_DBX_MAIN_SOURCE_DIRECTORY 0 | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_BLOCKS_FUNCTION_RELATIVE | 
|  | #define DBX_BLOCKS_FUNCTION_RELATIVE 0 | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_LINES_FUNCTION_RELATIVE | 
|  | #define DBX_LINES_FUNCTION_RELATIVE 0 | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_CONTIN_LENGTH | 
|  | #define DBX_CONTIN_LENGTH 80 | 
|  | #endif | 
|  |  | 
|  | #ifndef DBX_CONTIN_CHAR | 
|  | #define DBX_CONTIN_CHAR '\\' | 
|  | #endif | 
|  |  | 
|  | enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; | 
|  |  | 
|  | /* Structure recording information about a C data type. | 
|  | The status element says whether we have yet output | 
|  | the definition of the type.  TYPE_XREF says we have | 
|  | output it as a cross-reference only. | 
|  | The file_number and type_number elements are used if DBX_USE_BINCL | 
|  | is defined.  */ | 
|  |  | 
|  | struct GTY(()) typeinfo { | 
|  | enum typestatus status; | 
|  | int file_number; | 
|  | int type_number; | 
|  | }; | 
|  |  | 
|  | /* Vector recording information about C data types. | 
|  | When we first notice a data type (a tree node), | 
|  | we assign it a number using next_type_number. | 
|  | That is its index in this vector.  */ | 
|  |  | 
|  | static GTY ((length ("typevec_len"))) struct typeinfo *typevec; | 
|  |  | 
|  | /* Number of elements of space allocated in `typevec'.  */ | 
|  |  | 
|  | static GTY(()) int typevec_len; | 
|  |  | 
|  | /* In dbx output, each type gets a unique number. | 
|  | This is the number for the next type output. | 
|  | The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field.  */ | 
|  |  | 
|  | static GTY(()) int next_type_number; | 
|  |  | 
|  | /* The C front end may call dbxout_symbol before dbxout_init runs. | 
|  | We save all such decls in this list and output them when we get | 
|  | to dbxout_init.  */ | 
|  |  | 
|  | static GTY(()) tree preinit_symbols; | 
|  |  | 
|  | enum binclstatus {BINCL_NOT_REQUIRED, BINCL_PENDING, BINCL_PROCESSED}; | 
|  |  | 
|  | /* When using N_BINCL in dbx output, each type number is actually a | 
|  | pair of the file number and the type number within the file. | 
|  | This is a stack of input files.  */ | 
|  |  | 
|  | struct dbx_file | 
|  | { | 
|  | struct dbx_file *next; | 
|  | int file_number; | 
|  | int next_type_number; | 
|  | enum binclstatus bincl_status;  /* Keep track of lazy bincl.  */ | 
|  | const char *pending_bincl_name; /* Name of bincl.  */ | 
|  | struct dbx_file *prev;          /* Chain to traverse all pending bincls.  */ | 
|  | }; | 
|  |  | 
|  | /* This is the top of the stack. | 
|  |  | 
|  | This is not saved for PCH, because restoring a PCH should not change it. | 
|  | next_file_number does have to be saved, because the PCH may use some | 
|  | file numbers; however, just before restoring a PCH, next_file_number | 
|  | should always be 0 because we should not have needed any file numbers | 
|  | yet.  */ | 
|  |  | 
|  | #if (defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)) \ | 
|  | && defined (DBX_USE_BINCL) | 
|  | static struct dbx_file *current_file; | 
|  | #endif | 
|  |  | 
|  | /* This is the next file number to use.  */ | 
|  |  | 
|  | static GTY(()) int next_file_number; | 
|  |  | 
|  | /* A counter for dbxout_function_end.  */ | 
|  |  | 
|  | static GTY(()) int scope_labelno; | 
|  |  | 
|  | /* A counter for dbxout_source_line.  */ | 
|  |  | 
|  | static GTY(()) int dbxout_source_line_counter; | 
|  |  | 
|  | /* Number for the next N_SOL filename stabs label.  The number 0 is reserved | 
|  | for the N_SO filename stabs label.  */ | 
|  |  | 
|  | static GTY(()) int source_label_number = 1; | 
|  |  | 
|  | /* Last source file name mentioned in a NOTE insn.  */ | 
|  |  | 
|  | static GTY(()) const char *lastfile; | 
|  |  | 
|  | /* Last line number mentioned in a NOTE insn.  */ | 
|  |  | 
|  | static GTY(()) unsigned int lastlineno; | 
|  |  | 
|  | /* Used by PCH machinery to detect if 'lastfile' should be reset to | 
|  | base_input_file.  */ | 
|  | static GTY(()) int lastfile_is_base; | 
|  |  | 
|  | /* Typical USG systems don't have stab.h, and they also have | 
|  | no use for DBX-format debugging info.  */ | 
|  |  | 
|  | #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) | 
|  |  | 
|  | #ifdef DBX_USE_BINCL | 
|  | /* If zero then there is no pending BINCL.  */ | 
|  | static int pending_bincls = 0; | 
|  | #endif | 
|  |  | 
|  | /* The original input file name.  */ | 
|  | static const char *base_input_file; | 
|  |  | 
|  | #ifdef DEBUG_SYMS_TEXT | 
|  | #define FORCE_TEXT switch_to_section (current_function_section ()) | 
|  | #else | 
|  | #define FORCE_TEXT | 
|  | #endif | 
|  |  | 
|  | #include "gstab.h" | 
|  |  | 
|  | /* 1 if PARM is passed to this function in memory.  */ | 
|  |  | 
|  | #define PARM_PASSED_IN_MEMORY(PARM) \ | 
|  | (MEM_P (DECL_INCOMING_RTL (PARM))) | 
|  |  | 
|  | /* A C expression for the integer offset value of an automatic variable | 
|  | (N_LSYM) having address X (an RTX).  */ | 
|  | #ifndef DEBUGGER_AUTO_OFFSET | 
|  | #define DEBUGGER_AUTO_OFFSET(X) \ | 
|  | (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) | 
|  | #endif | 
|  |  | 
|  | /* A C expression for the integer offset value of an argument (N_PSYM) | 
|  | having address X (an RTX).  The nominal offset is OFFSET. | 
|  | Note that we use OFFSET + 0 here to avoid the self-assign warning | 
|  | when the macro is called in a context like | 
|  | number = DEBUGGER_ARG_OFFSET(number, X)  */ | 
|  | #ifndef DEBUGGER_ARG_OFFSET | 
|  | #define DEBUGGER_ARG_OFFSET(OFFSET, X) (OFFSET + 0) | 
|  | #endif | 
|  |  | 
|  | /* This obstack holds the stab string currently being constructed.  We | 
|  | build it up here, then write it out, so we can split long lines up | 
|  | properly (see dbxout_finish_complex_stabs).  */ | 
|  | static struct obstack stabstr_ob; | 
|  | static size_t stabstr_last_contin_point; | 
|  |  | 
|  | #ifdef DBX_USE_BINCL | 
|  | static void emit_bincl_stab             (const char *c); | 
|  | static void emit_pending_bincls         (void); | 
|  | #endif | 
|  | static inline void emit_pending_bincls_if_required (void); | 
|  |  | 
|  | static void dbxout_init (const char *); | 
|  |  | 
|  | static void dbxout_finish (const char *); | 
|  | static void dbxout_start_source_file (unsigned, const char *); | 
|  | static void dbxout_end_source_file (unsigned); | 
|  | static void dbxout_typedefs (tree); | 
|  | static void dbxout_type_index (tree); | 
|  | static void dbxout_args (tree); | 
|  | static void dbxout_type_fields (tree); | 
|  | static void dbxout_type_method_1 (tree); | 
|  | static void dbxout_type_methods (tree); | 
|  | static void dbxout_range_type (tree, tree, tree); | 
|  | static void dbxout_type (tree, int); | 
|  | static bool print_int_cst_bounds_in_octal_p (tree, tree, tree); | 
|  | static bool is_fortran (void); | 
|  | static void dbxout_type_name (tree); | 
|  | static void dbxout_class_name_qualifiers (tree); | 
|  | static int dbxout_symbol_location (tree, tree, const char *, rtx); | 
|  | static void dbxout_symbol_name (tree, const char *, int); | 
|  | static void dbxout_common_name (tree, const char *, stab_code_type); | 
|  | static const char *dbxout_common_check (tree, int *); | 
|  | static void dbxout_early_global_decl (tree); | 
|  | static void dbxout_late_global_decl (tree); | 
|  | static void dbxout_type_decl (tree, int); | 
|  | static void dbxout_handle_pch (unsigned); | 
|  | static void debug_free_queue (void); | 
|  |  | 
|  | /* The debug hooks structure.  */ | 
|  | #if defined (DBX_DEBUGGING_INFO) | 
|  |  | 
|  | static void dbxout_source_line (unsigned int, unsigned int, const char *, | 
|  | int, bool); | 
|  | static void dbxout_switch_text_section (void); | 
|  | static void dbxout_begin_prologue (unsigned int, unsigned int, const char *); | 
|  | static void dbxout_source_file (const char *); | 
|  | static void dbxout_function_end (tree); | 
|  | static void dbxout_begin_function (tree); | 
|  | static void dbxout_begin_block (unsigned, unsigned); | 
|  | static void dbxout_end_block (unsigned, unsigned); | 
|  | static void dbxout_function_decl (tree); | 
|  |  | 
|  | const struct gcc_debug_hooks dbx_debug_hooks = | 
|  | { | 
|  | dbxout_init, | 
|  | dbxout_finish, | 
|  | debug_nothing_charstar, | 
|  | debug_nothing_void, | 
|  | debug_nothing_int_charstar, | 
|  | debug_nothing_int_charstar, | 
|  | dbxout_start_source_file, | 
|  | dbxout_end_source_file, | 
|  | dbxout_begin_block, | 
|  | dbxout_end_block, | 
|  | debug_true_const_tree,	         /* ignore_block */ | 
|  | dbxout_source_line,		         /* source_line */ | 
|  | debug_nothing_int_int_charstar,	 /* set_ignored_loc */ | 
|  | dbxout_begin_prologue,	         /* begin_prologue */ | 
|  | debug_nothing_int_charstar,	         /* end_prologue */ | 
|  | debug_nothing_int_charstar,	         /* begin_epilogue */ | 
|  | debug_nothing_int_charstar,	         /* end_epilogue */ | 
|  | #ifdef DBX_FUNCTION_FIRST | 
|  | dbxout_begin_function, | 
|  | #else | 
|  | debug_nothing_tree,		         /* begin_function */ | 
|  | #endif | 
|  | debug_nothing_int,		         /* end_function */ | 
|  | debug_nothing_tree,			 /* register_main_translation_unit */ | 
|  | dbxout_function_decl, | 
|  | dbxout_early_global_decl,		 /* early_global_decl */ | 
|  | dbxout_late_global_decl,		 /* late_global_decl */ | 
|  | dbxout_type_decl,			 /* type_decl */ | 
|  | debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ | 
|  | debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */ | 
|  | debug_nothing_tree_charstar_uhwi,      /* register_external_die */ | 
|  | debug_nothing_tree,		         /* deferred_inline_function */ | 
|  | debug_nothing_tree,		         /* outlining_inline_function */ | 
|  | debug_nothing_rtx_code_label,	         /* label */ | 
|  | dbxout_handle_pch,		         /* handle_pch */ | 
|  | debug_nothing_rtx_insn,	         /* var_location */ | 
|  | debug_nothing_tree,	         	 /* inline_entry */ | 
|  | debug_nothing_tree,			 /* size_function */ | 
|  | dbxout_switch_text_section,            /* switch_text_section */ | 
|  | debug_nothing_tree_tree,		 /* set_name */ | 
|  | 0,                                     /* start_end_main_source_file */ | 
|  | TYPE_SYMTAB_IS_ADDRESS                 /* tree_type_symtab_field */ | 
|  | }; | 
|  | #endif /* DBX_DEBUGGING_INFO  */ | 
|  |  | 
|  | #if defined (XCOFF_DEBUGGING_INFO) | 
|  | const struct gcc_debug_hooks xcoff_debug_hooks = | 
|  | { | 
|  | dbxout_init, | 
|  | dbxout_finish, | 
|  | debug_nothing_charstar, | 
|  | debug_nothing_void, | 
|  | debug_nothing_int_charstar, | 
|  | debug_nothing_int_charstar, | 
|  | dbxout_start_source_file, | 
|  | dbxout_end_source_file, | 
|  | xcoffout_begin_block, | 
|  | xcoffout_end_block, | 
|  | debug_true_const_tree,	         /* ignore_block */ | 
|  | xcoffout_source_line, | 
|  | debug_nothing_int_int_charstar,	 /* set_ignored_loc */ | 
|  | xcoffout_begin_prologue,	         /* begin_prologue */ | 
|  | debug_nothing_int_charstar,	         /* end_prologue */ | 
|  | debug_nothing_int_charstar,	         /* begin_epilogue */ | 
|  | xcoffout_end_epilogue, | 
|  | debug_nothing_tree,		         /* begin_function */ | 
|  | xcoffout_end_function, | 
|  | debug_nothing_tree,			 /* register_main_translation_unit */ | 
|  | debug_nothing_tree,		         /* function_decl */ | 
|  | dbxout_early_global_decl,		 /* early_global_decl */ | 
|  | dbxout_late_global_decl,		 /* late_global_decl */ | 
|  | dbxout_type_decl,			 /* type_decl */ | 
|  | debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */ | 
|  | debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */ | 
|  | debug_nothing_tree_charstar_uhwi,      /* register_external_die */ | 
|  | debug_nothing_tree,		         /* deferred_inline_function */ | 
|  | debug_nothing_tree,		         /* outlining_inline_function */ | 
|  | debug_nothing_rtx_code_label,	         /* label */ | 
|  | dbxout_handle_pch,		         /* handle_pch */ | 
|  | debug_nothing_rtx_insn,	         /* var_location */ | 
|  | debug_nothing_tree,	         	 /* inline_entry */ | 
|  | debug_nothing_tree,			 /* size_function */ | 
|  | debug_nothing_void,                    /* switch_text_section */ | 
|  | debug_nothing_tree_tree,	         /* set_name */ | 
|  | 0,                                     /* start_end_main_source_file */ | 
|  | TYPE_SYMTAB_IS_ADDRESS                 /* tree_type_symtab_field */ | 
|  | }; | 
|  | #endif /* XCOFF_DEBUGGING_INFO  */ | 
|  |  | 
|  | /* Numeric formatting helper macro.  Note that this does not handle | 
|  | hexadecimal.  */ | 
|  | #define NUMBER_FMT_LOOP(P, NUM, BASE)		\ | 
|  | do						\ | 
|  | {						\ | 
|  | int digit = NUM % BASE;			\ | 
|  | NUM /= BASE;				\ | 
|  | *--P = digit + '0';			\ | 
|  | }						\ | 
|  | while (NUM > 0) | 
|  |  | 
|  | /* Utility: write a decimal integer NUM to asm_out_file.  */ | 
|  | void | 
|  | dbxout_int (int num) | 
|  | { | 
|  | char buf[64]; | 
|  | char *p = buf + sizeof buf; | 
|  | unsigned int unum; | 
|  |  | 
|  | if (num == 0) | 
|  | { | 
|  | putc ('0', asm_out_file); | 
|  | return; | 
|  | } | 
|  | if (num < 0) | 
|  | { | 
|  | putc ('-', asm_out_file); | 
|  | unum = -(unsigned int) num; | 
|  | } | 
|  | else | 
|  | unum = num; | 
|  |  | 
|  | NUMBER_FMT_LOOP (p, unum, 10); | 
|  |  | 
|  | while (p < buf + sizeof buf) | 
|  | { | 
|  | putc (*p, asm_out_file); | 
|  | p++; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Primitives for emitting simple stabs directives.  All other stabs | 
|  | routines should use these functions instead of directly emitting | 
|  | stabs.  They are exported because machine-dependent code may need | 
|  | to invoke them, e.g. in a DBX_OUTPUT_* macro whose definition | 
|  | forwards to code in CPU.c.  */ | 
|  |  | 
|  | /* The following functions should all be called immediately after one | 
|  | of the dbxout_begin_stab* functions (below).  They write out | 
|  | various things as the value of a stab.  */ | 
|  |  | 
|  | /* Write out a literal zero as the value of a stab.  */ | 
|  | void | 
|  | dbxout_stab_value_zero (void) | 
|  | { | 
|  | fputs ("0\n", asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Write out the label LABEL as the value of a stab.  */ | 
|  | void | 
|  | dbxout_stab_value_label (const char *label) | 
|  | { | 
|  | assemble_name (asm_out_file, label); | 
|  | putc ('\n', asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Write out the difference of two labels, LABEL - BASE, as the value | 
|  | of a stab.  */ | 
|  | void | 
|  | dbxout_stab_value_label_diff (const char *label, const char *base) | 
|  | { | 
|  | assemble_name (asm_out_file, label); | 
|  | putc ('-', asm_out_file); | 
|  | assemble_name (asm_out_file, base); | 
|  | putc ('\n', asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Write out an internal label as the value of a stab, and immediately | 
|  | emit that internal label.  This should be used only when | 
|  | dbxout_stabd will not work.  STEM is the name stem of the label, | 
|  | COUNTERP is a pointer to a counter variable which will be used to | 
|  | guarantee label uniqueness.  */ | 
|  | void | 
|  | dbxout_stab_value_internal_label (const char *stem, int *counterp) | 
|  | { | 
|  | char label[100]; | 
|  | int counter = counterp ? (*counterp)++ : 0; | 
|  |  | 
|  | ASM_GENERATE_INTERNAL_LABEL (label, stem, counter); | 
|  | dbxout_stab_value_label (label); | 
|  | targetm.asm_out.internal_label (asm_out_file, stem, counter); | 
|  | } | 
|  |  | 
|  | /* Write out the difference between BASE and an internal label as the | 
|  | value of a stab, and immediately emit that internal label.  STEM and | 
|  | COUNTERP are as for dbxout_stab_value_internal_label.  */ | 
|  | void | 
|  | dbxout_stab_value_internal_label_diff (const char *stem, int *counterp, | 
|  | const char *base) | 
|  | { | 
|  | char label[100]; | 
|  | int counter = counterp ? (*counterp)++ : 0; | 
|  |  | 
|  | ASM_GENERATE_INTERNAL_LABEL (label, stem, counter); | 
|  | dbxout_stab_value_label_diff (label, base); | 
|  | targetm.asm_out.internal_label (asm_out_file, stem, counter); | 
|  | } | 
|  |  | 
|  | /* The following functions produce specific kinds of stab directives.  */ | 
|  |  | 
|  | /* Write a .stabd directive with type STYPE and desc SDESC to asm_out_file.  */ | 
|  | void | 
|  | dbxout_stabd (int stype, int sdesc) | 
|  | { | 
|  | fputs (ASM_STABD_OP, asm_out_file); | 
|  | dbxout_int (stype); | 
|  | fputs (",0,", asm_out_file); | 
|  | dbxout_int (sdesc); | 
|  | putc ('\n', asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Write a .stabn directive with type STYPE.  This function stops | 
|  | short of emitting the value field, which is the responsibility of | 
|  | the caller (normally it will be either a symbol or the difference | 
|  | of two symbols).  */ | 
|  |  | 
|  | void | 
|  | dbxout_begin_stabn (int stype) | 
|  | { | 
|  | fputs (ASM_STABN_OP, asm_out_file); | 
|  | dbxout_int (stype); | 
|  | fputs (",0,0,", asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Write a .stabn directive with type N_SLINE and desc LINE.  As above, | 
|  | the value field is the responsibility of the caller.  */ | 
|  | void | 
|  | dbxout_begin_stabn_sline (int lineno) | 
|  | { | 
|  | fputs (ASM_STABN_OP, asm_out_file); | 
|  | dbxout_int (N_SLINE); | 
|  | fputs (",0,", asm_out_file); | 
|  | dbxout_int (lineno); | 
|  | putc (',', asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Begin a .stabs directive with string "", type STYPE, and desc and | 
|  | other fields 0.  The value field is the responsibility of the | 
|  | caller.  This function cannot be used for .stabx directives.  */ | 
|  | void | 
|  | dbxout_begin_empty_stabs (int stype) | 
|  | { | 
|  | fputs (ASM_STABS_OP, asm_out_file); | 
|  | fputs ("\"\",", asm_out_file); | 
|  | dbxout_int (stype); | 
|  | fputs (",0,0,", asm_out_file); | 
|  | } | 
|  |  | 
|  | /* Begin a .stabs directive with string STR, type STYPE, and desc 0. | 
|  | The value field is the responsibility of the caller.  */ | 
|  | void | 
|  | dbxout_begin_simple_stabs (const char *str, int stype) | 
|  | { | 
|  | fputs (ASM_STABS_OP, asm_out_file); | 
|  | output_quoted_string (asm_out_file, str); | 
|  | putc (',', asm_out_file); | 
|  | dbxout_int (stype); | 
|  | fputs (",0,0,", asm_out_file); | 
|  | } | 
|  |  | 
|  | /* As above but use SDESC for the desc field.  */ | 
|  | void | 
|  | dbxout_begin_simple_stabs_desc (const char *str, int stype, int sdesc) | 
|  | { | 
|  | fputs (ASM_STABS_OP, asm_out_file); | 
|  | output_quoted_string (asm_out_file, str); | 
|  | putc (',', asm_out_file); | 
|  | dbxout_int (stype); | 
|  | fputs (",0,", asm_out_file); | 
|  | dbxout_int (sdesc); | 
|  | putc (',', asm_out_file); | 
|  | } | 
|  |  | 
|  | /* The next set of functions are entirely concerned with production of | 
|  | "complex" .stabs directives: that is, .stabs directives whose | 
|  | strings have to be constructed piecemeal.  dbxout_type, | 
|  | dbxout_symbol, etc. use these routines heavily.  The string is queued | 
|  | up in an obstack, then written out by dbxout_finish_complex_stabs, which | 
|  | is also responsible for splitting it up if it exceeds DBX_CONTIN_LENGTH. | 
|  | (You might think it would be more efficient to go straight to stdio | 
|  | when DBX_CONTIN_LENGTH is 0 (i.e. no length limit) but that turns | 
|  | out not to be the case, and anyway this needs fewer #ifdefs.)  */ | 
|  |  | 
|  | /* Begin a complex .stabs directive.  If we can, write the initial | 
|  | ASM_STABS_OP to the asm_out_file.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_begin_complex_stabs (void) | 
|  | { | 
|  | emit_pending_bincls_if_required (); | 
|  | FORCE_TEXT; | 
|  | fputs (ASM_STABS_OP, asm_out_file); | 
|  | putc ('"', asm_out_file); | 
|  | gcc_assert (stabstr_last_contin_point == 0); | 
|  | } | 
|  |  | 
|  | /* As above, but do not force text or emit pending bincls.  This is | 
|  | used by dbxout_symbol_location, which needs to do something else.  */ | 
|  | static void | 
|  | dbxout_begin_complex_stabs_noforcetext (void) | 
|  | { | 
|  | fputs (ASM_STABS_OP, asm_out_file); | 
|  | putc ('"', asm_out_file); | 
|  | gcc_assert (stabstr_last_contin_point == 0); | 
|  | } | 
|  |  | 
|  | /* Add CHR, a single character, to the string being built.  */ | 
|  | #define stabstr_C(chr) obstack_1grow (&stabstr_ob, chr) | 
|  |  | 
|  | /* Add STR, a normal C string, to the string being built.  */ | 
|  | #define stabstr_S(str) obstack_grow (&stabstr_ob, str, strlen (str)) | 
|  |  | 
|  | /* Add the text of ID, an IDENTIFIER_NODE, to the string being built.  */ | 
|  | #define stabstr_I(id) obstack_grow (&stabstr_ob, \ | 
|  | IDENTIFIER_POINTER (id), \ | 
|  | IDENTIFIER_LENGTH (id)) | 
|  |  | 
|  | /* Add NUM, a signed decimal number, to the string being built.  */ | 
|  | static void | 
|  | stabstr_D (HOST_WIDE_INT num) | 
|  | { | 
|  | char buf[64]; | 
|  | char *p = buf + sizeof buf; | 
|  | unsigned HOST_WIDE_INT unum; | 
|  |  | 
|  | if (num == 0) | 
|  | { | 
|  | stabstr_C ('0'); | 
|  | return; | 
|  | } | 
|  | if (num < 0) | 
|  | { | 
|  | stabstr_C ('-'); | 
|  | unum = -(unsigned HOST_WIDE_INT) num; | 
|  | } | 
|  | else | 
|  | unum = num; | 
|  |  | 
|  | NUMBER_FMT_LOOP (p, unum, 10); | 
|  |  | 
|  | obstack_grow (&stabstr_ob, p, (buf + sizeof buf) - p); | 
|  | } | 
|  |  | 
|  | /* Add NUM, an unsigned decimal number, to the string being built.  */ | 
|  | static void | 
|  | stabstr_U (unsigned HOST_WIDE_INT num) | 
|  | { | 
|  | char buf[64]; | 
|  | char *p = buf + sizeof buf; | 
|  | if (num == 0) | 
|  | { | 
|  | stabstr_C ('0'); | 
|  | return; | 
|  | } | 
|  | NUMBER_FMT_LOOP (p, num, 10); | 
|  | obstack_grow (&stabstr_ob, p, (buf + sizeof buf) - p); | 
|  | } | 
|  |  | 
|  | /* Add CST, an INTEGER_CST tree, to the string being built as an | 
|  | unsigned octal number.  This routine handles values which are | 
|  | larger than a single HOST_WIDE_INT.  */ | 
|  | static void | 
|  | stabstr_O (tree cst) | 
|  | { | 
|  | int prec = TYPE_PRECISION (TREE_TYPE (cst)); | 
|  | int res_pres = prec % 3; | 
|  | int i; | 
|  | unsigned int digit; | 
|  |  | 
|  | /* Leading zero for base indicator.  */ | 
|  | stabstr_C ('0'); | 
|  |  | 
|  | /* If the value is zero, the base indicator will serve as the value | 
|  | all by itself.  */ | 
|  | if (wi::to_wide (cst) == 0) | 
|  | return; | 
|  |  | 
|  | /* GDB wants constants with no extra leading "1" bits, so | 
|  | we need to remove any sign-extension that might be | 
|  | present.  */ | 
|  | if (res_pres == 1) | 
|  | { | 
|  | digit = wi::extract_uhwi (wi::to_wide (cst), prec - 1, 1); | 
|  | stabstr_C ('0' + digit); | 
|  | } | 
|  | else if (res_pres == 2) | 
|  | { | 
|  | digit = wi::extract_uhwi (wi::to_wide (cst), prec - 2, 2); | 
|  | stabstr_C ('0' + digit); | 
|  | } | 
|  |  | 
|  | prec -= res_pres; | 
|  | for (i = prec - 3; i >= 0; i = i - 3) | 
|  | { | 
|  | digit = wi::extract_uhwi (wi::to_wide (cst), i, 3); | 
|  | stabstr_C ('0' + digit); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Called whenever it is safe to break a stabs string into multiple | 
|  | .stabs directives.  If the current string has exceeded the limit | 
|  | set by DBX_CONTIN_LENGTH, mark the current position in the buffer | 
|  | as a continuation point by inserting DBX_CONTIN_CHAR (doubled if | 
|  | it is a backslash) and a null character.  */ | 
|  | static inline void | 
|  | stabstr_continue (void) | 
|  | { | 
|  | if (DBX_CONTIN_LENGTH > 0 | 
|  | && obstack_object_size (&stabstr_ob) - stabstr_last_contin_point | 
|  | > DBX_CONTIN_LENGTH) | 
|  | { | 
|  | if (DBX_CONTIN_CHAR == '\\') | 
|  | obstack_1grow (&stabstr_ob, '\\'); | 
|  | obstack_1grow (&stabstr_ob, DBX_CONTIN_CHAR); | 
|  | obstack_1grow (&stabstr_ob, '\0'); | 
|  | stabstr_last_contin_point = obstack_object_size (&stabstr_ob); | 
|  | } | 
|  | } | 
|  | #define CONTIN stabstr_continue () | 
|  |  | 
|  | /* Macro subroutine of dbxout_finish_complex_stabs, which emits | 
|  | all of the arguments to the .stabs directive after the string. | 
|  | Overridden by xcoffout.h.  CODE is the stabs code for this symbol; | 
|  | LINE is the source line to write into the desc field (in extended | 
|  | mode); SYM is the symbol itself. | 
|  |  | 
|  | ADDR, LABEL, and NUMBER are three different ways to represent the | 
|  | stabs value field.  At most one of these should be nonzero. | 
|  |  | 
|  | ADDR is used most of the time; it represents the value as an | 
|  | RTL address constant. | 
|  |  | 
|  | LABEL is used (currently) only for N_CATCH stabs; it represents | 
|  | the value as a string suitable for assemble_name. | 
|  |  | 
|  | NUMBER is used when the value is an offset from an implicit base | 
|  | pointer (e.g. for a stack variable), or an index (e.g. for a | 
|  | register variable).  It represents the value as a decimal integer.  */ | 
|  |  | 
|  | #ifndef DBX_FINISH_STABS | 
|  | #define DBX_FINISH_STABS(SYM, CODE, LINE, ADDR, LABEL, NUMBER)	\ | 
|  | do {								\ | 
|  | int line_ = use_gnu_debug_info_extensions ? LINE : 0;		\ | 
|  | \ | 
|  | dbxout_int (CODE);						\ | 
|  | fputs (",0,", asm_out_file);					\ | 
|  | dbxout_int (line_);						\ | 
|  | putc (',', asm_out_file);					\ | 
|  | if (ADDR)							\ | 
|  | output_addr_const (asm_out_file, ADDR);			\ | 
|  | else if (LABEL)						\ | 
|  | assemble_name (asm_out_file, LABEL);			\ | 
|  | else								\ | 
|  | dbxout_int (NUMBER);					\ | 
|  | putc ('\n', asm_out_file);					\ | 
|  | } while (0) | 
|  | #endif | 
|  |  | 
|  | /* Finish the emission of a complex .stabs directive.  When DBX_CONTIN_LENGTH | 
|  | is zero, this has only to emit the close quote and the remainder of | 
|  | the arguments.  When it is nonzero, the string has been marshalled in | 
|  | stabstr_ob, and this routine is responsible for breaking it up into | 
|  | DBX_CONTIN_LENGTH-sized chunks. | 
|  |  | 
|  | SYM is the DECL of the symbol under consideration; it is used only | 
|  | for its DECL_SOURCE_LINE.  The other arguments are all passed directly | 
|  | to DBX_FINISH_STABS; see above for details.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_finish_complex_stabs (tree sym, stab_code_type code, | 
|  | rtx addr, const char *label, int number) | 
|  | { | 
|  | int line ATTRIBUTE_UNUSED; | 
|  | char *str; | 
|  | size_t len; | 
|  |  | 
|  | line = sym ? DECL_SOURCE_LINE (sym) : 0; | 
|  | if (DBX_CONTIN_LENGTH > 0) | 
|  | { | 
|  | char *chunk; | 
|  | size_t chunklen; | 
|  |  | 
|  | /* Nul-terminate the growing string, then get its size and | 
|  | address.  */ | 
|  | obstack_1grow (&stabstr_ob, '\0'); | 
|  |  | 
|  | len = obstack_object_size (&stabstr_ob); | 
|  | chunk = str = XOBFINISH (&stabstr_ob, char *); | 
|  |  | 
|  | /* Within the buffer are a sequence of NUL-separated strings, | 
|  | each of which is to be written out as a separate stab | 
|  | directive.  */ | 
|  | for (;;) | 
|  | { | 
|  | chunklen = strlen (chunk); | 
|  | fwrite (chunk, 1, chunklen, asm_out_file); | 
|  | fputs ("\",", asm_out_file); | 
|  |  | 
|  | /* Must add an extra byte to account for the NUL separator.  */ | 
|  | chunk += chunklen + 1; | 
|  | len   -= chunklen + 1; | 
|  |  | 
|  | /* Only put a line number on the last stab in the sequence.  */ | 
|  | DBX_FINISH_STABS (sym, code, len == 0 ? line : 0, | 
|  | addr, label, number); | 
|  | if (len == 0) | 
|  | break; | 
|  |  | 
|  | fputs (ASM_STABS_OP, asm_out_file); | 
|  | putc ('"', asm_out_file); | 
|  | } | 
|  | stabstr_last_contin_point = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* No continuations - we can put the whole string out at once. | 
|  | It is faster to augment the string with the close quote and | 
|  | comma than to do a two-character fputs.  */ | 
|  | obstack_grow (&stabstr_ob, "\",", 2); | 
|  | len = obstack_object_size (&stabstr_ob); | 
|  | str = XOBFINISH (&stabstr_ob, char *); | 
|  |  | 
|  | fwrite (str, 1, len, asm_out_file); | 
|  | DBX_FINISH_STABS (sym, code, line, addr, label, number); | 
|  | } | 
|  | obstack_free (&stabstr_ob, str); | 
|  | } | 
|  |  | 
|  | #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) | 
|  |  | 
|  | /* When -gused is used, emit debug info for only used symbols. But in | 
|  | addition to the standard intercepted debug_hooks there are some | 
|  | direct calls into this file, i.e., dbxout_symbol, dbxout_parms, and | 
|  | dbxout_reg_params.  Those routines may also be called from a higher | 
|  | level intercepted routine. So to prevent recording data for an inner | 
|  | call to one of these for an intercept, we maintain an intercept | 
|  | nesting counter (debug_nesting). We only save the intercepted | 
|  | arguments if the nesting is 1.  */ | 
|  | static int debug_nesting = 0; | 
|  |  | 
|  | static tree *symbol_queue; | 
|  | static int symbol_queue_index = 0; | 
|  | static int symbol_queue_size = 0; | 
|  |  | 
|  | #define DBXOUT_DECR_NESTING \ | 
|  | if (--debug_nesting == 0 && symbol_queue_index > 0) \ | 
|  | { emit_pending_bincls_if_required (); debug_flush_symbol_queue (); } | 
|  |  | 
|  | #define DBXOUT_DECR_NESTING_AND_RETURN(x) \ | 
|  | do {--debug_nesting; return (x);} while (0) | 
|  |  | 
|  | #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ | 
|  |  | 
|  | #if defined (DBX_DEBUGGING_INFO) | 
|  |  | 
|  | static void | 
|  | dbxout_function_end (tree decl ATTRIBUTE_UNUSED) | 
|  | { | 
|  | char lscope_label_name[100]; | 
|  |  | 
|  | /* The Lscope label must be emitted even if we aren't doing anything | 
|  | else; dbxout_block needs it.  */ | 
|  | switch_to_section (current_function_section ()); | 
|  |  | 
|  | /* Convert Lscope into the appropriate format for local labels in case | 
|  | the system doesn't insert underscores in front of user generated | 
|  | labels.  */ | 
|  | ASM_GENERATE_INTERNAL_LABEL (lscope_label_name, "Lscope", scope_labelno); | 
|  | targetm.asm_out.internal_label (asm_out_file, "Lscope", scope_labelno); | 
|  |  | 
|  | /* The N_FUN tag at the end of the function is a GNU extension, | 
|  | which may be undesirable, and is unnecessary if we do not have | 
|  | named sections.  */ | 
|  | if (!use_gnu_debug_info_extensions | 
|  | || NO_DBX_FUNCTION_END | 
|  | || !targetm_common.have_named_sections) | 
|  | return; | 
|  |  | 
|  | /* By convention, GCC will mark the end of a function with an N_FUN | 
|  | symbol and an empty string.  */ | 
|  | if (crtl->has_bb_partition) | 
|  | { | 
|  | dbxout_begin_empty_stabs (N_FUN); | 
|  | if (in_cold_section_p) | 
|  | dbxout_stab_value_label_diff (crtl->subsections.cold_section_end_label, | 
|  | crtl->subsections.cold_section_label); | 
|  | else | 
|  | dbxout_stab_value_label_diff (crtl->subsections.hot_section_end_label, | 
|  | crtl->subsections.hot_section_label); | 
|  | } | 
|  | else | 
|  | { | 
|  | char begin_label[20]; | 
|  | /* Reference current function start using LFBB.  */ | 
|  | ASM_GENERATE_INTERNAL_LABEL (begin_label, "LFBB", scope_labelno); | 
|  | dbxout_begin_empty_stabs (N_FUN); | 
|  | dbxout_stab_value_label_diff (lscope_label_name, begin_label); | 
|  | } | 
|  |  | 
|  | if (!NO_DBX_BNSYM_ENSYM && !flag_debug_only_used_symbols) | 
|  | dbxout_stabd (N_ENSYM, 0); | 
|  | } | 
|  | #endif /* DBX_DEBUGGING_INFO */ | 
|  |  | 
|  | /* Get lang description for N_SO stab.  */ | 
|  | static unsigned int ATTRIBUTE_UNUSED | 
|  | get_lang_number (void) | 
|  | { | 
|  | const char *language_string = lang_hooks.name; | 
|  | if (lang_GNU_C ()) | 
|  | return N_SO_C; | 
|  | else if (lang_GNU_CXX ()) | 
|  | return N_SO_CC; | 
|  | else if (strcmp (language_string, "GNU F77") == 0) | 
|  | return N_SO_FORTRAN; | 
|  | else if (lang_GNU_Fortran ()) | 
|  | return N_SO_FORTRAN90; /* CHECKME */ | 
|  | else if (strcmp (language_string, "GNU Objective-C") == 0) | 
|  | return N_SO_OBJC; | 
|  | else if (strcmp (language_string, "GNU Objective-C++") == 0) | 
|  | return N_SO_OBJCPLUS; | 
|  | else | 
|  | return 0; | 
|  |  | 
|  | } | 
|  |  | 
|  | static bool | 
|  | is_fortran (void) | 
|  | { | 
|  | unsigned int lang = get_lang_number (); | 
|  |  | 
|  | return (lang == N_SO_FORTRAN) || (lang == N_SO_FORTRAN90); | 
|  | } | 
|  |  | 
|  | /* At the beginning of compilation, start writing the symbol table. | 
|  | Initialize `typevec' and output the standard data types of C.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_init (const char *input_file_name) | 
|  | { | 
|  | char ltext_label_name[100]; | 
|  | bool used_ltext_label_name = false; | 
|  | tree syms = lang_hooks.decls.getdecls (); | 
|  | const char *mapped_name; | 
|  |  | 
|  | typevec_len = 100; | 
|  | typevec = ggc_cleared_vec_alloc<typeinfo> (typevec_len); | 
|  |  | 
|  | /* stabstr_ob contains one string, which will be just fine with | 
|  | 1-byte alignment.  */ | 
|  | obstack_specify_allocation (&stabstr_ob, 0, 1, xmalloc, free); | 
|  |  | 
|  | /* Convert Ltext into the appropriate format for local labels in case | 
|  | the system doesn't insert underscores in front of user generated | 
|  | labels.  */ | 
|  | ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); | 
|  |  | 
|  | /* Put the current working directory in an N_SO symbol.  */ | 
|  | if (use_gnu_debug_info_extensions && !NO_DBX_MAIN_SOURCE_DIRECTORY) | 
|  | { | 
|  | static const char *cwd; | 
|  |  | 
|  | if (!cwd) | 
|  | { | 
|  | cwd = get_src_pwd (); | 
|  | if (cwd[0] == '\0') | 
|  | cwd = "/"; | 
|  | else if (!IS_DIR_SEPARATOR (cwd[strlen (cwd) - 1])) | 
|  | cwd = concat (cwd, "/", NULL); | 
|  | cwd = remap_debug_filename (cwd); | 
|  | } | 
|  | #ifdef DBX_OUTPUT_MAIN_SOURCE_DIRECTORY | 
|  | DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (asm_out_file, cwd); | 
|  | #else /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ | 
|  | dbxout_begin_simple_stabs_desc (cwd, N_SO, get_lang_number ()); | 
|  | dbxout_stab_value_label (ltext_label_name); | 
|  | used_ltext_label_name = true; | 
|  | #endif /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ | 
|  | } | 
|  |  | 
|  | mapped_name = remap_debug_filename (input_file_name); | 
|  | #ifdef DBX_OUTPUT_MAIN_SOURCE_FILENAME | 
|  | DBX_OUTPUT_MAIN_SOURCE_FILENAME (asm_out_file, mapped_name); | 
|  | #else | 
|  | dbxout_begin_simple_stabs_desc (mapped_name, N_SO, get_lang_number ()); | 
|  | dbxout_stab_value_label (ltext_label_name); | 
|  | used_ltext_label_name = true; | 
|  | #endif | 
|  |  | 
|  | if (used_ltext_label_name) | 
|  | { | 
|  | switch_to_section (text_section); | 
|  | targetm.asm_out.internal_label (asm_out_file, "Ltext", 0); | 
|  | } | 
|  |  | 
|  | /* Emit an N_OPT stab to indicate that this file was compiled by GCC. | 
|  | The string used is historical.  */ | 
|  | #ifndef NO_DBX_GCC_MARKER | 
|  | dbxout_begin_simple_stabs ("gcc2_compiled.", N_OPT); | 
|  | dbxout_stab_value_zero (); | 
|  | #endif | 
|  |  | 
|  | base_input_file = lastfile = input_file_name; | 
|  |  | 
|  | next_type_number = 1; | 
|  |  | 
|  | #ifdef DBX_USE_BINCL | 
|  | current_file = XNEW (struct dbx_file); | 
|  | current_file->next = NULL; | 
|  | current_file->file_number = 0; | 
|  | current_file->next_type_number = 1; | 
|  | next_file_number = 1; | 
|  | current_file->prev = NULL; | 
|  | current_file->bincl_status = BINCL_NOT_REQUIRED; | 
|  | current_file->pending_bincl_name = NULL; | 
|  | #endif | 
|  |  | 
|  | /* Get all permanent types that have typedef names, and output them | 
|  | all, except for those already output.  Some language front ends | 
|  | put these declarations in the top-level scope; some do not; | 
|  | the latter are responsible for calling debug_hooks->type_decl from | 
|  | their record_builtin_type function.  */ | 
|  | dbxout_typedefs (syms); | 
|  |  | 
|  | if (preinit_symbols) | 
|  | { | 
|  | tree t; | 
|  | for (t = nreverse (preinit_symbols); t; t = TREE_CHAIN (t)) | 
|  | dbxout_symbol (TREE_VALUE (t), 0); | 
|  | preinit_symbols = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Output any typedef names for types described by TYPE_DECLs in SYMS.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_typedefs (tree syms) | 
|  | { | 
|  | for (; syms != NULL_TREE; syms = DECL_CHAIN (syms)) | 
|  | { | 
|  | if (TREE_CODE (syms) == TYPE_DECL) | 
|  | { | 
|  | tree type = TREE_TYPE (syms); | 
|  | if (TYPE_NAME (type) | 
|  | && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | 
|  | && COMPLETE_OR_VOID_TYPE_P (type) | 
|  | && ! TREE_ASM_WRITTEN (TYPE_NAME (type))) | 
|  | dbxout_symbol (TYPE_NAME (type), 0); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifdef DBX_USE_BINCL | 
|  | /* Emit BINCL stab using given name.  */ | 
|  | static void | 
|  | emit_bincl_stab (const char *name) | 
|  | { | 
|  | dbxout_begin_simple_stabs (name, N_BINCL); | 
|  | dbxout_stab_value_zero (); | 
|  | } | 
|  |  | 
|  | /* If there are pending bincls then it is time to emit all of them.  */ | 
|  |  | 
|  | static inline void | 
|  | emit_pending_bincls_if_required (void) | 
|  | { | 
|  | if (pending_bincls) | 
|  | emit_pending_bincls (); | 
|  | } | 
|  |  | 
|  | /* Emit all pending bincls.  */ | 
|  |  | 
|  | static void | 
|  | emit_pending_bincls (void) | 
|  | { | 
|  | struct dbx_file *f = current_file; | 
|  |  | 
|  | /* Find first pending bincl.  */ | 
|  | while (f->bincl_status == BINCL_PENDING) | 
|  | f = f->next; | 
|  |  | 
|  | /* Now emit all bincls.  */ | 
|  | f = f->prev; | 
|  |  | 
|  | while (f) | 
|  | { | 
|  | if (f->bincl_status == BINCL_PENDING) | 
|  | { | 
|  | emit_bincl_stab (f->pending_bincl_name); | 
|  |  | 
|  | /* Update file number and status.  */ | 
|  | f->file_number = next_file_number++; | 
|  | f->bincl_status = BINCL_PROCESSED; | 
|  | } | 
|  | if (f == current_file) | 
|  | break; | 
|  | f = f->prev; | 
|  | } | 
|  |  | 
|  | /* All pending bincls have been emitted.  */ | 
|  | pending_bincls = 0; | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | static inline void | 
|  | emit_pending_bincls_if_required (void) {} | 
|  | #endif | 
|  |  | 
|  | /* Change to reading from a new source file.  Generate a N_BINCL stab.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_start_source_file (unsigned int line ATTRIBUTE_UNUSED, | 
|  | const char *filename ATTRIBUTE_UNUSED) | 
|  | { | 
|  | #ifdef DBX_USE_BINCL | 
|  | struct dbx_file *n = XNEW (struct dbx_file); | 
|  |  | 
|  | n->next = current_file; | 
|  | n->next_type_number = 1; | 
|  | /* Do not assign file number now. | 
|  | Delay it until we actually emit BINCL.  */ | 
|  | n->file_number = 0; | 
|  | n->prev = NULL; | 
|  | current_file->prev = n; | 
|  | n->bincl_status = BINCL_PENDING; | 
|  | n->pending_bincl_name = remap_debug_filename (filename); | 
|  | pending_bincls = 1; | 
|  | current_file = n; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Revert to reading a previous source file.  Generate a N_EINCL stab.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_end_source_file (unsigned int line ATTRIBUTE_UNUSED) | 
|  | { | 
|  | #ifdef DBX_USE_BINCL | 
|  | /* Emit EINCL stab only if BINCL is not pending.  */ | 
|  | if (current_file->bincl_status == BINCL_PROCESSED) | 
|  | { | 
|  | dbxout_begin_stabn (N_EINCL); | 
|  | dbxout_stab_value_zero (); | 
|  | } | 
|  | current_file->bincl_status = BINCL_NOT_REQUIRED; | 
|  | current_file = current_file->next; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Handle a few odd cases that occur when trying to make PCH files work.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_handle_pch (unsigned at_end) | 
|  | { | 
|  | if (! at_end) | 
|  | { | 
|  | /* When using the PCH, this file will be included, so we need to output | 
|  | a BINCL.  */ | 
|  | dbxout_start_source_file (0, lastfile); | 
|  |  | 
|  | /* The base file when using the PCH won't be the same as | 
|  | the base file when it's being generated.  */ | 
|  | lastfile = NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* ... and an EINCL.  */ | 
|  | dbxout_end_source_file (0); | 
|  |  | 
|  | /* Deal with cases where 'lastfile' was never actually changed.  */ | 
|  | lastfile_is_base = lastfile == NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | #if defined (DBX_DEBUGGING_INFO) | 
|  |  | 
|  | static bool dbxout_block (tree, int, tree, int); | 
|  |  | 
|  | /* Output debugging info to FILE to switch to sourcefile FILENAME.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_source_file (const char *filename) | 
|  | { | 
|  | if (lastfile == 0 && lastfile_is_base) | 
|  | { | 
|  | lastfile = base_input_file; | 
|  | lastfile_is_base = 0; | 
|  | } | 
|  |  | 
|  | if (filename && (lastfile == 0 || strcmp (filename, lastfile))) | 
|  | { | 
|  | /* Don't change section amid function.  */ | 
|  | if (current_function_decl == NULL_TREE) | 
|  | switch_to_section (text_section); | 
|  |  | 
|  | dbxout_begin_simple_stabs (remap_debug_filename (filename), N_SOL); | 
|  | dbxout_stab_value_internal_label ("Ltext", &source_label_number); | 
|  | lastfile = filename; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Output N_BNSYM, line number symbol entry, and local symbol at | 
|  | function scope  */ | 
|  |  | 
|  | static void | 
|  | dbxout_begin_prologue (unsigned int lineno, | 
|  | unsigned int column ATTRIBUTE_UNUSED, | 
|  | const char *filename) | 
|  | { | 
|  | if (use_gnu_debug_info_extensions | 
|  | && !NO_DBX_FUNCTION_END | 
|  | && !NO_DBX_BNSYM_ENSYM | 
|  | && !flag_debug_only_used_symbols) | 
|  | dbxout_stabd (N_BNSYM, 0); | 
|  |  | 
|  | /* pre-increment the scope counter */ | 
|  | scope_labelno++; | 
|  |  | 
|  | dbxout_source_line (lineno, 0, filename, 0, true); | 
|  | /* Output function begin block at function scope, referenced | 
|  | by dbxout_block, dbxout_source_line and dbxout_function_end.  */ | 
|  | emit_pending_bincls_if_required (); | 
|  | targetm.asm_out.internal_label (asm_out_file, "LFBB", scope_labelno); | 
|  | } | 
|  |  | 
|  | /* Output a line number symbol entry for source file FILENAME and line | 
|  | number LINENO.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_source_line (unsigned int lineno, unsigned int column ATTRIBUTE_UNUSED, | 
|  | const char *filename, int discriminator ATTRIBUTE_UNUSED, | 
|  | bool is_stmt ATTRIBUTE_UNUSED) | 
|  | { | 
|  | dbxout_source_file (filename); | 
|  |  | 
|  | #ifdef DBX_OUTPUT_SOURCE_LINE | 
|  | DBX_OUTPUT_SOURCE_LINE (asm_out_file, lineno, dbxout_source_line_counter); | 
|  | #else | 
|  | if (DBX_LINES_FUNCTION_RELATIVE) | 
|  | { | 
|  | char begin_label[20]; | 
|  | dbxout_begin_stabn_sline (lineno); | 
|  | /* Reference current function start using LFBB.  */ | 
|  | ASM_GENERATE_INTERNAL_LABEL (begin_label, "LFBB", scope_labelno); | 
|  | dbxout_stab_value_internal_label_diff ("LM", &dbxout_source_line_counter, | 
|  | begin_label); | 
|  | } | 
|  | else | 
|  | dbxout_stabd (N_SLINE, lineno); | 
|  | #endif | 
|  | lastlineno = lineno; | 
|  | } | 
|  |  | 
|  | /* Unfortunately, at least when emitting relative addresses, STABS | 
|  | has no way to express multiple partitions.  Represent a function | 
|  | as two functions in this case.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_switch_text_section (void) | 
|  | { | 
|  | /* The N_FUN tag at the end of the function is a GNU extension, | 
|  | which may be undesirable, and is unnecessary if we do not have | 
|  | named sections.  */ | 
|  | in_cold_section_p = !in_cold_section_p; | 
|  | switch_to_section (current_function_section ()); | 
|  | dbxout_block (DECL_INITIAL (current_function_decl), 0, | 
|  | DECL_ARGUMENTS (current_function_decl), -1); | 
|  | dbxout_function_end (current_function_decl); | 
|  | in_cold_section_p = !in_cold_section_p; | 
|  |  | 
|  | switch_to_section (current_function_section ()); | 
|  |  | 
|  | tree context = decl_function_context (current_function_decl); | 
|  | extern tree cold_function_name; | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  | stabstr_I (cold_function_name); | 
|  | stabstr_S (":f"); | 
|  |  | 
|  | tree type = TREE_TYPE (current_function_decl); | 
|  | if (TREE_TYPE (type)) | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | else | 
|  | dbxout_type (void_type_node, 0); | 
|  |  | 
|  | if (context != 0) | 
|  | { | 
|  | stabstr_C (','); | 
|  | stabstr_I (cold_function_name); | 
|  | stabstr_C (','); | 
|  | stabstr_I (DECL_NAME (context)); | 
|  | } | 
|  |  | 
|  | dbxout_finish_complex_stabs (current_function_decl, N_FUN, 0, | 
|  | crtl->subsections.cold_section_label, 0); | 
|  |  | 
|  | /* pre-increment the scope counter */ | 
|  | scope_labelno++; | 
|  |  | 
|  | dbxout_source_line (lastlineno, 0, lastfile, 0, true); | 
|  | /* Output function begin block at function scope, referenced | 
|  | by dbxout_block, dbxout_source_line and dbxout_function_end.  */ | 
|  | emit_pending_bincls_if_required (); | 
|  | targetm.asm_out.internal_label (asm_out_file, "LFBB", scope_labelno); | 
|  | } | 
|  |  | 
|  | /* Describe the beginning of an internal block within a function.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_begin_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int n) | 
|  | { | 
|  | emit_pending_bincls_if_required (); | 
|  | targetm.asm_out.internal_label (asm_out_file, "LBB", n); | 
|  | } | 
|  |  | 
|  | /* Describe the end line-number of an internal block within a function.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int n) | 
|  | { | 
|  | emit_pending_bincls_if_required (); | 
|  | targetm.asm_out.internal_label (asm_out_file, "LBE", n); | 
|  | } | 
|  |  | 
|  | /* Output dbx data for a function definition. | 
|  | This includes a definition of the function name itself (a symbol), | 
|  | definitions of the parameters (locating them in the parameter list) | 
|  | and then output the block that makes up the function's body | 
|  | (including all the auto variables of the function).  */ | 
|  |  | 
|  | static void | 
|  | dbxout_function_decl (tree decl) | 
|  | { | 
|  | emit_pending_bincls_if_required (); | 
|  | #ifndef DBX_FUNCTION_FIRST | 
|  | dbxout_begin_function (decl); | 
|  | #endif | 
|  | dbxout_block (DECL_INITIAL (decl), 0, DECL_ARGUMENTS (decl), -1); | 
|  | dbxout_function_end (decl); | 
|  | } | 
|  |  | 
|  | #endif /* DBX_DEBUGGING_INFO  */ | 
|  |  | 
|  | static void | 
|  | dbxout_early_global_decl (tree decl ATTRIBUTE_UNUSED) | 
|  | { | 
|  | /* NYI for non-dwarf.  */ | 
|  | } | 
|  |  | 
|  | /* Debug information for a global DECL.  Called from toplev.cc after | 
|  | compilation proper has finished.  */ | 
|  | static void | 
|  | dbxout_late_global_decl (tree decl) | 
|  | { | 
|  | if (VAR_P (decl) && !DECL_EXTERNAL (decl)) | 
|  | { | 
|  | int saved_tree_used = TREE_USED (decl); | 
|  | TREE_USED (decl) = 1; | 
|  | dbxout_symbol (decl, 0); | 
|  | TREE_USED (decl) = saved_tree_used; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This is just a function-type adapter; dbxout_symbol does exactly | 
|  | what we want but returns an int.  */ | 
|  | static void | 
|  | dbxout_type_decl (tree decl, int local) | 
|  | { | 
|  | dbxout_symbol (decl, local); | 
|  | } | 
|  |  | 
|  | /* At the end of compilation, finish writing the symbol table. | 
|  | The default is to call debug_free_queue but do nothing else.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_finish (const char *filename ATTRIBUTE_UNUSED) | 
|  | { | 
|  | #ifdef DBX_OUTPUT_MAIN_SOURCE_FILE_END | 
|  | DBX_OUTPUT_MAIN_SOURCE_FILE_END (asm_out_file, filename); | 
|  | #elif defined DBX_OUTPUT_NULL_N_SO_AT_MAIN_SOURCE_FILE_END | 
|  | { | 
|  | switch_to_section (text_section); | 
|  | dbxout_begin_empty_stabs (N_SO); | 
|  | dbxout_stab_value_internal_label ("Letext", 0); | 
|  | } | 
|  | #endif | 
|  | debug_free_queue (); | 
|  | } | 
|  |  | 
|  | /* Output the index of a type.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_type_index (tree type) | 
|  | { | 
|  | #ifndef DBX_USE_BINCL | 
|  | stabstr_D (TYPE_SYMTAB_ADDRESS (type)); | 
|  | #else | 
|  | struct typeinfo *t = &typevec[TYPE_SYMTAB_ADDRESS (type)]; | 
|  | stabstr_C ('('); | 
|  | stabstr_D (t->file_number); | 
|  | stabstr_C (','); | 
|  | stabstr_D (t->type_number); | 
|  | stabstr_C (')'); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Generate the symbols for any queued up type symbols we encountered | 
|  | while generating the type info for some originally used symbol. | 
|  | This might generate additional entries in the queue.  Only when | 
|  | the nesting depth goes to 0 is this routine called.  */ | 
|  |  | 
|  | static void | 
|  | debug_flush_symbol_queue (void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* Make sure that additionally queued items are not flushed | 
|  | prematurely.  */ | 
|  |  | 
|  | ++debug_nesting; | 
|  |  | 
|  | for (i = 0; i < symbol_queue_index; ++i) | 
|  | { | 
|  | /* If we pushed queued symbols then such symbols must be | 
|  | output no matter what anyone else says.  Specifically, | 
|  | we need to make sure dbxout_symbol() thinks the symbol was | 
|  | used and also we need to override TYPE_DECL_SUPPRESS_DEBUG | 
|  | which may be set for outside reasons.  */ | 
|  | int saved_tree_used = TREE_USED (symbol_queue[i]); | 
|  | int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]); | 
|  | TREE_USED (symbol_queue[i]) = 1; | 
|  | TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0; | 
|  |  | 
|  | #ifdef DBX_DEBUGGING_INFO | 
|  | dbxout_symbol (symbol_queue[i], 0); | 
|  | #endif | 
|  |  | 
|  | TREE_USED (symbol_queue[i]) = saved_tree_used; | 
|  | TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug; | 
|  | } | 
|  |  | 
|  | symbol_queue_index = 0; | 
|  | --debug_nesting; | 
|  | } | 
|  |  | 
|  | /* Queue a type symbol needed as part of the definition of a decl | 
|  | symbol.  These symbols are generated when debug_flush_symbol_queue() | 
|  | is called.  */ | 
|  |  | 
|  | static void | 
|  | debug_queue_symbol (tree decl) | 
|  | { | 
|  | if (symbol_queue_index >= symbol_queue_size) | 
|  | { | 
|  | symbol_queue_size += 10; | 
|  | symbol_queue = XRESIZEVEC (tree, symbol_queue, symbol_queue_size); | 
|  | } | 
|  |  | 
|  | symbol_queue[symbol_queue_index++] = decl; | 
|  | } | 
|  |  | 
|  | /* Free symbol queue.  */ | 
|  | static void | 
|  | debug_free_queue (void) | 
|  | { | 
|  | if (symbol_queue) | 
|  | { | 
|  | free (symbol_queue); | 
|  | symbol_queue = NULL; | 
|  | symbol_queue_size = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Used in several places: evaluates to '0' for a private decl, | 
|  | '1' for a protected decl, '2' for a public decl.  */ | 
|  | #define DECL_ACCESSIBILITY_CHAR(DECL) \ | 
|  | (TREE_PRIVATE (DECL) ? '0' : TREE_PROTECTED (DECL) ? '1' : '2') | 
|  |  | 
|  | /* Subroutine of `dbxout_type'.  Output the type fields of TYPE. | 
|  | This must be a separate function because anonymous unions require | 
|  | recursive calls.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_type_fields (tree type) | 
|  | { | 
|  | tree tem; | 
|  |  | 
|  | /* Output the name, type, position (in bits), size (in bits) of each | 
|  | field that we can support.  */ | 
|  | for (tem = TYPE_FIELDS (type); tem; tem = DECL_CHAIN (tem)) | 
|  | { | 
|  | /* If one of the nodes is an error_mark or its type is then | 
|  | return early.  */ | 
|  | if (error_operand_p (tem)) | 
|  | return; | 
|  |  | 
|  | /* Omit here local type decls until we know how to support them.  */ | 
|  | if (TREE_CODE (tem) == TYPE_DECL | 
|  | || TREE_CODE (tem) == TEMPLATE_DECL | 
|  | /* Member functions emitted after fields.  */ | 
|  | || TREE_CODE (tem) == FUNCTION_DECL | 
|  | /* Omit here the nameless fields that are used to skip bits.  */ | 
|  | || DECL_IGNORED_P (tem) | 
|  | /* Omit fields whose position or size are variable or too large to | 
|  | represent.  */ | 
|  | || (TREE_CODE (tem) == FIELD_DECL | 
|  | && (! tree_fits_shwi_p (bit_position (tem)) | 
|  | || ! DECL_SIZE (tem) | 
|  | || ! tree_fits_uhwi_p (DECL_SIZE (tem))))) | 
|  | continue; | 
|  |  | 
|  | else if (TREE_CODE (tem) != CONST_DECL) | 
|  | { | 
|  | /* Continue the line if necessary, | 
|  | but not before the first field.  */ | 
|  | if (tem != TYPE_FIELDS (type)) | 
|  | CONTIN; | 
|  |  | 
|  | if (DECL_NAME (tem)) | 
|  | stabstr_I (DECL_NAME (tem)); | 
|  | stabstr_C (':'); | 
|  |  | 
|  | if (use_gnu_debug_info_extensions | 
|  | && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem) | 
|  | || TREE_CODE (tem) != FIELD_DECL)) | 
|  | { | 
|  | stabstr_C ('/'); | 
|  | stabstr_C (DECL_ACCESSIBILITY_CHAR (tem)); | 
|  | } | 
|  |  | 
|  | dbxout_type ((TREE_CODE (tem) == FIELD_DECL | 
|  | && DECL_BIT_FIELD_TYPE (tem)) | 
|  | ? DECL_BIT_FIELD_TYPE (tem) : TREE_TYPE (tem), 0); | 
|  |  | 
|  | if (VAR_P (tem)) | 
|  | { | 
|  | if (TREE_STATIC (tem) && use_gnu_debug_info_extensions) | 
|  | { | 
|  | tree name = DECL_ASSEMBLER_NAME (tem); | 
|  |  | 
|  | stabstr_C (':'); | 
|  | stabstr_I (name); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | else | 
|  | /* If TEM is non-static, GDB won't understand it.  */ | 
|  | stabstr_S (",0,0;"); | 
|  | } | 
|  | else | 
|  | { | 
|  | stabstr_C (','); | 
|  | stabstr_D (int_bit_position (tem)); | 
|  | stabstr_C (','); | 
|  | stabstr_D (tree_to_uhwi (DECL_SIZE (tem))); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Subroutine of `dbxout_type_methods'.  Output debug info about the | 
|  | method described DECL.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_type_method_1 (tree decl) | 
|  | { | 
|  | char c1 = 'A', c2; | 
|  |  | 
|  | if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE) | 
|  | c2 = '?'; | 
|  | else /* it's a METHOD_TYPE.  */ | 
|  | { | 
|  | tree firstarg = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))); | 
|  | /* A for normal functions. | 
|  | B for `const' member functions. | 
|  | C for `volatile' member functions. | 
|  | D for `const volatile' member functions.  */ | 
|  | if (TYPE_READONLY (TREE_TYPE (firstarg))) | 
|  | c1 += 1; | 
|  | if (TYPE_VOLATILE (TREE_TYPE (firstarg))) | 
|  | c1 += 2; | 
|  |  | 
|  | if (DECL_VINDEX (decl)) | 
|  | c2 = '*'; | 
|  | else | 
|  | c2 = '.'; | 
|  | } | 
|  |  | 
|  | /* ??? Output the mangled name, which contains an encoding of the | 
|  | method's type signature.  May not be necessary anymore.  */ | 
|  | stabstr_C (':'); | 
|  | stabstr_I (DECL_ASSEMBLER_NAME (decl)); | 
|  | stabstr_C (';'); | 
|  | stabstr_C (DECL_ACCESSIBILITY_CHAR (decl)); | 
|  | stabstr_C (c1); | 
|  | stabstr_C (c2); | 
|  |  | 
|  | if (DECL_VINDEX (decl) && tree_fits_shwi_p (DECL_VINDEX (decl))) | 
|  | { | 
|  | stabstr_D (tree_to_shwi (DECL_VINDEX (decl))); | 
|  | stabstr_C (';'); | 
|  | dbxout_type (DECL_CONTEXT (decl), 0); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Subroutine of `dbxout_type'.  Output debug info about the member | 
|  | functions defined in TYPE.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_type_methods (tree type) | 
|  | { | 
|  | for (tree fndecl = TYPE_FIELDS (type); fndecl;) | 
|  | { | 
|  | int need_prefix = 1; | 
|  |  | 
|  | /* Group together all the methods for the same operation. | 
|  | These differ in the types of the arguments.  */ | 
|  | for (tree last = NULL_TREE; | 
|  | fndecl && (last == NULL_TREE || DECL_NAME (fndecl) == DECL_NAME (last)); | 
|  | fndecl = DECL_CHAIN (fndecl)) | 
|  | /* Output the name of the field (after overloading), as | 
|  | well as the name of the field before overloading, along | 
|  | with its parameter list */ | 
|  | { | 
|  | /* Skip non-functions.  */ | 
|  | if (TREE_CODE (fndecl) != FUNCTION_DECL) | 
|  | continue; | 
|  |  | 
|  | /* Also ignore abstract methods; those are only interesting to | 
|  | the DWARF backends.  */ | 
|  | if (DECL_IGNORED_P (fndecl) || DECL_ABSTRACT_P (fndecl)) | 
|  | continue; | 
|  |  | 
|  | CONTIN; | 
|  |  | 
|  | last = fndecl; | 
|  |  | 
|  | /* Redundantly output the plain name, since that's what gdb | 
|  | expects.  */ | 
|  | if (need_prefix) | 
|  | { | 
|  | stabstr_I (DECL_NAME (fndecl)); | 
|  | stabstr_S ("::"); | 
|  | need_prefix = 0; | 
|  | } | 
|  |  | 
|  | dbxout_type (TREE_TYPE (fndecl), 0); | 
|  | dbxout_type_method_1 (fndecl); | 
|  | } | 
|  | if (!need_prefix) | 
|  | stabstr_C (';'); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Emit a "range" type specification, which has the form: | 
|  | "r<index type>;<lower bound>;<upper bound>;". | 
|  | TYPE is an INTEGER_TYPE, LOW and HIGH are the bounds.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_range_type (tree type, tree low, tree high) | 
|  | { | 
|  | stabstr_C ('r'); | 
|  | if (TREE_TYPE (type)) | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | else if (TREE_CODE (type) != INTEGER_TYPE) | 
|  | dbxout_type (type, 0); | 
|  | else | 
|  | { | 
|  | /* Traditionally, we made sure 'int' was type 1, and builtin types | 
|  | were defined to be sub-ranges of int.  Unfortunately, this | 
|  | does not allow us to distinguish true sub-ranges from integer | 
|  | types.  So, instead we define integer (non-sub-range) types as | 
|  | sub-ranges of themselves.  This matters for Chill.  If this isn't | 
|  | a subrange type, then we want to define it in terms of itself. | 
|  | However, in C, this may be an anonymous integer type, and we don't | 
|  | want to emit debug info referring to it.  Just calling | 
|  | dbxout_type_index won't work anyways, because the type hasn't been | 
|  | defined yet.  We make this work for both cases by checked to see | 
|  | whether this is a defined type, referring to it if it is, and using | 
|  | 'int' otherwise.  */ | 
|  | if (TYPE_SYMTAB_ADDRESS (type) != 0) | 
|  | dbxout_type_index (type); | 
|  | else | 
|  | dbxout_type_index (integer_type_node); | 
|  | } | 
|  |  | 
|  | stabstr_C (';'); | 
|  | if (low && tree_fits_shwi_p (low)) | 
|  | { | 
|  | if (print_int_cst_bounds_in_octal_p (type, low, high)) | 
|  | stabstr_O (low); | 
|  | else | 
|  | stabstr_D (tree_to_shwi (low)); | 
|  | } | 
|  | else | 
|  | stabstr_C ('0'); | 
|  |  | 
|  | stabstr_C (';'); | 
|  | if (high && tree_fits_shwi_p (high)) | 
|  | { | 
|  | if (print_int_cst_bounds_in_octal_p (type, low, high)) | 
|  | stabstr_O (high); | 
|  | else | 
|  | stabstr_D (tree_to_shwi (high)); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | else | 
|  | stabstr_S ("-1;"); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Output a reference to a type.  If the type has not yet been | 
|  | described in the dbx output, output its definition now. | 
|  | For a type already defined, just refer to its definition | 
|  | using the type number. | 
|  |  | 
|  | If FULL is nonzero, and the type has been described only with | 
|  | a forward-reference, output the definition now. | 
|  | If FULL is zero in this case, just refer to the forward-reference | 
|  | using the number previously allocated.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_type (tree type, int full) | 
|  | { | 
|  | static int anonymous_type_number = 0; | 
|  | tree tem, main_variant, low, high; | 
|  |  | 
|  | if (TREE_CODE (type) == INTEGER_TYPE) | 
|  | { | 
|  | if (TREE_TYPE (type) == 0) | 
|  | { | 
|  | low = TYPE_MIN_VALUE (type); | 
|  | high = TYPE_MAX_VALUE (type); | 
|  | } | 
|  |  | 
|  | else if (subrange_type_for_debug_p (type, &low, &high)) | 
|  | ; | 
|  |  | 
|  | /* If this is a subtype that should not be emitted as a subrange type, | 
|  | use the base type.  */ | 
|  | else | 
|  | { | 
|  | type = TREE_TYPE (type); | 
|  | low = TYPE_MIN_VALUE (type); | 
|  | high = TYPE_MAX_VALUE (type); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* If there was an input error and we don't really have a type, | 
|  | avoid crashing and write something that is at least valid | 
|  | by assuming `int'.  */ | 
|  | if (type == error_mark_node) | 
|  | type = integer_type_node; | 
|  | else | 
|  | { | 
|  | if (TYPE_NAME (type) | 
|  | && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | 
|  | && TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type))) | 
|  | full = 0; | 
|  | } | 
|  |  | 
|  | /* Try to find the "main variant" with the same name.  */ | 
|  | if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | 
|  | && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) | 
|  | main_variant = TREE_TYPE (TYPE_NAME (type)); | 
|  | else | 
|  | main_variant = TYPE_MAIN_VARIANT (type); | 
|  |  | 
|  | /* If we are not using extensions, stabs does not distinguish const and | 
|  | volatile, so there is no need to make them separate types.  */ | 
|  | if (!use_gnu_debug_info_extensions) | 
|  | type = main_variant; | 
|  |  | 
|  | if (TYPE_SYMTAB_ADDRESS (type) == 0) | 
|  | { | 
|  | /* Type has no dbx number assigned.  Assign next available number.  */ | 
|  | TYPE_SYMTAB_ADDRESS (type) = next_type_number++; | 
|  |  | 
|  | /* Make sure type vector is long enough to record about this type.  */ | 
|  |  | 
|  | if (next_type_number == typevec_len) | 
|  | { | 
|  | typevec = GGC_RESIZEVEC (struct typeinfo, typevec, typevec_len * 2); | 
|  | memset (typevec + typevec_len, 0, typevec_len * sizeof typevec[0]); | 
|  | typevec_len *= 2; | 
|  | } | 
|  |  | 
|  | #ifdef DBX_USE_BINCL | 
|  | emit_pending_bincls_if_required (); | 
|  | typevec[TYPE_SYMTAB_ADDRESS (type)].file_number | 
|  | = current_file->file_number; | 
|  | typevec[TYPE_SYMTAB_ADDRESS (type)].type_number | 
|  | = current_file->next_type_number++; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | if (flag_debug_only_used_symbols) | 
|  | { | 
|  | if ((TREE_CODE (type) == RECORD_TYPE | 
|  | || TREE_CODE (type) == UNION_TYPE | 
|  | || TREE_CODE (type) == QUAL_UNION_TYPE | 
|  | || TREE_CODE (type) == ENUMERAL_TYPE) | 
|  | && TYPE_STUB_DECL (type) | 
|  | && DECL_P (TYPE_STUB_DECL (type)) | 
|  | && ! DECL_IGNORED_P (TYPE_STUB_DECL (type))) | 
|  | debug_queue_symbol (TYPE_STUB_DECL (type)); | 
|  | else if (TYPE_NAME (type) | 
|  | && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) | 
|  | debug_queue_symbol (TYPE_NAME (type)); | 
|  | } | 
|  |  | 
|  | /* Output the number of this type, to refer to it.  */ | 
|  | dbxout_type_index (type); | 
|  |  | 
|  | #ifdef DBX_TYPE_DEFINED | 
|  | if (DBX_TYPE_DEFINED (type)) | 
|  | return; | 
|  | #endif | 
|  |  | 
|  | /* If this type's definition has been output or is now being output, | 
|  | that is all.  */ | 
|  |  | 
|  | switch (typevec[TYPE_SYMTAB_ADDRESS (type)].status) | 
|  | { | 
|  | case TYPE_UNSEEN: | 
|  | break; | 
|  | case TYPE_XREF: | 
|  | /* If we have already had a cross reference, | 
|  | and either that's all we want or that's the best we could do, | 
|  | don't repeat the cross reference. | 
|  | Sun dbx crashes if we do.  */ | 
|  | if (! full || !COMPLETE_TYPE_P (type) | 
|  | /* No way in DBX fmt to describe a variable size.  */ | 
|  | || ! tree_fits_uhwi_p (TYPE_SIZE (type))) | 
|  | return; | 
|  | break; | 
|  | case TYPE_DEFINED: | 
|  | return; | 
|  | } | 
|  |  | 
|  | #ifdef DBX_NO_XREFS | 
|  | /* For systems where dbx output does not allow the `=xsNAME:' syntax, | 
|  | leave the type-number completely undefined rather than output | 
|  | a cross-reference.  If we have already used GNU debug info extensions, | 
|  | then it is OK to output a cross reference.  This is necessary to get | 
|  | proper C++ debug output.  */ | 
|  | if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE | 
|  | || TREE_CODE (type) == QUAL_UNION_TYPE | 
|  | || TREE_CODE (type) == ENUMERAL_TYPE) | 
|  | && ! use_gnu_debug_info_extensions) | 
|  | /* We must use the same test here as we use twice below when deciding | 
|  | whether to emit a cross-reference.  */ | 
|  | if ((TYPE_NAME (type) != 0 | 
|  | && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | 
|  | && DECL_IGNORED_P (TYPE_NAME (type))) | 
|  | && !full) | 
|  | || !COMPLETE_TYPE_P (type) | 
|  | /* No way in DBX fmt to describe a variable size.  */ | 
|  | || ! tree_fits_uhwi_p (TYPE_SIZE (type))) | 
|  | { | 
|  | typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; | 
|  | return; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* Output a definition now.  */ | 
|  | stabstr_C ('='); | 
|  |  | 
|  | /* Mark it as defined, so that if it is self-referent | 
|  | we will not get into an infinite recursion of definitions.  */ | 
|  |  | 
|  | typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_DEFINED; | 
|  |  | 
|  | /* If this type is a variant of some other, hand off.  Types with | 
|  | different names are usefully distinguished.  We only distinguish | 
|  | cv-qualified types if we're using extensions.  */ | 
|  | if (TYPE_READONLY (type) > TYPE_READONLY (main_variant)) | 
|  | { | 
|  | stabstr_C ('k'); | 
|  | dbxout_type (build_type_variant (type, 0, TYPE_VOLATILE (type)), 0); | 
|  | return; | 
|  | } | 
|  | else if (TYPE_VOLATILE (type) > TYPE_VOLATILE (main_variant)) | 
|  | { | 
|  | stabstr_C ('B'); | 
|  | dbxout_type (build_type_variant (type, TYPE_READONLY (type), 0), 0); | 
|  | return; | 
|  | } | 
|  | else if (main_variant != TYPE_MAIN_VARIANT (type)) | 
|  | { | 
|  | if (flag_debug_only_used_symbols) | 
|  | { | 
|  | tree orig_type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); | 
|  |  | 
|  | if ((TREE_CODE (orig_type) == RECORD_TYPE | 
|  | || TREE_CODE (orig_type) == UNION_TYPE | 
|  | || TREE_CODE (orig_type) == QUAL_UNION_TYPE | 
|  | || TREE_CODE (orig_type) == ENUMERAL_TYPE) | 
|  | && TYPE_STUB_DECL (orig_type) | 
|  | && ! DECL_IGNORED_P (TYPE_STUB_DECL (orig_type))) | 
|  | debug_queue_symbol (TYPE_STUB_DECL (orig_type)); | 
|  | } | 
|  | /* 'type' is a typedef; output the type it refers to.  */ | 
|  | dbxout_type (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), 0); | 
|  | return; | 
|  | } | 
|  | /* else continue.  */ | 
|  |  | 
|  | switch (TREE_CODE (type)) | 
|  | { | 
|  | case VOID_TYPE: | 
|  | case NULLPTR_TYPE: | 
|  | case LANG_TYPE: | 
|  | case OPAQUE_TYPE: | 
|  | /* For a void type, just define it as itself; i.e., "5=5". | 
|  | This makes us consider it defined | 
|  | without saying what it is.  The debugger will make it | 
|  | a void type when the reference is seen, and nothing will | 
|  | ever override that default.  */ | 
|  | dbxout_type_index (type); | 
|  | break; | 
|  |  | 
|  | case INTEGER_TYPE: | 
|  | if (type == char_type_node && ! TYPE_UNSIGNED (type)) | 
|  | { | 
|  | /* Output the type `char' as a subrange of itself! | 
|  | I don't understand this definition, just copied it | 
|  | from the output of pcc. | 
|  | This used to use `r2' explicitly and we used to | 
|  | take care to make sure that `char' was type number 2.  */ | 
|  | stabstr_C ('r'); | 
|  | dbxout_type_index (type); | 
|  | stabstr_S (";0;127;"); | 
|  | } | 
|  |  | 
|  | /* If this is a subtype of another integer type, always prefer to | 
|  | write it as a subtype.  */ | 
|  | else if (TREE_TYPE (type) != 0 | 
|  | && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE) | 
|  | { | 
|  | /* If the size is non-standard, say what it is if we can use | 
|  | GDB extensions.  */ | 
|  |  | 
|  | if (use_gnu_debug_info_extensions | 
|  | && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) | 
|  | { | 
|  | stabstr_S ("@s"); | 
|  | stabstr_D (TYPE_PRECISION (type)); | 
|  | stabstr_C (';'); | 
|  | } | 
|  |  | 
|  | dbxout_range_type (type, low, high); | 
|  | } | 
|  |  | 
|  | else | 
|  | { | 
|  | /* If the size is non-standard, say what it is if we can use | 
|  | GDB extensions.  */ | 
|  |  | 
|  | if (use_gnu_debug_info_extensions | 
|  | && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) | 
|  | { | 
|  | stabstr_S ("@s"); | 
|  | stabstr_D (TYPE_PRECISION (type)); | 
|  | stabstr_C (';'); | 
|  | } | 
|  |  | 
|  | if (print_int_cst_bounds_in_octal_p (type, low, high)) | 
|  | { | 
|  | stabstr_C ('r'); | 
|  |  | 
|  | /* If this type derives from another type, output type index of | 
|  | parent type. This is particularly important when parent type | 
|  | is an enumerated type, because not generating the parent type | 
|  | index would transform the definition of this enumerated type | 
|  | into a plain unsigned type.  */ | 
|  | if (TREE_TYPE (type) != 0) | 
|  | dbxout_type_index (TREE_TYPE (type)); | 
|  | else | 
|  | dbxout_type_index (type); | 
|  |  | 
|  | stabstr_C (';'); | 
|  | stabstr_O (low); | 
|  | stabstr_C (';'); | 
|  | stabstr_O (high); | 
|  | stabstr_C (';'); | 
|  | } | 
|  |  | 
|  | else | 
|  | /* Output other integer types as subranges of `int'.  */ | 
|  | dbxout_range_type (type, low, high); | 
|  | } | 
|  |  | 
|  | break; | 
|  |  | 
|  | case REAL_TYPE: | 
|  | case FIXED_POINT_TYPE: | 
|  | /* This used to say `r1' and we used to take care | 
|  | to make sure that `int' was type number 1.  */ | 
|  | stabstr_C ('r'); | 
|  | dbxout_type_index (integer_type_node); | 
|  | stabstr_C (';'); | 
|  | stabstr_D (int_size_in_bytes (type)); | 
|  | stabstr_S (";0;"); | 
|  | break; | 
|  |  | 
|  | case BOOLEAN_TYPE: | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_S ("@s"); | 
|  | stabstr_D (BITS_PER_UNIT * int_size_in_bytes (type)); | 
|  | stabstr_S (";-16;"); | 
|  | } | 
|  | else /* Define as enumeral type (False, True) */ | 
|  | stabstr_S ("eFalse:0,True:1,;"); | 
|  | break; | 
|  |  | 
|  | case COMPLEX_TYPE: | 
|  | /* Differs from the REAL_TYPE by its new data type number. | 
|  | R3 is NF_COMPLEX.  We don't try to use any of the other NF_* | 
|  | codes since gdb doesn't care anyway.  */ | 
|  |  | 
|  | if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE) | 
|  | { | 
|  | stabstr_S ("R3;"); | 
|  | stabstr_D (2 * int_size_in_bytes (TREE_TYPE (type))); | 
|  | stabstr_S (";0;"); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Output a complex integer type as a structure, | 
|  | pending some other way to do it.  */ | 
|  | stabstr_C ('s'); | 
|  | stabstr_D (int_size_in_bytes (type)); | 
|  |  | 
|  | stabstr_S ("real:"); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | stabstr_S (",0,"); | 
|  | stabstr_D (TYPE_PRECISION (TREE_TYPE (type))); | 
|  |  | 
|  | stabstr_S (";imag:"); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | stabstr_C (','); | 
|  | stabstr_D (TYPE_PRECISION (TREE_TYPE (type))); | 
|  | stabstr_C (','); | 
|  | stabstr_D (TYPE_PRECISION (TREE_TYPE (type))); | 
|  | stabstr_S (";;"); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ARRAY_TYPE: | 
|  | /* Make arrays of packed bits look like bitstrings for chill.  */ | 
|  | if (TYPE_PACKED (type) && use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_S ("@s"); | 
|  | stabstr_D (BITS_PER_UNIT * int_size_in_bytes (type)); | 
|  | stabstr_S (";@S;S"); | 
|  | dbxout_type (TYPE_DOMAIN (type), 0); | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Output "a" followed by a range type definition | 
|  | for the index type of the array | 
|  | followed by a reference to the target-type. | 
|  | ar1;0;N;M for a C array of type M and size N+1.  */ | 
|  | /* Check if a character string type, which in Chill is | 
|  | different from an array of characters.  */ | 
|  | if (TYPE_STRING_FLAG (type) && use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_S ("@S;"); | 
|  | } | 
|  | tem = TYPE_DOMAIN (type); | 
|  | if (tem == NULL) | 
|  | { | 
|  | stabstr_S ("ar"); | 
|  | dbxout_type_index (integer_type_node); | 
|  | stabstr_S (";0;-1;"); | 
|  | } | 
|  | else | 
|  | { | 
|  | stabstr_C ('a'); | 
|  | dbxout_range_type (tem, TYPE_MIN_VALUE (tem), TYPE_MAX_VALUE (tem)); | 
|  | } | 
|  |  | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | break; | 
|  |  | 
|  | case VECTOR_TYPE: | 
|  | /* Make vectors look like an array.  */ | 
|  | if (use_gnu_debug_info_extensions) | 
|  | stabstr_S ("@V;"); | 
|  |  | 
|  | /* Output "a" followed by a range type definition | 
|  | for the index type of the array | 
|  | followed by a reference to the target-type. | 
|  | ar1;0;N;M for a C array of type M and size N+1.  */ | 
|  | stabstr_C ('a'); | 
|  | dbxout_range_type (integer_type_node, size_zero_node, | 
|  | size_int (TYPE_VECTOR_SUBPARTS (type) - 1)); | 
|  |  | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | break; | 
|  |  | 
|  | case RECORD_TYPE: | 
|  | case UNION_TYPE: | 
|  | case QUAL_UNION_TYPE: | 
|  | { | 
|  | tree binfo = TYPE_BINFO (type); | 
|  |  | 
|  | /* Output a structure type.  We must use the same test here as we | 
|  | use in the DBX_NO_XREFS case above.  */ | 
|  | if ((TYPE_NAME (type) != 0 | 
|  | && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | 
|  | && DECL_IGNORED_P (TYPE_NAME (type))) | 
|  | && !full) | 
|  | || !COMPLETE_TYPE_P (type) | 
|  | /* No way in DBX fmt to describe a variable size.  */ | 
|  | || ! tree_fits_uhwi_p (TYPE_SIZE (type))) | 
|  | { | 
|  | /* If the type is just a cross reference, output one | 
|  | and mark the type as partially described. | 
|  | If it later becomes defined, we will output | 
|  | its real definition. | 
|  | If the type has a name, don't nest its definition within | 
|  | another type's definition; instead, output an xref | 
|  | and let the definition come when the name is defined.  */ | 
|  | stabstr_S ((TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu"); | 
|  | if (TYPE_IDENTIFIER (type)) | 
|  | { | 
|  | /* Note that the C frontend creates for anonymous variable | 
|  | length records/unions TYPE_NAME with DECL_NAME NULL.  */ | 
|  | dbxout_type_name (type); | 
|  | } | 
|  | else | 
|  | { | 
|  | stabstr_S ("$$"); | 
|  | stabstr_D (anonymous_type_number++); | 
|  | } | 
|  |  | 
|  | stabstr_C (':'); | 
|  | typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Identify record or union, and print its size.  */ | 
|  | stabstr_C ((TREE_CODE (type) == RECORD_TYPE) ? 's' : 'u'); | 
|  | stabstr_D (int_size_in_bytes (type)); | 
|  |  | 
|  | if (binfo) | 
|  | { | 
|  | int i; | 
|  | tree child; | 
|  | vec<tree, va_gc> *accesses = BINFO_BASE_ACCESSES (binfo); | 
|  |  | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | if (BINFO_N_BASE_BINFOS (binfo)) | 
|  | { | 
|  | stabstr_C ('!'); | 
|  | stabstr_U (BINFO_N_BASE_BINFOS (binfo)); | 
|  | stabstr_C (','); | 
|  | } | 
|  | } | 
|  | for (i = 0; BINFO_BASE_ITERATE (binfo, i, child); i++) | 
|  | { | 
|  | tree access = (accesses ? (*accesses)[i] : access_public_node); | 
|  |  | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_C (BINFO_VIRTUAL_P (child) ? '1' : '0'); | 
|  | stabstr_C (access == access_public_node ? '2' : | 
|  | access == access_protected_node | 
|  | ? '1' :'0'); | 
|  | if (BINFO_VIRTUAL_P (child) | 
|  | && (lang_GNU_CXX () | 
|  | || strcmp (lang_hooks.name, "GNU Objective-C++") == 0)) | 
|  | /* For a virtual base, print the (negative) | 
|  | offset within the vtable where we must look | 
|  | to find the necessary adjustment.  */ | 
|  | stabstr_D | 
|  | (tree_to_shwi (BINFO_VPTR_FIELD (child)) | 
|  | * BITS_PER_UNIT); | 
|  | else | 
|  | stabstr_D (tree_to_shwi (BINFO_OFFSET (child)) | 
|  | * BITS_PER_UNIT); | 
|  | stabstr_C (','); | 
|  | dbxout_type (BINFO_TYPE (child), 0); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Print out the base class information with | 
|  | fields which have the same names at the types | 
|  | they hold.  */ | 
|  | dbxout_type_name (BINFO_TYPE (child)); | 
|  | stabstr_C (':'); | 
|  | dbxout_type (BINFO_TYPE (child), full); | 
|  | stabstr_C (','); | 
|  | stabstr_D (tree_to_shwi (BINFO_OFFSET (child)) | 
|  | * BITS_PER_UNIT); | 
|  | stabstr_C (','); | 
|  | stabstr_D | 
|  | (tree_to_shwi (TYPE_SIZE (BINFO_TYPE (child))) | 
|  | * BITS_PER_UNIT); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Write out the field declarations.  */ | 
|  | dbxout_type_fields (type); | 
|  | if (use_gnu_debug_info_extensions) | 
|  | dbxout_type_methods (type); | 
|  |  | 
|  | stabstr_C (';'); | 
|  |  | 
|  | if (use_gnu_debug_info_extensions && TREE_CODE (type) == RECORD_TYPE | 
|  | /* Avoid the ~ if we don't really need it--it confuses dbx.  */ | 
|  | && TYPE_VFIELD (type)) | 
|  | { | 
|  |  | 
|  | /* We need to write out info about what field this class | 
|  | uses as its "main" vtable pointer field, because if this | 
|  | field is inherited from a base class, GDB cannot necessarily | 
|  | figure out which field it's using in time.  */ | 
|  | stabstr_S ("~%"); | 
|  | dbxout_type (DECL_FCONTEXT (TYPE_VFIELD (type)), 0); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ENUMERAL_TYPE: | 
|  | /* We must use the same test here as we use in the DBX_NO_XREFS case | 
|  | above.  We simplify it a bit since an enum will never have a variable | 
|  | size.  */ | 
|  | if ((TYPE_NAME (type) != 0 | 
|  | && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL | 
|  | && DECL_IGNORED_P (TYPE_NAME (type))) | 
|  | && !full) | 
|  | || !COMPLETE_TYPE_P (type)) | 
|  | { | 
|  | stabstr_S ("xe"); | 
|  | dbxout_type_name (type); | 
|  | typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; | 
|  | stabstr_C (':'); | 
|  | return; | 
|  | } | 
|  | if (use_gnu_debug_info_extensions | 
|  | && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) | 
|  | { | 
|  | stabstr_S ("@s"); | 
|  | stabstr_D (TYPE_PRECISION (type)); | 
|  | stabstr_C (';'); | 
|  | } | 
|  |  | 
|  | stabstr_C ('e'); | 
|  | for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) | 
|  | { | 
|  | tree value = TREE_VALUE (tem); | 
|  |  | 
|  | stabstr_I (TREE_PURPOSE (tem)); | 
|  | stabstr_C (':'); | 
|  |  | 
|  | if (TREE_CODE (value) == CONST_DECL) | 
|  | value = DECL_INITIAL (value); | 
|  |  | 
|  | if (cst_and_fits_in_hwi (value)) | 
|  | stabstr_D (TREE_INT_CST_LOW (value)); | 
|  | else | 
|  | stabstr_O (value); | 
|  |  | 
|  | stabstr_C (','); | 
|  | if (TREE_CHAIN (tem) != 0) | 
|  | CONTIN; | 
|  | } | 
|  |  | 
|  | stabstr_C (';'); | 
|  | break; | 
|  |  | 
|  | case POINTER_TYPE: | 
|  | stabstr_C ('*'); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | break; | 
|  |  | 
|  | case METHOD_TYPE: | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_C ('#'); | 
|  |  | 
|  | /* Write the argument types out longhand.  */ | 
|  | dbxout_type (TYPE_METHOD_BASETYPE (type), 0); | 
|  | stabstr_C (','); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | dbxout_args (TYPE_ARG_TYPES (type)); | 
|  | stabstr_C (';'); | 
|  | } | 
|  | else | 
|  | /* Treat it as a function type.  */ | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | break; | 
|  |  | 
|  | case OFFSET_TYPE: | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_C ('@'); | 
|  | dbxout_type (TYPE_OFFSET_BASETYPE (type), 0); | 
|  | stabstr_C (','); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | } | 
|  | else | 
|  | /* Should print as an int, because it is really just an offset.  */ | 
|  | dbxout_type (integer_type_node, 0); | 
|  | break; | 
|  |  | 
|  | case REFERENCE_TYPE: | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_C ('&'); | 
|  | } | 
|  | else | 
|  | stabstr_C ('*'); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | break; | 
|  |  | 
|  | case FUNCTION_TYPE: | 
|  | stabstr_C ('f'); | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | /* A C++ function with deduced return type can have a TEMPLATE_TYPE_PARM | 
|  | named 'auto' in its type. | 
|  | No debug info for TEMPLATE_TYPE_PARM type supported yet.  */ | 
|  | if (lang_GNU_CXX ()) | 
|  | { | 
|  | tree name = TYPE_IDENTIFIER (type); | 
|  | if (name == get_identifier ("auto") | 
|  | || name == get_identifier ("decltype(auto)")) | 
|  | break; | 
|  | } | 
|  |  | 
|  | gcc_unreachable (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Return nonzero if the given type represents an integer whose bounds | 
|  | should be printed in octal format.  */ | 
|  |  | 
|  | static bool | 
|  | print_int_cst_bounds_in_octal_p (tree type, tree low, tree high) | 
|  | { | 
|  | /* If we can use GDB extensions and the size is wider than a long | 
|  | (the size used by GDB to read them) or we may have trouble writing | 
|  | the bounds the usual way, write them in octal.  Note the test is for | 
|  | the *target's* size of "long", not that of the host.  The host test | 
|  | is just to make sure we can write it out in case the host wide int | 
|  | is narrower than the target "long". | 
|  |  | 
|  | For unsigned types, we use octal if they are the same size or larger. | 
|  | This is because we print the bounds as signed decimal, and hence they | 
|  | can't span same size unsigned types.  */ | 
|  |  | 
|  | if (use_gnu_debug_info_extensions | 
|  | && low && TREE_CODE (low) == INTEGER_CST | 
|  | && high && TREE_CODE (high) == INTEGER_CST | 
|  | && (TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node) | 
|  | || ((TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) | 
|  | && TYPE_UNSIGNED (type)) | 
|  | || TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT | 
|  | || (TYPE_PRECISION (type) == HOST_BITS_PER_WIDE_INT | 
|  | && TYPE_UNSIGNED (type)))) | 
|  | return TRUE; | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Output the name of type TYPE, with no punctuation. | 
|  | Such names can be set up either by typedef declarations | 
|  | or by struct, enum and union tags.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_type_name (tree type) | 
|  | { | 
|  | tree t = TYPE_NAME (type); | 
|  |  | 
|  | gcc_assert (t); | 
|  | switch (TREE_CODE (t)) | 
|  | { | 
|  | case IDENTIFIER_NODE: | 
|  | break; | 
|  | case TYPE_DECL: | 
|  | t = DECL_NAME (t); | 
|  | break; | 
|  | default: | 
|  | gcc_unreachable (); | 
|  | } | 
|  |  | 
|  | stabstr_I (t); | 
|  | } | 
|  |  | 
|  | /* Output leading struct or class names needed for qualifying type | 
|  | whose scope is limited to a struct or class.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_class_name_qualifiers (tree decl) | 
|  | { | 
|  | tree context = decl_type_context (decl); | 
|  |  | 
|  | if (context != NULL_TREE | 
|  | && TREE_CODE (context) == RECORD_TYPE | 
|  | && TYPE_NAME (context) != 0 | 
|  | && (TREE_CODE (TYPE_NAME (context)) == IDENTIFIER_NODE | 
|  | || (DECL_NAME (TYPE_NAME (context)) != 0))) | 
|  | { | 
|  | tree name = TYPE_NAME (context); | 
|  |  | 
|  | if (TREE_CODE (name) == TYPE_DECL) | 
|  | { | 
|  | dbxout_class_name_qualifiers (name); | 
|  | name = DECL_NAME (name); | 
|  | } | 
|  | stabstr_I (name); | 
|  | stabstr_S ("::"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This is a specialized subset of expand_expr for use by dbxout_symbol in | 
|  | evaluating DECL_VALUE_EXPR.  In particular, we stop if we find decls that | 
|  | haven't been expanded, or if the expression is getting so complex we won't | 
|  | be able to represent it in stabs anyway.  Returns NULL on failure.  */ | 
|  |  | 
|  | static rtx | 
|  | dbxout_expand_expr (tree expr) | 
|  | { | 
|  | switch (TREE_CODE (expr)) | 
|  | { | 
|  | case VAR_DECL: | 
|  | /* We can't handle emulated tls variables, because the address is an | 
|  | offset to the return value of __emutls_get_address, and there is no | 
|  | way to express that in stabs.  Also, there are name mangling issues | 
|  | here.  We end up with references to undefined symbols if we don't | 
|  | disable debug info for these variables.  */ | 
|  | if (!targetm.have_tls && DECL_THREAD_LOCAL_P (expr)) | 
|  | return NULL; | 
|  | if (TREE_STATIC (expr) | 
|  | && !TREE_ASM_WRITTEN (expr) | 
|  | && !DECL_HAS_VALUE_EXPR_P (expr) | 
|  | && !TREE_PUBLIC (expr) | 
|  | && DECL_RTL_SET_P (expr) | 
|  | && MEM_P (DECL_RTL (expr))) | 
|  | { | 
|  | /* If this is a var that might not be actually output, | 
|  | return NULL, otherwise stabs might reference an undefined | 
|  | symbol.  */ | 
|  | varpool_node *node = varpool_node::get (expr); | 
|  | if (!node || !node->definition) | 
|  | return NULL; | 
|  | } | 
|  | /* FALLTHRU */ | 
|  |  | 
|  | case PARM_DECL: | 
|  | case RESULT_DECL: | 
|  | if (DECL_HAS_VALUE_EXPR_P (expr)) | 
|  | return dbxout_expand_expr (DECL_VALUE_EXPR (expr)); | 
|  | /* FALLTHRU */ | 
|  |  | 
|  | case CONST_DECL: | 
|  | return DECL_RTL_IF_SET (expr); | 
|  |  | 
|  | case INTEGER_CST: | 
|  | return expand_expr (expr, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); | 
|  |  | 
|  | case COMPONENT_REF: | 
|  | case ARRAY_REF: | 
|  | case ARRAY_RANGE_REF: | 
|  | case BIT_FIELD_REF: | 
|  | { | 
|  | machine_mode mode; | 
|  | poly_int64 bitsize, bitpos; | 
|  | tree offset, tem; | 
|  | int unsignedp, reversep, volatilep = 0; | 
|  | rtx x; | 
|  |  | 
|  | tem = get_inner_reference (expr, &bitsize, &bitpos, &offset, &mode, | 
|  | &unsignedp, &reversep, &volatilep); | 
|  |  | 
|  | x = dbxout_expand_expr (tem); | 
|  | if (x == NULL || !MEM_P (x)) | 
|  | return NULL; | 
|  | if (offset != NULL) | 
|  | { | 
|  | if (!tree_fits_shwi_p (offset)) | 
|  | return NULL; | 
|  | x = adjust_address_nv (x, mode, tree_to_shwi (offset)); | 
|  | } | 
|  | if (maybe_ne (bitpos, 0)) | 
|  | x = adjust_address_nv (x, mode, bits_to_bytes_round_down (bitpos)); | 
|  |  | 
|  | return x; | 
|  | } | 
|  |  | 
|  | default: | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Helper function for output_used_types.  Queue one entry from the | 
|  | used types hash to be output.  */ | 
|  |  | 
|  | bool | 
|  | output_used_types_helper (tree const &type, vec<tree> *types_p) | 
|  | { | 
|  | if ((TREE_CODE (type) == RECORD_TYPE | 
|  | || TREE_CODE (type) == UNION_TYPE | 
|  | || TREE_CODE (type) == QUAL_UNION_TYPE | 
|  | || TREE_CODE (type) == ENUMERAL_TYPE) | 
|  | && TYPE_STUB_DECL (type) | 
|  | && DECL_P (TYPE_STUB_DECL (type)) | 
|  | && ! DECL_IGNORED_P (TYPE_STUB_DECL (type))) | 
|  | types_p->quick_push (TYPE_STUB_DECL (type)); | 
|  | else if (TYPE_NAME (type) | 
|  | && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) | 
|  | types_p->quick_push (TYPE_NAME (type)); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* This is a qsort callback which sorts types and declarations into a | 
|  | predictable order (types, then declarations, sorted by UID | 
|  | within).  */ | 
|  |  | 
|  | static int | 
|  | output_types_sort (const void *pa, const void *pb) | 
|  | { | 
|  | const tree lhs = *((const tree *)pa); | 
|  | const tree rhs = *((const tree *)pb); | 
|  |  | 
|  | if (TYPE_P (lhs)) | 
|  | { | 
|  | if (TYPE_P (rhs)) | 
|  | return TYPE_UID (lhs) - TYPE_UID (rhs); | 
|  | else | 
|  | return 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (TYPE_P (rhs)) | 
|  | return -1; | 
|  | else | 
|  | return DECL_UID (lhs) - DECL_UID (rhs); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Force all types used by this function to be output in debug | 
|  | information.  */ | 
|  |  | 
|  | static void | 
|  | output_used_types (void) | 
|  | { | 
|  | if (cfun && cfun->used_types_hash) | 
|  | { | 
|  | vec<tree> types; | 
|  | int i; | 
|  | tree type; | 
|  |  | 
|  | types.create (cfun->used_types_hash->elements ()); | 
|  | cfun->used_types_hash->traverse<vec<tree> *, output_used_types_helper> | 
|  | (&types); | 
|  |  | 
|  | /* Sort by UID to prevent dependence on hash table ordering.  */ | 
|  | types.qsort (output_types_sort); | 
|  |  | 
|  | FOR_EACH_VEC_ELT (types, i, type) | 
|  | debug_queue_symbol (type); | 
|  |  | 
|  | types.release (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Output a .stabs for the symbol defined by DECL, | 
|  | which must be a ..._DECL node in the normal namespace. | 
|  | It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL. | 
|  | LOCAL is nonzero if the scope is less than the entire file. | 
|  | Return 1 if a stabs might have been emitted.  */ | 
|  |  | 
|  | int | 
|  | dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) | 
|  | { | 
|  | tree type = TREE_TYPE (decl); | 
|  | tree context = NULL_TREE; | 
|  | int result = 0; | 
|  | rtx decl_rtl; | 
|  |  | 
|  | /* "Intercept" dbxout_symbol() calls like we do all debug_hooks.  */ | 
|  | ++debug_nesting; | 
|  |  | 
|  | /* Ignore nameless syms, but don't ignore type tags.  */ | 
|  |  | 
|  | if ((DECL_NAME (decl) == 0 && TREE_CODE (decl) != TYPE_DECL) | 
|  | || DECL_IGNORED_P (decl)) | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  |  | 
|  | /* If we are to generate only the symbols actually used then such | 
|  | symbol nodes are flagged with TREE_USED.  Ignore any that | 
|  | aren't flagged as TREE_USED.  */ | 
|  |  | 
|  | if (flag_debug_only_used_symbols | 
|  | && (!TREE_USED (decl) | 
|  | && (!VAR_P (decl) || !DECL_INITIAL (decl)))) | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  |  | 
|  | /* If dbxout_init has not yet run, queue this symbol for later.  */ | 
|  | if (!typevec) | 
|  | { | 
|  | preinit_symbols = tree_cons (0, decl, preinit_symbols); | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  | } | 
|  |  | 
|  | if (flag_debug_only_used_symbols) | 
|  | { | 
|  | tree t; | 
|  |  | 
|  | /* We now have a used symbol.  We need to generate the info for | 
|  | the symbol's type in addition to the symbol itself.  These | 
|  | type symbols are queued to be generated after were done with | 
|  | the symbol itself (otherwise they would fight over the | 
|  | stabstr obstack). | 
|  |  | 
|  | Note, because the TREE_TYPE(type) might be something like a | 
|  | pointer to a named type we need to look for the first name | 
|  | we see following the TREE_TYPE chain.  */ | 
|  |  | 
|  | t = type; | 
|  | while (POINTER_TYPE_P (t)) | 
|  | t = TREE_TYPE (t); | 
|  |  | 
|  | /* RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE, and ENUMERAL_TYPE | 
|  | need special treatment.  The TYPE_STUB_DECL field in these | 
|  | types generally represents the tag name type we want to | 
|  | output.  In addition there  could be a typedef type with | 
|  | a different name.  In that case we also want to output | 
|  | that.  */ | 
|  |  | 
|  | if (TREE_CODE (t) == RECORD_TYPE | 
|  | || TREE_CODE (t) == UNION_TYPE | 
|  | || TREE_CODE (t) == QUAL_UNION_TYPE | 
|  | || TREE_CODE (t) == ENUMERAL_TYPE) | 
|  | { | 
|  | if (TYPE_STUB_DECL (t) | 
|  | && TYPE_STUB_DECL (t) != decl | 
|  | && DECL_P (TYPE_STUB_DECL (t)) | 
|  | && ! DECL_IGNORED_P (TYPE_STUB_DECL (t))) | 
|  | { | 
|  | debug_queue_symbol (TYPE_STUB_DECL (t)); | 
|  | if (TYPE_NAME (t) | 
|  | && TYPE_NAME (t) != TYPE_STUB_DECL (t) | 
|  | && TYPE_NAME (t) != decl | 
|  | && DECL_P (TYPE_NAME (t))) | 
|  | debug_queue_symbol (TYPE_NAME (t)); | 
|  | } | 
|  | } | 
|  | else if (TYPE_NAME (t) | 
|  | && TYPE_NAME (t) != decl | 
|  | && DECL_P (TYPE_NAME (t))) | 
|  | debug_queue_symbol (TYPE_NAME (t)); | 
|  | } | 
|  |  | 
|  | emit_pending_bincls_if_required (); | 
|  |  | 
|  | switch (TREE_CODE (decl)) | 
|  | { | 
|  | case CONST_DECL: | 
|  | /* Enum values are defined by defining the enum type.  */ | 
|  | break; | 
|  |  | 
|  | case FUNCTION_DECL: | 
|  | decl_rtl = DECL_RTL_IF_SET (decl); | 
|  | if (!decl_rtl) | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  | if (DECL_EXTERNAL (decl)) | 
|  | break; | 
|  | /* Don't mention a nested function under its parent.  */ | 
|  | context = decl_function_context (decl); | 
|  | if (context == current_function_decl) | 
|  | break; | 
|  | /* Don't mention an inline instance of a nested function.  */ | 
|  | if (context && DECL_FROM_INLINE (decl)) | 
|  | break; | 
|  | if (!MEM_P (decl_rtl) | 
|  | || GET_CODE (XEXP (decl_rtl, 0)) != SYMBOL_REF) | 
|  | break; | 
|  |  | 
|  | if (flag_debug_only_used_symbols) | 
|  | output_used_types (); | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  | stabstr_I (DECL_ASSEMBLER_NAME (decl)); | 
|  | stabstr_S (TREE_PUBLIC (decl) ? ":F" : ":f"); | 
|  | result = 1; | 
|  |  | 
|  | if (TREE_TYPE (type)) | 
|  | dbxout_type (TREE_TYPE (type), 0); | 
|  | else | 
|  | dbxout_type (void_type_node, 0); | 
|  |  | 
|  | /* For a nested function, when that function is compiled, | 
|  | mention the containing function name | 
|  | as well as (since dbx wants it) our own assembler-name.  */ | 
|  | if (context != 0) | 
|  | { | 
|  | stabstr_C (','); | 
|  | stabstr_I (DECL_ASSEMBLER_NAME (decl)); | 
|  | stabstr_C (','); | 
|  | stabstr_I (DECL_NAME (context)); | 
|  | } | 
|  |  | 
|  | dbxout_finish_complex_stabs (decl, N_FUN, XEXP (decl_rtl, 0), 0, 0); | 
|  | break; | 
|  |  | 
|  | case TYPE_DECL: | 
|  | /* Don't output the same typedef twice. | 
|  | And don't output what language-specific stuff doesn't want output.  */ | 
|  | if (TREE_ASM_WRITTEN (decl) || TYPE_DECL_SUPPRESS_DEBUG (decl)) | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  |  | 
|  | /* Don't output typedefs for types with magic type numbers (XCOFF).  */ | 
|  | #ifdef DBX_ASSIGN_FUNDAMENTAL_TYPE_NUMBER | 
|  | { | 
|  | int fundamental_type_number = | 
|  | DBX_ASSIGN_FUNDAMENTAL_TYPE_NUMBER (decl); | 
|  |  | 
|  | if (fundamental_type_number != 0) | 
|  | { | 
|  | TREE_ASM_WRITTEN (decl) = 1; | 
|  | TYPE_SYMTAB_ADDRESS (TREE_TYPE (decl)) = fundamental_type_number; | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | FORCE_TEXT; | 
|  | result = 1; | 
|  | { | 
|  | int tag_needed = 1; | 
|  | int did_output = 0; | 
|  |  | 
|  | if (DECL_NAME (decl)) | 
|  | { | 
|  | /* Nonzero means we must output a tag as well as a typedef.  */ | 
|  | tag_needed = 0; | 
|  |  | 
|  | /* Handle the case of a C++ structure or union | 
|  | where the TYPE_NAME is a TYPE_DECL | 
|  | which gives both a typedef name and a tag.  */ | 
|  | /* dbx requires the tag first and the typedef second.  */ | 
|  | if ((TREE_CODE (type) == RECORD_TYPE | 
|  | || TREE_CODE (type) == UNION_TYPE | 
|  | || TREE_CODE (type) == QUAL_UNION_TYPE) | 
|  | && TYPE_NAME (type) == decl | 
|  | && !use_gnu_debug_info_extensions | 
|  | && !TREE_ASM_WRITTEN (TYPE_NAME (type)) | 
|  | /* Distinguish the implicit typedefs of C++ | 
|  | from explicit ones that might be found in C.  */ | 
|  | && DECL_ARTIFICIAL (decl) | 
|  | /* Do not generate a tag for incomplete records.  */ | 
|  | && COMPLETE_TYPE_P (type) | 
|  | /* Do not generate a tag for records of variable size, | 
|  | since this type cannot be properly described in the | 
|  | DBX format, and it confuses some tools such as objdump.  */ | 
|  | && tree_fits_uhwi_p (TYPE_SIZE (type))) | 
|  | { | 
|  | tree name = TYPE_IDENTIFIER (type); | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  | stabstr_I (name); | 
|  | stabstr_S (":T"); | 
|  | dbxout_type (type, 1); | 
|  | dbxout_finish_complex_stabs (0, DBX_TYPE_DECL_STABS_CODE, | 
|  | 0, 0, 0); | 
|  | } | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  |  | 
|  | /* Output leading class/struct qualifiers.  */ | 
|  | if (use_gnu_debug_info_extensions) | 
|  | dbxout_class_name_qualifiers (decl); | 
|  |  | 
|  | /* Output typedef name.  */ | 
|  | stabstr_I (DECL_NAME (decl)); | 
|  | stabstr_C (':'); | 
|  |  | 
|  | /* Short cut way to output a tag also.  */ | 
|  | if ((TREE_CODE (type) == RECORD_TYPE | 
|  | || TREE_CODE (type) == UNION_TYPE | 
|  | || TREE_CODE (type) == QUAL_UNION_TYPE) | 
|  | && TYPE_NAME (type) == decl | 
|  | /* Distinguish the implicit typedefs of C++ | 
|  | from explicit ones that might be found in C.  */ | 
|  | && DECL_ARTIFICIAL (decl)) | 
|  | { | 
|  | if (use_gnu_debug_info_extensions) | 
|  | { | 
|  | stabstr_C ('T'); | 
|  | TREE_ASM_WRITTEN (TYPE_NAME (type)) = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | stabstr_C ('t'); | 
|  | dbxout_type (type, 1); | 
|  | dbxout_finish_complex_stabs (decl, DBX_TYPE_DECL_STABS_CODE, | 
|  | 0, 0, 0); | 
|  | did_output = 1; | 
|  | } | 
|  |  | 
|  | /* Don't output a tag if this is an incomplete type.  This prevents | 
|  | the sun4 Sun OS 4.x dbx from crashing.  */ | 
|  |  | 
|  | if (tag_needed && TYPE_NAME (type) != 0 | 
|  | && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE | 
|  | || (DECL_NAME (TYPE_NAME (type)) != 0)) | 
|  | && COMPLETE_TYPE_P (type) | 
|  | && !TREE_ASM_WRITTEN (TYPE_NAME (type))) | 
|  | { | 
|  | /* For a TYPE_DECL with no name, but the type has a name, | 
|  | output a tag. | 
|  | This is what represents `struct foo' with no typedef.  */ | 
|  | /* In C++, the name of a type is the corresponding typedef. | 
|  | In C, it is an IDENTIFIER_NODE.  */ | 
|  | tree name = TYPE_IDENTIFIER (type); | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  | stabstr_I (name); | 
|  | stabstr_S (":T"); | 
|  | dbxout_type (type, 1); | 
|  | dbxout_finish_complex_stabs (0, DBX_TYPE_DECL_STABS_CODE, 0, 0, 0); | 
|  | did_output = 1; | 
|  | } | 
|  |  | 
|  | /* If an enum type has no name, it cannot be referred to, but | 
|  | we must output it anyway, to record the enumeration | 
|  | constants.  */ | 
|  |  | 
|  | if (!did_output && TREE_CODE (type) == ENUMERAL_TYPE) | 
|  | { | 
|  | dbxout_begin_complex_stabs (); | 
|  | /* Some debuggers fail when given NULL names, so give this a | 
|  | harmless name of " " (Why not "(anon)"?).  */ | 
|  | stabstr_S (" :T"); | 
|  | dbxout_type (type, 1); | 
|  | dbxout_finish_complex_stabs (0, DBX_TYPE_DECL_STABS_CODE, 0, 0, 0); | 
|  | } | 
|  |  | 
|  | /* Prevent duplicate output of a typedef.  */ | 
|  | TREE_ASM_WRITTEN (decl) = 1; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case PARM_DECL: | 
|  | if (DECL_HAS_VALUE_EXPR_P (decl)) | 
|  | decl = DECL_VALUE_EXPR (decl); | 
|  |  | 
|  | /* PARM_DECLs go in their own separate chain and are output by | 
|  | dbxout_reg_parms and dbxout_parms, except for those that are | 
|  | disguised VAR_DECLs like Out parameters in Ada.  */ | 
|  | gcc_assert (VAR_P (decl)); | 
|  |  | 
|  | /* fall through */ | 
|  |  | 
|  | case RESULT_DECL: | 
|  | case VAR_DECL: | 
|  | /* Don't mention a variable that is external. | 
|  | Let the file that defines it describe it.  */ | 
|  | if (DECL_EXTERNAL (decl)) | 
|  | break; | 
|  |  | 
|  | /* If the variable is really a constant | 
|  | and not written in memory, inform the debugger. | 
|  |  | 
|  | ??? Why do we skip emitting the type and location in this case?  */ | 
|  | if (TREE_STATIC (decl) && TREE_READONLY (decl) | 
|  | && DECL_INITIAL (decl) != 0 | 
|  | && tree_fits_shwi_p (DECL_INITIAL (decl)) | 
|  | && ! TREE_ASM_WRITTEN (decl) | 
|  | && (DECL_FILE_SCOPE_P (decl) | 
|  | || TREE_CODE (DECL_CONTEXT (decl)) == BLOCK | 
|  | || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL) | 
|  | && TREE_PUBLIC (decl) == 0) | 
|  | { | 
|  | /* The sun4 assembler does not grok this.  */ | 
|  |  | 
|  | if (TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE | 
|  | || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) | 
|  | { | 
|  | HOST_WIDE_INT ival = tree_to_shwi (DECL_INITIAL (decl)); | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  | dbxout_symbol_name (decl, NULL, 'c'); | 
|  | stabstr_S ("=i"); | 
|  | stabstr_D (ival); | 
|  | dbxout_finish_complex_stabs (0, N_LSYM, 0, 0, 0); | 
|  | DBXOUT_DECR_NESTING; | 
|  | return 1; | 
|  | } | 
|  | else | 
|  | break; | 
|  | } | 
|  | /* else it is something we handle like a normal variable.  */ | 
|  |  | 
|  | decl_rtl = dbxout_expand_expr (decl); | 
|  | if (!decl_rtl) | 
|  | DBXOUT_DECR_NESTING_AND_RETURN (0); | 
|  |  | 
|  | if (!is_global_var (decl)) | 
|  | decl_rtl = eliminate_regs (decl_rtl, VOIDmode, NULL_RTX); | 
|  | #ifdef LEAF_REG_REMAP | 
|  | if (crtl->uses_only_leaf_regs) | 
|  | leaf_renumber_regs_insn (decl_rtl); | 
|  | #endif | 
|  |  | 
|  | result = dbxout_symbol_location (decl, type, 0, decl_rtl); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  | DBXOUT_DECR_NESTING; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Output the stab for DECL, a VAR_DECL, RESULT_DECL or PARM_DECL. | 
|  | Add SUFFIX to its name, if SUFFIX is not 0. | 
|  | Describe the variable as residing in HOME | 
|  | (usually HOME is DECL_RTL (DECL), but not always). | 
|  | Returns 1 if the stab was really emitted.  */ | 
|  |  | 
|  | static int | 
|  | dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) | 
|  | { | 
|  | int letter = 0; | 
|  | stab_code_type code; | 
|  | rtx addr = 0; | 
|  | int number = 0; | 
|  | int regno = -1; | 
|  |  | 
|  | /* Don't mention a variable at all | 
|  | if it was completely optimized into nothingness. | 
|  |  | 
|  | If the decl was from an inline function, then its rtl | 
|  | is not identically the rtl that was used in this | 
|  | particular compilation.  */ | 
|  | if (GET_CODE (home) == SUBREG) | 
|  | { | 
|  | rtx value = home; | 
|  |  | 
|  | while (GET_CODE (value) == SUBREG) | 
|  | value = SUBREG_REG (value); | 
|  | if (REG_P (value)) | 
|  | { | 
|  | if (REGNO (value) >= FIRST_PSEUDO_REGISTER) | 
|  | return 0; | 
|  | } | 
|  | home = alter_subreg (&home, true); | 
|  | } | 
|  | if (REG_P (home)) | 
|  | { | 
|  | regno = REGNO (home); | 
|  | if (regno >= FIRST_PSEUDO_REGISTER) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* The kind-of-variable letter depends on where | 
|  | the variable is and on the scope of its name: | 
|  | G and N_GSYM for static storage and global scope, | 
|  | S for static storage and file scope, | 
|  | V for static storage and local scope, | 
|  | for those two, use N_LCSYM if data is in bss segment, | 
|  | N_STSYM if in data segment, N_FUN otherwise. | 
|  | (We used N_FUN originally, then changed to N_STSYM | 
|  | to please GDB.  However, it seems that confused ld. | 
|  | Now GDB has been fixed to like N_FUN, says Kingdon.) | 
|  | no letter at all, and N_LSYM, for auto variable, | 
|  | r and N_RSYM for register variable.  */ | 
|  |  | 
|  | if (MEM_P (home) && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) | 
|  | { | 
|  | if (TREE_PUBLIC (decl)) | 
|  | { | 
|  | int offs; | 
|  | letter = 'G'; | 
|  | code = N_GSYM; | 
|  | if (dbxout_common_check (decl, &offs) != NULL) | 
|  | { | 
|  | letter = 'V'; | 
|  | addr = 0; | 
|  | number = offs; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | addr = XEXP (home, 0); | 
|  |  | 
|  | letter = decl_function_context (decl) ? 'V' : 'S'; | 
|  |  | 
|  | /* Some ports can transform a symbol ref into a label ref, | 
|  | because the symbol ref is too far away and has to be | 
|  | dumped into a constant pool.  Alternatively, the symbol | 
|  | in the constant pool might be referenced by a different | 
|  | symbol.  */ | 
|  | if (GET_CODE (addr) == SYMBOL_REF | 
|  | && CONSTANT_POOL_ADDRESS_P (addr)) | 
|  | { | 
|  | bool marked; | 
|  | rtx tmp = get_pool_constant_mark (addr, &marked); | 
|  |  | 
|  | if (GET_CODE (tmp) == SYMBOL_REF) | 
|  | { | 
|  | addr = tmp; | 
|  | if (CONSTANT_POOL_ADDRESS_P (addr)) | 
|  | get_pool_constant_mark (addr, &marked); | 
|  | else | 
|  | marked = true; | 
|  | } | 
|  | else if (GET_CODE (tmp) == LABEL_REF) | 
|  | { | 
|  | addr = tmp; | 
|  | marked = true; | 
|  | } | 
|  |  | 
|  | /* If all references to the constant pool were optimized | 
|  | out, we just ignore the symbol.  */ | 
|  | if (!marked) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* This should be the same condition as in assemble_variable, but | 
|  | we don't have access to dont_output_data here.  So, instead, | 
|  | we rely on the fact that error_mark_node initializers always | 
|  | end up in bss for C++ and never end up in bss for C.  */ | 
|  | if (DECL_INITIAL (decl) == 0 | 
|  | || (lang_GNU_CXX () | 
|  | && DECL_INITIAL (decl) == error_mark_node)) | 
|  | { | 
|  | int offs; | 
|  | code = N_LCSYM; | 
|  | if (dbxout_common_check (decl, &offs) != NULL) | 
|  | { | 
|  | addr = 0; | 
|  | number = offs; | 
|  | letter = 'V'; | 
|  | code = N_GSYM; | 
|  | } | 
|  | } | 
|  | else if (DECL_IN_TEXT_SECTION (decl)) | 
|  | /* This is not quite right, but it's the closest | 
|  | of all the codes that Unix defines.  */ | 
|  | code = DBX_STATIC_CONST_VAR_CODE; | 
|  | else | 
|  | { | 
|  | /* Ultrix `as' seems to need this.  */ | 
|  | #ifdef DBX_STATIC_STAB_DATA_SECTION | 
|  | switch_to_section (data_section); | 
|  | #endif | 
|  | code = N_STSYM; | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (regno >= 0) | 
|  | { | 
|  | letter = 'r'; | 
|  | code = N_RSYM; | 
|  | number = DBX_REGISTER_NUMBER (regno); | 
|  | } | 
|  | else if (MEM_P (home) | 
|  | && (MEM_P (XEXP (home, 0)) | 
|  | || (REG_P (XEXP (home, 0)) | 
|  | && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM | 
|  | && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM | 
|  | #if !HARD_FRAME_POINTER_IS_ARG_POINTER | 
|  | && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM | 
|  | #endif | 
|  | ))) | 
|  | /* If the value is indirect by memory or by a register | 
|  | that isn't the frame pointer | 
|  | then it means the object is variable-sized and address through | 
|  | that register or stack slot.  DBX has no way to represent this | 
|  | so all we can do is output the variable as a pointer. | 
|  | If it's not a parameter, ignore it.  */ | 
|  | { | 
|  | if (REG_P (XEXP (home, 0))) | 
|  | { | 
|  | letter = 'r'; | 
|  | code = N_RSYM; | 
|  | if (REGNO (XEXP (home, 0)) >= FIRST_PSEUDO_REGISTER) | 
|  | return 0; | 
|  | number = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0))); | 
|  | } | 
|  | else | 
|  | { | 
|  | code = N_LSYM; | 
|  | /* RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). | 
|  | We want the value of that CONST_INT.  */ | 
|  | number = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0)); | 
|  | } | 
|  |  | 
|  | /* Effectively do build_pointer_type, but don't cache this type, | 
|  | since it might be temporary whereas the type it points to | 
|  | might have been saved for inlining.  */ | 
|  | /* Don't use REFERENCE_TYPE because dbx can't handle that.  */ | 
|  | type = make_node (POINTER_TYPE); | 
|  | TREE_TYPE (type) = TREE_TYPE (decl); | 
|  | } | 
|  | else if (MEM_P (home) | 
|  | && REG_P (XEXP (home, 0))) | 
|  | { | 
|  | code = N_LSYM; | 
|  | number = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); | 
|  | } | 
|  | else if (MEM_P (home) | 
|  | && GET_CODE (XEXP (home, 0)) == PLUS | 
|  | && CONST_INT_P (XEXP (XEXP (home, 0), 1))) | 
|  | { | 
|  | code = N_LSYM; | 
|  | /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) | 
|  | We want the value of that CONST_INT.  */ | 
|  | number = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); | 
|  | } | 
|  | else if (MEM_P (home) | 
|  | && GET_CODE (XEXP (home, 0)) == CONST) | 
|  | { | 
|  | /* Handle an obscure case which can arise when optimizing and | 
|  | when there are few available registers.  (This is *always* | 
|  | the case for i386/i486 targets).  The RTL looks like | 
|  | (MEM (CONST ...)) even though this variable is a local `auto' | 
|  | or a local `register' variable.  In effect, what has happened | 
|  | is that the reload pass has seen that all assignments and | 
|  | references for one such a local variable can be replaced by | 
|  | equivalent assignments and references to some static storage | 
|  | variable, thereby avoiding the need for a register.  In such | 
|  | cases we're forced to lie to debuggers and tell them that | 
|  | this variable was itself `static'.  */ | 
|  | int offs; | 
|  | code = N_LCSYM; | 
|  | letter = 'V'; | 
|  | if (dbxout_common_check (decl, &offs) == NULL) | 
|  | addr = XEXP (XEXP (home, 0), 0); | 
|  | else | 
|  | { | 
|  | addr = 0; | 
|  | number = offs; | 
|  | code = N_GSYM; | 
|  | } | 
|  | } | 
|  | else if (GET_CODE (home) == CONCAT) | 
|  | { | 
|  | tree subtype; | 
|  |  | 
|  | /* If TYPE is not a COMPLEX_TYPE (it might be a RECORD_TYPE, | 
|  | for example), then there is no easy way to figure out | 
|  | what SUBTYPE should be.  So, we give up.  */ | 
|  | if (TREE_CODE (type) != COMPLEX_TYPE) | 
|  | return 0; | 
|  |  | 
|  | subtype = TREE_TYPE (type); | 
|  |  | 
|  | /* If the variable's storage is in two parts, | 
|  | output each as a separate stab with a modified name.  */ | 
|  | if (WORDS_BIG_ENDIAN) | 
|  | dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 0)); | 
|  | else | 
|  | dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0)); | 
|  |  | 
|  | if (WORDS_BIG_ENDIAN) | 
|  | dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1)); | 
|  | else | 
|  | dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 1)); | 
|  | return 1; | 
|  | } | 
|  | else | 
|  | /* Address might be a MEM, when DECL is a variable-sized object. | 
|  | Or it might be const0_rtx, meaning previous passes | 
|  | want us to ignore this variable.  */ | 
|  | return 0; | 
|  |  | 
|  | /* Ok, start a symtab entry and output the variable name.  */ | 
|  | emit_pending_bincls_if_required (); | 
|  | FORCE_TEXT; | 
|  |  | 
|  | #ifdef DBX_STATIC_BLOCK_START | 
|  | DBX_STATIC_BLOCK_START (asm_out_file, code); | 
|  | #endif | 
|  |  | 
|  | dbxout_begin_complex_stabs_noforcetext (); | 
|  | dbxout_symbol_name (decl, suffix, letter); | 
|  | dbxout_type (type, 0); | 
|  | dbxout_finish_complex_stabs (decl, code, addr, 0, number); | 
|  |  | 
|  | #ifdef DBX_STATIC_BLOCK_END | 
|  | DBX_STATIC_BLOCK_END (asm_out_file, code); | 
|  | #endif | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Output the symbol name of DECL for a stabs, with suffix SUFFIX. | 
|  | Then output LETTER to indicate the kind of location the symbol has.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_symbol_name (tree decl, const char *suffix, int letter) | 
|  | { | 
|  | tree name; | 
|  |  | 
|  | if (DECL_CONTEXT (decl) | 
|  | && (TYPE_P (DECL_CONTEXT (decl)) | 
|  | || TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)) | 
|  | /* One slight hitch: if this is a VAR_DECL which is a class member | 
|  | or a namespace member, we must put out the mangled name instead of the | 
|  | DECL_NAME.  Note also that static member (variable) names DO NOT begin | 
|  | with underscores in .stabs directives.  */ | 
|  | name = DECL_ASSEMBLER_NAME (decl); | 
|  | else | 
|  | /* ...but if we're function-local, we don't want to include the junk | 
|  | added by ASM_FORMAT_PRIVATE_NAME.  */ | 
|  | name = DECL_NAME (decl); | 
|  |  | 
|  | if (name) | 
|  | stabstr_I (name); | 
|  | else | 
|  | stabstr_S ("(anon)"); | 
|  |  | 
|  | if (suffix) | 
|  | stabstr_S (suffix); | 
|  | stabstr_C (':'); | 
|  | if (letter) | 
|  | stabstr_C (letter); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Output the common block name for DECL in a stabs. | 
|  |  | 
|  | Symbols in global common (.comm) get wrapped with an N_BCOMM/N_ECOMM pair | 
|  | around each group of symbols in the same .comm area.  The N_GSYM stabs | 
|  | that are emitted only contain the offset in the common area.  This routine | 
|  | emits the N_BCOMM and N_ECOMM stabs.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_common_name (tree decl, const char *name, stab_code_type op) | 
|  | { | 
|  | dbxout_begin_complex_stabs (); | 
|  | stabstr_S (name); | 
|  | dbxout_finish_complex_stabs (decl, op, NULL_RTX, NULL, 0); | 
|  | } | 
|  |  | 
|  | /* Check decl to determine whether it is a VAR_DECL destined for storage in a | 
|  | common area.  If it is, the return value will be a non-null string giving | 
|  | the name of the common storage block it will go into.  If non-null, the | 
|  | value is the offset into the common block for that symbol's storage.  */ | 
|  |  | 
|  | static const char * | 
|  | dbxout_common_check (tree decl, int *value) | 
|  | { | 
|  | rtx home; | 
|  | rtx sym_addr; | 
|  | const char *name = NULL; | 
|  |  | 
|  | /* If the decl isn't a VAR_DECL, or if it isn't static, or if | 
|  | it does not have a value (the offset into the common area), or if it | 
|  | is thread local (as opposed to global) then it isn't common, and shouldn't | 
|  | be handled as such. | 
|  |  | 
|  | ??? DECL_THREAD_LOCAL_P check prevents problems with improper .stabs | 
|  | for thread-local symbols.  Can be handled via same mechanism as used | 
|  | in dwarf2out.cc.  */ | 
|  | if (!VAR_P (decl) | 
|  | || !TREE_STATIC (decl) | 
|  | || !DECL_HAS_VALUE_EXPR_P (decl) | 
|  | || DECL_THREAD_LOCAL_P (decl) | 
|  | || !is_fortran ()) | 
|  | return NULL; | 
|  |  | 
|  | home = DECL_RTL (decl); | 
|  | if (home == NULL_RTX || GET_CODE (home) != MEM) | 
|  | return NULL; | 
|  |  | 
|  | sym_addr = dbxout_expand_expr (DECL_VALUE_EXPR (decl)); | 
|  | if (sym_addr == NULL_RTX || GET_CODE (sym_addr) != MEM) | 
|  | return NULL; | 
|  |  | 
|  | sym_addr = XEXP (sym_addr, 0); | 
|  | if (GET_CODE (sym_addr) == CONST) | 
|  | sym_addr = XEXP (sym_addr, 0); | 
|  | if ((GET_CODE (sym_addr) == SYMBOL_REF || GET_CODE (sym_addr) == PLUS) | 
|  | && DECL_INITIAL (decl) == 0) | 
|  | { | 
|  |  | 
|  | /* We have a sym that will go into a common area, meaning that it | 
|  | will get storage reserved with a .comm/.lcomm assembler pseudo-op. | 
|  |  | 
|  | Determine name of common area this symbol will be an offset into, | 
|  | and offset into that area.  Also retrieve the decl for the area | 
|  | that the symbol is offset into.  */ | 
|  | tree cdecl = NULL; | 
|  |  | 
|  | switch (GET_CODE (sym_addr)) | 
|  | { | 
|  | case PLUS: | 
|  | if (CONST_INT_P (XEXP (sym_addr, 0))) | 
|  | { | 
|  | name = | 
|  | targetm.strip_name_encoding (XSTR (XEXP (sym_addr, 1), 0)); | 
|  | *value = INTVAL (XEXP (sym_addr, 0)); | 
|  | cdecl = SYMBOL_REF_DECL (XEXP (sym_addr, 1)); | 
|  | } | 
|  | else | 
|  | { | 
|  | name = | 
|  | targetm.strip_name_encoding (XSTR (XEXP (sym_addr, 0), 0)); | 
|  | *value = INTVAL (XEXP (sym_addr, 1)); | 
|  | cdecl = SYMBOL_REF_DECL (XEXP (sym_addr, 0)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case SYMBOL_REF: | 
|  | name = targetm.strip_name_encoding (XSTR (sym_addr, 0)); | 
|  | *value = 0; | 
|  | cdecl = SYMBOL_REF_DECL (sym_addr); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | error ("common symbol debug info is not structured as " | 
|  | "symbol+offset"); | 
|  | } | 
|  |  | 
|  | /* Check area common symbol is offset into.  If this is not public, then | 
|  | it is not a symbol in a common block.  It must be a .lcomm symbol, not | 
|  | a .comm symbol.  */ | 
|  | if (cdecl == NULL || !TREE_PUBLIC (cdecl)) | 
|  | name = NULL; | 
|  | } | 
|  | else | 
|  | name = NULL; | 
|  |  | 
|  | return name; | 
|  | } | 
|  |  | 
|  | /* Output definitions of all the decls in a chain. Return nonzero if | 
|  | anything was output */ | 
|  |  | 
|  | int | 
|  | dbxout_syms (tree syms) | 
|  | { | 
|  | int result = 0; | 
|  | const char *comm_prev = NULL; | 
|  | tree syms_prev = NULL; | 
|  |  | 
|  | while (syms) | 
|  | { | 
|  | int temp, copen, cclos; | 
|  | const char *comm_new; | 
|  |  | 
|  | /* Check for common symbol, and then progression into a new/different | 
|  | block of common symbols.  Emit closing/opening common bracket if | 
|  | necessary.  */ | 
|  | comm_new = dbxout_common_check (syms, &temp); | 
|  | copen = comm_new != NULL | 
|  | && (comm_prev == NULL || strcmp (comm_new, comm_prev)); | 
|  | cclos = comm_prev != NULL | 
|  | && (comm_new == NULL || strcmp (comm_new, comm_prev)); | 
|  | if (cclos) | 
|  | dbxout_common_name (syms_prev, comm_prev, N_ECOMM); | 
|  | if (copen) | 
|  | { | 
|  | dbxout_common_name (syms, comm_new, N_BCOMM); | 
|  | syms_prev = syms; | 
|  | } | 
|  | comm_prev = comm_new; | 
|  |  | 
|  | result += dbxout_symbol (syms, 1); | 
|  | syms = DECL_CHAIN (syms); | 
|  | } | 
|  |  | 
|  | if (comm_prev != NULL) | 
|  | dbxout_common_name (syms_prev, comm_prev, N_ECOMM); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* The following two functions output definitions of function parameters. | 
|  | Each parameter gets a definition locating it in the parameter list. | 
|  | Each parameter that is a register variable gets a second definition | 
|  | locating it in the register. | 
|  |  | 
|  | Printing or argument lists in gdb uses the definitions that | 
|  | locate in the parameter list.  But reference to the variable in | 
|  | expressions uses preferentially the definition as a register.  */ | 
|  |  | 
|  | /* Output definitions, referring to storage in the parmlist, | 
|  | of all the parms in PARMS, which is a chain of PARM_DECL nodes.  */ | 
|  |  | 
|  | void | 
|  | dbxout_parms (tree parms) | 
|  | { | 
|  | ++debug_nesting; | 
|  | emit_pending_bincls_if_required (); | 
|  | fixed_size_mode rtl_mode, type_mode; | 
|  |  | 
|  | for (; parms; parms = DECL_CHAIN (parms)) | 
|  | if (DECL_NAME (parms) | 
|  | && TREE_TYPE (parms) != error_mark_node | 
|  | && DECL_RTL_SET_P (parms) | 
|  | && DECL_INCOMING_RTL (parms) | 
|  | /* We can't represent variable-sized types in this format.  */ | 
|  | && is_a <fixed_size_mode> (TYPE_MODE (TREE_TYPE (parms)), &type_mode) | 
|  | && is_a <fixed_size_mode> (GET_MODE (DECL_RTL (parms)), &rtl_mode)) | 
|  | { | 
|  | tree eff_type; | 
|  | char letter; | 
|  | stab_code_type code; | 
|  | int number; | 
|  |  | 
|  | /* Perform any necessary register eliminations on the parameter's rtl, | 
|  | so that the debugging output will be accurate.  */ | 
|  | DECL_INCOMING_RTL (parms) | 
|  | = eliminate_regs (DECL_INCOMING_RTL (parms), VOIDmode, NULL_RTX); | 
|  | SET_DECL_RTL (parms, | 
|  | eliminate_regs (DECL_RTL (parms), VOIDmode, NULL_RTX)); | 
|  | #ifdef LEAF_REG_REMAP | 
|  | if (crtl->uses_only_leaf_regs) | 
|  | { | 
|  | leaf_renumber_regs_insn (DECL_INCOMING_RTL (parms)); | 
|  | leaf_renumber_regs_insn (DECL_RTL (parms)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (PARM_PASSED_IN_MEMORY (parms)) | 
|  | { | 
|  | rtx inrtl = XEXP (DECL_INCOMING_RTL (parms), 0); | 
|  |  | 
|  | /* ??? Here we assume that the parm address is indexed | 
|  | off the frame pointer or arg pointer. | 
|  | If that is not true, we produce meaningless results, | 
|  | but do not crash.  */ | 
|  | if (GET_CODE (inrtl) == PLUS | 
|  | && CONST_INT_P (XEXP (inrtl, 1))) | 
|  | number = INTVAL (XEXP (inrtl, 1)); | 
|  | else | 
|  | number = 0; | 
|  |  | 
|  | code = N_PSYM; | 
|  | number = DEBUGGER_ARG_OFFSET (number, inrtl); | 
|  | letter = 'p'; | 
|  |  | 
|  | /* It is quite tempting to use TREE_TYPE (parms) instead | 
|  | of DECL_ARG_TYPE (parms) for the eff_type, so that gcc | 
|  | reports the actual type of the parameter, rather than | 
|  | the promoted type.  This certainly makes GDB's life | 
|  | easier, at least for some ports.  The change is a bad | 
|  | idea however, since GDB expects to be able access the | 
|  | type without performing any conversions.  So for | 
|  | example, if we were passing a float to an unprototyped | 
|  | function, gcc will store a double on the stack, but if | 
|  | we emit a stab saying the type is a float, then gdb | 
|  | will only read in a single value, and this will produce | 
|  | an erroneous value.  */ | 
|  | eff_type = DECL_ARG_TYPE (parms); | 
|  | } | 
|  | else if (REG_P (DECL_RTL (parms))) | 
|  | { | 
|  | rtx best_rtl; | 
|  |  | 
|  | /* Parm passed in registers and lives in registers or nowhere.  */ | 
|  | code = DBX_REGPARM_STABS_CODE; | 
|  | letter = DBX_REGPARM_STABS_LETTER; | 
|  |  | 
|  | /* For parms passed in registers, it is better to use the | 
|  | declared type of the variable, not the type it arrived in.  */ | 
|  | eff_type = TREE_TYPE (parms); | 
|  |  | 
|  | /* If parm lives in a register, use that register; pretend | 
|  | the parm was passed there.  It would be more consistent | 
|  | to describe the register where the parm was passed, but | 
|  | in practice that register usually holds something else. | 
|  | If the parm lives nowhere, use the register where it | 
|  | was passed.  */ | 
|  | if (REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) | 
|  | best_rtl = DECL_RTL (parms); | 
|  | else if (GET_CODE (DECL_INCOMING_RTL (parms)) == PARALLEL) | 
|  | best_rtl = XEXP (XVECEXP (DECL_INCOMING_RTL (parms), 0, 0), 0); | 
|  | else | 
|  | best_rtl = DECL_INCOMING_RTL (parms); | 
|  |  | 
|  | number = DBX_REGISTER_NUMBER (REGNO (best_rtl)); | 
|  | } | 
|  | else if (MEM_P (DECL_RTL (parms)) | 
|  | && REG_P (XEXP (DECL_RTL (parms), 0)) | 
|  | && REGNO (XEXP (DECL_RTL (parms), 0)) != HARD_FRAME_POINTER_REGNUM | 
|  | && REGNO (XEXP (DECL_RTL (parms), 0)) != STACK_POINTER_REGNUM | 
|  | #if !HARD_FRAME_POINTER_IS_ARG_POINTER | 
|  | && REGNO (XEXP (DECL_RTL (parms), 0)) != ARG_POINTER_REGNUM | 
|  | #endif | 
|  | ) | 
|  | { | 
|  | /* Parm was passed via invisible reference. | 
|  | That is, its address was passed in a register. | 
|  | Output it as if it lived in that register. | 
|  | The debugger will know from the type | 
|  | that it was actually passed by invisible reference.  */ | 
|  |  | 
|  | code = DBX_REGPARM_STABS_CODE; | 
|  |  | 
|  | /* GDB likes this marked with a special letter.  */ | 
|  | letter = (use_gnu_debug_info_extensions | 
|  | ? 'a' : DBX_REGPARM_STABS_LETTER); | 
|  | eff_type = TREE_TYPE (parms); | 
|  |  | 
|  | /* DECL_RTL looks like (MEM (REG...).  Get the register number. | 
|  | If it is an unallocated pseudo-reg, then use the register where | 
|  | it was passed instead. | 
|  | ??? Why is DBX_REGISTER_NUMBER not used here?  */ | 
|  |  | 
|  | if (REGNO (XEXP (DECL_RTL (parms), 0)) < FIRST_PSEUDO_REGISTER) | 
|  | number = REGNO (XEXP (DECL_RTL (parms), 0)); | 
|  | else | 
|  | number = REGNO (DECL_INCOMING_RTL (parms)); | 
|  | } | 
|  | else if (MEM_P (DECL_RTL (parms)) | 
|  | && MEM_P (XEXP (DECL_RTL (parms), 0))) | 
|  | { | 
|  | /* Parm was passed via invisible reference, with the reference | 
|  | living on the stack.  DECL_RTL looks like | 
|  | (MEM (MEM (PLUS (REG ...) (CONST_INT ...)))) or it | 
|  | could look like (MEM (MEM (REG))).  */ | 
|  |  | 
|  | code = N_PSYM; | 
|  | letter = 'v'; | 
|  | eff_type = TREE_TYPE (parms); | 
|  |  | 
|  | if (!REG_P (XEXP (XEXP (DECL_RTL (parms), 0), 0))) | 
|  | number = INTVAL (XEXP (XEXP (XEXP (DECL_RTL (parms), 0), 0), 1)); | 
|  | else | 
|  | number = 0; | 
|  |  | 
|  | number = DEBUGGER_ARG_OFFSET (number, | 
|  | XEXP (XEXP (DECL_RTL (parms), 0), 0)); | 
|  | } | 
|  | else if (MEM_P (DECL_RTL (parms)) | 
|  | && XEXP (DECL_RTL (parms), 0) != const0_rtx | 
|  | /* ??? A constant address for a parm can happen | 
|  | when the reg it lives in is equiv to a constant in memory. | 
|  | Should make this not happen, after 2.4.  */ | 
|  | && ! CONSTANT_P (XEXP (DECL_RTL (parms), 0))) | 
|  | { | 
|  | /* Parm was passed in registers but lives on the stack.  */ | 
|  |  | 
|  | code = N_PSYM; | 
|  | letter = 'p'; | 
|  | eff_type = TREE_TYPE (parms); | 
|  |  | 
|  | /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))), | 
|  | in which case we want the value of that CONST_INT, | 
|  | or (MEM (REG ...)), | 
|  | in which case we use a value of zero.  */ | 
|  | if (!REG_P (XEXP (DECL_RTL (parms), 0))) | 
|  | number = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); | 
|  | else | 
|  | number = 0; | 
|  |  | 
|  | /* Make a big endian correction if the mode of the type of the | 
|  | parameter is not the same as the mode of the rtl.  */ | 
|  | if (BYTES_BIG_ENDIAN | 
|  | && type_mode != rtl_mode | 
|  | && GET_MODE_SIZE (type_mode) < UNITS_PER_WORD) | 
|  | number += GET_MODE_SIZE (rtl_mode) - GET_MODE_SIZE (type_mode); | 
|  | } | 
|  | else | 
|  | /* ??? We don't know how to represent this argument.  */ | 
|  | continue; | 
|  |  | 
|  | dbxout_begin_complex_stabs (); | 
|  |  | 
|  | if (DECL_NAME (parms)) | 
|  | { | 
|  | stabstr_I (DECL_NAME (parms)); | 
|  | stabstr_C (':'); | 
|  | } | 
|  | else | 
|  | stabstr_S ("(anon):"); | 
|  | stabstr_C (letter); | 
|  | dbxout_type (eff_type, 0); | 
|  | dbxout_finish_complex_stabs (parms, code, 0, 0, number); | 
|  | } | 
|  | DBXOUT_DECR_NESTING; | 
|  | } | 
|  |  | 
|  | /* Output definitions for the places where parms live during the function, | 
|  | when different from where they were passed, when the parms were passed | 
|  | in memory. | 
|  |  | 
|  | It is not useful to do this for parms passed in registers | 
|  | that live during the function in different registers, because it is | 
|  | impossible to look in the passed register for the passed value, | 
|  | so we use the within-the-function register to begin with. | 
|  |  | 
|  | PARMS is a chain of PARM_DECL nodes.  */ | 
|  |  | 
|  | void | 
|  | dbxout_reg_parms (tree parms) | 
|  | { | 
|  | ++debug_nesting; | 
|  |  | 
|  | for (; parms; parms = DECL_CHAIN (parms)) | 
|  | if (DECL_NAME (parms) && PARM_PASSED_IN_MEMORY (parms)) | 
|  | { | 
|  | /* Report parms that live in registers during the function | 
|  | but were passed in memory.  */ | 
|  | if (REG_P (DECL_RTL (parms)) | 
|  | && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) | 
|  | dbxout_symbol_location (parms, TREE_TYPE (parms), | 
|  | 0, DECL_RTL (parms)); | 
|  | else if (GET_CODE (DECL_RTL (parms)) == CONCAT) | 
|  | dbxout_symbol_location (parms, TREE_TYPE (parms), | 
|  | 0, DECL_RTL (parms)); | 
|  | /* Report parms that live in memory but not where they were passed.  */ | 
|  | else if (MEM_P (DECL_RTL (parms)) | 
|  | && ! rtx_equal_p (DECL_RTL (parms), DECL_INCOMING_RTL (parms))) | 
|  | dbxout_symbol_location (parms, TREE_TYPE (parms), | 
|  | 0, DECL_RTL (parms)); | 
|  | } | 
|  | DBXOUT_DECR_NESTING; | 
|  | } | 
|  |  | 
|  | /* Given a chain of ..._TYPE nodes (as come in a parameter list), | 
|  | output definitions of those names, in raw form */ | 
|  |  | 
|  | static void | 
|  | dbxout_args (tree args) | 
|  | { | 
|  | while (args) | 
|  | { | 
|  | stabstr_C (','); | 
|  | dbxout_type (TREE_VALUE (args), 0); | 
|  | args = TREE_CHAIN (args); | 
|  | } | 
|  | } | 
|  |  | 
|  | #if defined (DBX_DEBUGGING_INFO) | 
|  |  | 
|  | /* Subroutine of dbxout_block.  Emit an N_LBRAC stab referencing LABEL. | 
|  | BEGIN_LABEL is the name of the beginning of the function, which may | 
|  | be required.  */ | 
|  | static void | 
|  | dbx_output_lbrac (const char *label, | 
|  | const char *begin_label ATTRIBUTE_UNUSED) | 
|  | { | 
|  | dbxout_begin_stabn (N_LBRAC); | 
|  | if (DBX_BLOCKS_FUNCTION_RELATIVE) | 
|  | dbxout_stab_value_label_diff (label, begin_label); | 
|  | else | 
|  | dbxout_stab_value_label (label); | 
|  | } | 
|  |  | 
|  | /* Subroutine of dbxout_block.  Emit an N_RBRAC stab referencing LABEL. | 
|  | BEGIN_LABEL is the name of the beginning of the function, which may | 
|  | be required.  */ | 
|  | static void | 
|  | dbx_output_rbrac (const char *label, | 
|  | const char *begin_label ATTRIBUTE_UNUSED) | 
|  | { | 
|  | dbxout_begin_stabn (N_RBRAC); | 
|  | if (DBX_BLOCKS_FUNCTION_RELATIVE) | 
|  | dbxout_stab_value_label_diff (label, begin_label); | 
|  | else | 
|  | dbxout_stab_value_label (label); | 
|  | } | 
|  |  | 
|  | /* Return true if at least one block among BLOCK, its children or siblings | 
|  | has TREE_USED, TREE_ASM_WRITTEN and BLOCK_IN_COLD_SECTION_P | 
|  | set.  If there is none, clear TREE_USED bit on such blocks.  */ | 
|  |  | 
|  | static bool | 
|  | dbx_block_with_cold_children (tree block) | 
|  | { | 
|  | bool ret = false; | 
|  | for (; block; block = BLOCK_CHAIN (block)) | 
|  | if (TREE_USED (block) && TREE_ASM_WRITTEN (block)) | 
|  | { | 
|  | bool children = dbx_block_with_cold_children (BLOCK_SUBBLOCKS (block)); | 
|  | if (BLOCK_IN_COLD_SECTION_P (block) || children) | 
|  | ret = true; | 
|  | else | 
|  | TREE_USED (block) = false; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Output everything about a symbol block (a BLOCK node | 
|  | that represents a scope level), | 
|  | including recursive output of contained blocks. | 
|  |  | 
|  | BLOCK is the BLOCK node. | 
|  | DEPTH is its depth within containing symbol blocks. | 
|  | ARGS is usually zero; but for the outermost block of the | 
|  | body of a function, it is a chain of PARM_DECLs for the function parameters. | 
|  | We output definitions of all the register parms | 
|  | as if they were local variables of that block. | 
|  |  | 
|  | If -g1 was used, we count blocks just the same, but output nothing | 
|  | except for the outermost block. | 
|  |  | 
|  | Actually, BLOCK may be several blocks chained together. | 
|  | We handle them all in sequence. | 
|  |  | 
|  | Return true if we emitted any LBRAC/RBRAC.  */ | 
|  |  | 
|  | static bool | 
|  | dbxout_block (tree block, int depth, tree args, int parent_blocknum) | 
|  | { | 
|  | bool ret = false; | 
|  | char begin_label[20]; | 
|  | /* Reference current function start using LFBB.  */ | 
|  | ASM_GENERATE_INTERNAL_LABEL (begin_label, "LFBB", scope_labelno); | 
|  |  | 
|  | /* If called for the second partition, ignore blocks that don't have | 
|  | any children in the second partition.  */ | 
|  | if (crtl->has_bb_partition && in_cold_section_p && depth == 0) | 
|  | dbx_block_with_cold_children (block); | 
|  |  | 
|  | for (; block; block = BLOCK_CHAIN (block)) | 
|  | { | 
|  | /* Ignore blocks never expanded or otherwise marked as real.  */ | 
|  | if (TREE_USED (block) && TREE_ASM_WRITTEN (block)) | 
|  | { | 
|  | int did_output; | 
|  | int blocknum = BLOCK_NUMBER (block); | 
|  | int this_parent = parent_blocknum; | 
|  |  | 
|  | /* In dbx format, the syms of a block come before the N_LBRAC. | 
|  | If nothing is output, we don't need the N_LBRAC, either.  */ | 
|  | did_output = 0; | 
|  | if (debug_info_level != DINFO_LEVEL_TERSE || depth == 0) | 
|  | did_output = dbxout_syms (BLOCK_VARS (block)); | 
|  | if (args) | 
|  | dbxout_reg_parms (args); | 
|  |  | 
|  | /* Now output an N_LBRAC symbol to represent the beginning of | 
|  | the block.  Use the block's tree-walk order to generate | 
|  | the assembler symbols LBBn and LBEn | 
|  | that final will define around the code in this block.  */ | 
|  | if (did_output | 
|  | && BLOCK_IN_COLD_SECTION_P (block) == in_cold_section_p) | 
|  | { | 
|  | char buf[20]; | 
|  | const char *scope_start; | 
|  |  | 
|  | ret = true; | 
|  | if (depth == 0) | 
|  | /* The outermost block doesn't get LBB labels; use | 
|  | the LFBB local symbol emitted by dbxout_begin_prologue.  */ | 
|  | scope_start = begin_label; | 
|  | else | 
|  | { | 
|  | ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", blocknum); | 
|  | scope_start = buf; | 
|  | this_parent = blocknum; | 
|  | } | 
|  |  | 
|  | dbx_output_lbrac (scope_start, begin_label); | 
|  | } | 
|  |  | 
|  | /* Output the subblocks.  */ | 
|  | bool children | 
|  | = dbxout_block (BLOCK_SUBBLOCKS (block), depth + 1, NULL_TREE, | 
|  | this_parent); | 
|  | ret |= children; | 
|  |  | 
|  | /* Refer to the marker for the end of the block.  */ | 
|  | if (did_output | 
|  | && BLOCK_IN_COLD_SECTION_P (block) == in_cold_section_p) | 
|  | { | 
|  | char buf[100]; | 
|  | if (depth == 0) | 
|  | /* The outermost block doesn't get LBE labels; | 
|  | use the "scope" label which will be emitted | 
|  | by dbxout_function_end.  */ | 
|  | ASM_GENERATE_INTERNAL_LABEL (buf, "Lscope", scope_labelno); | 
|  | else | 
|  | ASM_GENERATE_INTERNAL_LABEL (buf, "LBE", blocknum); | 
|  |  | 
|  | dbx_output_rbrac (buf, begin_label); | 
|  | } | 
|  | else if (did_output && !children) | 
|  | { | 
|  | /* If we emitted any vars and didn't output any LBRAC/RBRAC, | 
|  | either at this level or any lower level, we need to emit | 
|  | an empty LBRAC/RBRAC pair now.  */ | 
|  | char buf[30]; | 
|  | const char *scope_start; | 
|  |  | 
|  | ret = true; | 
|  | if (parent_blocknum == -1) | 
|  | scope_start = begin_label; | 
|  | else | 
|  | { | 
|  | ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", parent_blocknum); | 
|  | scope_start = buf; | 
|  | } | 
|  |  | 
|  | dbx_output_lbrac (scope_start, begin_label); | 
|  | dbx_output_rbrac (scope_start, begin_label); | 
|  | } | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Output the information about a function and its arguments and result. | 
|  | Usually this follows the function's code, | 
|  | but on some systems, it comes before.  */ | 
|  |  | 
|  | static void | 
|  | dbxout_begin_function (tree decl) | 
|  | { | 
|  | int saved_tree_used1; | 
|  |  | 
|  | saved_tree_used1 = TREE_USED (decl); | 
|  | TREE_USED (decl) = 1; | 
|  | if (DECL_NAME (DECL_RESULT (decl)) != 0) | 
|  | { | 
|  | int saved_tree_used2 = TREE_USED (DECL_RESULT (decl)); | 
|  | TREE_USED (DECL_RESULT (decl)) = 1; | 
|  | dbxout_symbol (decl, 0); | 
|  | TREE_USED (DECL_RESULT (decl)) = saved_tree_used2; | 
|  | } | 
|  | else | 
|  | dbxout_symbol (decl, 0); | 
|  | TREE_USED (decl) = saved_tree_used1; | 
|  |  | 
|  | dbxout_parms (DECL_ARGUMENTS (decl)); | 
|  | if (DECL_NAME (DECL_RESULT (decl)) != 0) | 
|  | dbxout_symbol (DECL_RESULT (decl), 1); | 
|  | } | 
|  | #endif /* DBX_DEBUGGING_INFO */ | 
|  |  | 
|  | #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ | 
|  |  | 
|  | /* Record an element in the table of global destructors.  SYMBOL is | 
|  | a SYMBOL_REF of the function to be called; PRIORITY is a number | 
|  | between 0 and MAX_INIT_PRIORITY.  */ | 
|  |  | 
|  | void | 
|  | default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED, | 
|  | int priority ATTRIBUTE_UNUSED) | 
|  | { | 
|  | #if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO | 
|  | /* Tell GNU LD that this is part of the static destructor set. | 
|  | This will work for any system that uses stabs, most usefully | 
|  | aout systems.  */ | 
|  | dbxout_begin_simple_stabs ("___DTOR_LIST__", 22 /* N_SETT */); | 
|  | dbxout_stab_value_label (XSTR (symbol, 0)); | 
|  | #else | 
|  | sorry ("global destructors not supported on this target"); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Likewise for global constructors.  */ | 
|  |  | 
|  | void | 
|  | default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED, | 
|  | int priority ATTRIBUTE_UNUSED) | 
|  | { | 
|  | #if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO | 
|  | /* Tell GNU LD that this is part of the static destructor set. | 
|  | This will work for any system that uses stabs, most usefully | 
|  | aout systems.  */ | 
|  | dbxout_begin_simple_stabs ("___CTOR_LIST__", 22 /* N_SETT */); | 
|  | dbxout_stab_value_label (XSTR (symbol, 0)); | 
|  | #else | 
|  | sorry ("global constructors not supported on this target"); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #include "gt-dbxout.h" |