dwarf2out.c revision 50397
150397Sobrien/* Output Dwarf2 format symbol table information from the GNU C compiler. 250397Sobrien Copyright (C) 1992, 93, 95, 96, 97, 1998 Free Software Foundation, Inc. 350397Sobrien Contributed by Gary Funck (gary@intrepid.com). 450397Sobrien Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). 550397Sobrien Extensively modified by Jason Merrill (jason@cygnus.com). 650397Sobrien 750397SobrienThis file is part of GNU CC. 850397Sobrien 950397SobrienGNU CC is free software; you can redistribute it and/or modify 1050397Sobrienit under the terms of the GNU General Public License as published by 1150397Sobrienthe Free Software Foundation; either version 2, or (at your option) 1250397Sobrienany later version. 1350397Sobrien 1450397SobrienGNU CC is distributed in the hope that it will be useful, 1550397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1650397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1750397SobrienGNU General Public License for more details. 1850397Sobrien 1950397SobrienYou should have received a copy of the GNU General Public License 2050397Sobrienalong with GNU CC; see the file COPYING. If not, write to 2150397Sobrienthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 2250397Sobrien 2350397Sobrien/* The first part of this file deals with the DWARF 2 frame unwind 2450397Sobrien information, which is also used by the GCC efficient exception handling 2550397Sobrien mechanism. The second part, controlled only by an #ifdef 2650397Sobrien DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging 2750397Sobrien information. */ 2850397Sobrien 2950397Sobrien#include "config.h" 3050397Sobrien#include "system.h" 3150397Sobrien#include "defaults.h" 3250397Sobrien#include "tree.h" 3350397Sobrien#include "flags.h" 3450397Sobrien#include "rtl.h" 3550397Sobrien#include "hard-reg-set.h" 3650397Sobrien#include "regs.h" 3750397Sobrien#include "insn-config.h" 3850397Sobrien#include "reload.h" 3950397Sobrien#include "output.h" 4050397Sobrien#include "expr.h" 4150397Sobrien#include "except.h" 4250397Sobrien#include "dwarf2.h" 4350397Sobrien#include "dwarf2out.h" 4450397Sobrien#include "toplev.h" 4550397Sobrien#include "dyn-string.h" 4650397Sobrien 4750397Sobrien/* We cannot use <assert.h> in GCC source, since that would include 4850397Sobrien GCC's assert.h, which may not be compatible with the host compiler. */ 4950397Sobrien#undef assert 5050397Sobrien#ifdef NDEBUG 5150397Sobrien# define assert(e) 5250397Sobrien#else 5350397Sobrien# define assert(e) do { if (! (e)) abort (); } while (0) 5450397Sobrien#endif 5550397Sobrien 5650397Sobrien/* Decide whether we want to emit frame unwind information for the current 5750397Sobrien translation unit. */ 5850397Sobrien 5950397Sobrienint 6050397Sobriendwarf2out_do_frame () 6150397Sobrien{ 6250397Sobrien return (write_symbols == DWARF2_DEBUG 6350397Sobrien#ifdef DWARF2_FRAME_INFO 6450397Sobrien || DWARF2_FRAME_INFO 6550397Sobrien#endif 6650397Sobrien#ifdef DWARF2_UNWIND_INFO 6750397Sobrien || (flag_exceptions && ! exceptions_via_longjmp) 6850397Sobrien#endif 6950397Sobrien ); 7050397Sobrien} 7150397Sobrien 7250397Sobrien#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) 7350397Sobrien 7450397Sobrien#ifndef __GNUC__ 7550397Sobrien#define inline 7650397Sobrien#endif 7750397Sobrien 7850397Sobrien/* How to start an assembler comment. */ 7950397Sobrien#ifndef ASM_COMMENT_START 8050397Sobrien#define ASM_COMMENT_START ";#" 8150397Sobrien#endif 8250397Sobrien 8350397Sobrientypedef struct dw_cfi_struct *dw_cfi_ref; 8450397Sobrientypedef struct dw_fde_struct *dw_fde_ref; 8550397Sobrientypedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref; 8650397Sobrien 8750397Sobrien/* Call frames are described using a sequence of Call Frame 8850397Sobrien Information instructions. The register number, offset 8950397Sobrien and address fields are provided as possible operands; 9050397Sobrien their use is selected by the opcode field. */ 9150397Sobrien 9250397Sobrientypedef union dw_cfi_oprnd_struct 9350397Sobrien{ 9450397Sobrien unsigned long dw_cfi_reg_num; 9550397Sobrien long int dw_cfi_offset; 9650397Sobrien char *dw_cfi_addr; 9750397Sobrien} 9850397Sobriendw_cfi_oprnd; 9950397Sobrien 10050397Sobrientypedef struct dw_cfi_struct 10150397Sobrien{ 10250397Sobrien dw_cfi_ref dw_cfi_next; 10350397Sobrien enum dwarf_call_frame_info dw_cfi_opc; 10450397Sobrien dw_cfi_oprnd dw_cfi_oprnd1; 10550397Sobrien dw_cfi_oprnd dw_cfi_oprnd2; 10650397Sobrien} 10750397Sobriendw_cfi_node; 10850397Sobrien 10950397Sobrien/* All call frame descriptions (FDE's) in the GCC generated DWARF 11050397Sobrien refer to a single Common Information Entry (CIE), defined at 11150397Sobrien the beginning of the .debug_frame section. This used of a single 11250397Sobrien CIE obviates the need to keep track of multiple CIE's 11350397Sobrien in the DWARF generation routines below. */ 11450397Sobrien 11550397Sobrientypedef struct dw_fde_struct 11650397Sobrien{ 11750397Sobrien char *dw_fde_begin; 11850397Sobrien char *dw_fde_current_label; 11950397Sobrien char *dw_fde_end; 12050397Sobrien dw_cfi_ref dw_fde_cfi; 12150397Sobrien} 12250397Sobriendw_fde_node; 12350397Sobrien 12450397Sobrien/* Maximum size (in bytes) of an artificially generated label. */ 12550397Sobrien#define MAX_ARTIFICIAL_LABEL_BYTES 30 12650397Sobrien 12750397Sobrien/* Make sure we know the sizes of the various types dwarf can describe. These 12850397Sobrien are only defaults. If the sizes are different for your target, you should 12950397Sobrien override these values by defining the appropriate symbols in your tm.h 13050397Sobrien file. */ 13150397Sobrien 13250397Sobrien#ifndef CHAR_TYPE_SIZE 13350397Sobrien#define CHAR_TYPE_SIZE BITS_PER_UNIT 13450397Sobrien#endif 13550397Sobrien#ifndef PTR_SIZE 13650397Sobrien#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT) 13750397Sobrien#endif 13850397Sobrien 13950397Sobrien/* The size in bytes of a DWARF field indicating an offset or length 14050397Sobrien relative to a debug info section, specified to be 4 bytes in the DWARF-2 14150397Sobrien specification. The SGI/MIPS ABI defines it to be the same as PTR_SIZE. */ 14250397Sobrien 14350397Sobrien#ifndef DWARF_OFFSET_SIZE 14450397Sobrien#define DWARF_OFFSET_SIZE 4 14550397Sobrien#endif 14650397Sobrien 14750397Sobrien#define DWARF_VERSION 2 14850397Sobrien 14950397Sobrien/* Round SIZE up to the nearest BOUNDARY. */ 15050397Sobrien#define DWARF_ROUND(SIZE,BOUNDARY) \ 15150397Sobrien (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1)) 15250397Sobrien 15350397Sobrien/* Offsets recorded in opcodes are a multiple of this alignment factor. */ 15450397Sobrien#ifdef STACK_GROWS_DOWNWARD 15550397Sobrien#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD) 15650397Sobrien#else 15750397Sobrien#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD 15850397Sobrien#endif 15950397Sobrien 16050397Sobrien/* A pointer to the base of a table that contains frame description 16150397Sobrien information for each routine. */ 16250397Sobrienstatic dw_fde_ref fde_table; 16350397Sobrien 16450397Sobrien/* Number of elements currently allocated for fde_table. */ 16550397Sobrienstatic unsigned fde_table_allocated; 16650397Sobrien 16750397Sobrien/* Number of elements in fde_table currently in use. */ 16850397Sobrienstatic unsigned fde_table_in_use; 16950397Sobrien 17050397Sobrien/* Size (in elements) of increments by which we may expand the 17150397Sobrien fde_table. */ 17250397Sobrien#define FDE_TABLE_INCREMENT 256 17350397Sobrien 17450397Sobrien/* A list of call frame insns for the CIE. */ 17550397Sobrienstatic dw_cfi_ref cie_cfi_head; 17650397Sobrien 17750397Sobrien/* The number of the current function definition for which debugging 17850397Sobrien information is being generated. These numbers range from 1 up to the 17950397Sobrien maximum number of function definitions contained within the current 18050397Sobrien compilation unit. These numbers are used to create unique label id's 18150397Sobrien unique to each function definition. */ 18250397Sobrienstatic unsigned current_funcdef_number = 0; 18350397Sobrien 18450397Sobrien/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram 18550397Sobrien attribute that accelerates the lookup of the FDE associated 18650397Sobrien with the subprogram. This variable holds the table index of the FDE 18750397Sobrien associated with the current function (body) definition. */ 18850397Sobrienstatic unsigned current_funcdef_fde; 18950397Sobrien 19050397Sobrien/* Forward declarations for functions defined in this file. */ 19150397Sobrien 19250397Sobrienstatic char *stripattributes PROTO((char *)); 19350397Sobrienstatic char *dwarf_cfi_name PROTO((unsigned)); 19450397Sobrienstatic dw_cfi_ref new_cfi PROTO((void)); 19550397Sobrienstatic void add_cfi PROTO((dw_cfi_ref *, dw_cfi_ref)); 19650397Sobrienstatic unsigned long size_of_uleb128 PROTO((unsigned long)); 19750397Sobrienstatic unsigned long size_of_sleb128 PROTO((long)); 19850397Sobrienstatic void output_uleb128 PROTO((unsigned long)); 19950397Sobrienstatic void output_sleb128 PROTO((long)); 20050397Sobrienstatic void add_fde_cfi PROTO((char *, dw_cfi_ref)); 20150397Sobrienstatic void lookup_cfa_1 PROTO((dw_cfi_ref, unsigned long *, 20250397Sobrien long *)); 20350397Sobrienstatic void lookup_cfa PROTO((unsigned long *, long *)); 20450397Sobrienstatic void reg_save PROTO((char *, unsigned, unsigned, 20550397Sobrien long)); 20650397Sobrienstatic void initial_return_save PROTO((rtx)); 20750397Sobrienstatic void output_cfi PROTO((dw_cfi_ref, dw_fde_ref)); 20850397Sobrienstatic void output_call_frame_info PROTO((int)); 20950397Sobrienstatic unsigned reg_number PROTO((rtx)); 21050397Sobrienstatic void dwarf2out_stack_adjust PROTO((rtx)); 21150397Sobrien 21250397Sobrien/* Definitions of defaults for assembler-dependent names of various 21350397Sobrien pseudo-ops and section names. 21450397Sobrien Theses may be overridden in the tm.h file (if necessary) for a particular 21550397Sobrien assembler. */ 21650397Sobrien 21750397Sobrien#ifdef OBJECT_FORMAT_ELF 21850397Sobrien#ifndef UNALIGNED_SHORT_ASM_OP 21950397Sobrien#define UNALIGNED_SHORT_ASM_OP ".2byte" 22050397Sobrien#endif 22150397Sobrien#ifndef UNALIGNED_INT_ASM_OP 22250397Sobrien#define UNALIGNED_INT_ASM_OP ".4byte" 22350397Sobrien#endif 22450397Sobrien#ifndef UNALIGNED_DOUBLE_INT_ASM_OP 22550397Sobrien#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte" 22650397Sobrien#endif 22750397Sobrien#endif /* OBJECT_FORMAT_ELF */ 22850397Sobrien 22950397Sobrien#ifndef ASM_BYTE_OP 23050397Sobrien#define ASM_BYTE_OP ".byte" 23150397Sobrien#endif 23250397Sobrien 23350397Sobrien/* Data and reference forms for relocatable data. */ 23450397Sobrien#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4) 23550397Sobrien#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4) 23650397Sobrien 23750397Sobrien/* Pseudo-op for defining a new section. */ 23850397Sobrien#ifndef SECTION_ASM_OP 23950397Sobrien#define SECTION_ASM_OP ".section" 24050397Sobrien#endif 24150397Sobrien 24250397Sobrien/* The default format used by the ASM_OUTPUT_SECTION macro (see below) to 24350397Sobrien print the SECTION_ASM_OP and the section name. The default here works for 24450397Sobrien almost all svr4 assemblers, except for the sparc, where the section name 24550397Sobrien must be enclosed in double quotes. (See sparcv4.h). */ 24650397Sobrien#ifndef SECTION_FORMAT 24750397Sobrien#ifdef PUSHSECTION_FORMAT 24850397Sobrien#define SECTION_FORMAT PUSHSECTION_FORMAT 24950397Sobrien#else 25050397Sobrien#define SECTION_FORMAT "\t%s\t%s\n" 25150397Sobrien#endif 25250397Sobrien#endif 25350397Sobrien 25450397Sobrien#ifndef FRAME_SECTION 25550397Sobrien#define FRAME_SECTION ".debug_frame" 25650397Sobrien#endif 25750397Sobrien 25850397Sobrien#ifndef FUNC_BEGIN_LABEL 25950397Sobrien#define FUNC_BEGIN_LABEL "LFB" 26050397Sobrien#endif 26150397Sobrien#ifndef FUNC_END_LABEL 26250397Sobrien#define FUNC_END_LABEL "LFE" 26350397Sobrien#endif 26450397Sobrien#define CIE_AFTER_SIZE_LABEL "LSCIE" 26550397Sobrien#define CIE_END_LABEL "LECIE" 26650397Sobrien#define CIE_LENGTH_LABEL "LLCIE" 26750397Sobrien#define FDE_AFTER_SIZE_LABEL "LSFDE" 26850397Sobrien#define FDE_END_LABEL "LEFDE" 26950397Sobrien#define FDE_LENGTH_LABEL "LLFDE" 27050397Sobrien 27150397Sobrien/* Definitions of defaults for various types of primitive assembly language 27250397Sobrien output operations. These may be overridden from within the tm.h file, 27350397Sobrien but typically, that is unnecessary. */ 27450397Sobrien 27550397Sobrien#ifndef ASM_OUTPUT_SECTION 27650397Sobrien#define ASM_OUTPUT_SECTION(FILE, SECTION) \ 27750397Sobrien fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION) 27850397Sobrien#endif 27950397Sobrien 28050397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA1 28150397Sobrien#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \ 28250397Sobrien fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE)) 28350397Sobrien#endif 28450397Sobrien 28550397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA1 28650397Sobrien#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2) \ 28750397Sobrien do { fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \ 28850397Sobrien assemble_name (FILE, LABEL1); \ 28950397Sobrien fprintf (FILE, "-"); \ 29050397Sobrien assemble_name (FILE, LABEL2); \ 29150397Sobrien } while (0) 29250397Sobrien#endif 29350397Sobrien 29450397Sobrien#ifdef UNALIGNED_INT_ASM_OP 29550397Sobrien 29650397Sobrien#ifndef UNALIGNED_OFFSET_ASM_OP 29750397Sobrien#define UNALIGNED_OFFSET_ASM_OP \ 29850397Sobrien (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) 29950397Sobrien#endif 30050397Sobrien 30150397Sobrien#ifndef UNALIGNED_WORD_ASM_OP 30250397Sobrien#define UNALIGNED_WORD_ASM_OP \ 30350397Sobrien (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) 30450397Sobrien#endif 30550397Sobrien 30650397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA2 30750397Sobrien#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ 30850397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \ 30950397Sobrien assemble_name (FILE, LABEL1); \ 31050397Sobrien fprintf (FILE, "-"); \ 31150397Sobrien assemble_name (FILE, LABEL2); \ 31250397Sobrien } while (0) 31350397Sobrien#endif 31450397Sobrien 31550397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA4 31650397Sobrien#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ 31750397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ 31850397Sobrien assemble_name (FILE, LABEL1); \ 31950397Sobrien fprintf (FILE, "-"); \ 32050397Sobrien assemble_name (FILE, LABEL2); \ 32150397Sobrien } while (0) 32250397Sobrien#endif 32350397Sobrien 32450397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA 32550397Sobrien#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ 32650397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ 32750397Sobrien assemble_name (FILE, LABEL1); \ 32850397Sobrien fprintf (FILE, "-"); \ 32950397Sobrien assemble_name (FILE, LABEL2); \ 33050397Sobrien } while (0) 33150397Sobrien#endif 33250397Sobrien 33350397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA 33450397Sobrien#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ 33550397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ 33650397Sobrien assemble_name (FILE, LABEL1); \ 33750397Sobrien fprintf (FILE, "-"); \ 33850397Sobrien assemble_name (FILE, LABEL2); \ 33950397Sobrien } while (0) 34050397Sobrien#endif 34150397Sobrien 34250397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR 34350397Sobrien#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ 34450397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ 34550397Sobrien assemble_name (FILE, LABEL); \ 34650397Sobrien } while (0) 34750397Sobrien#endif 34850397Sobrien 34950397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR_CONST 35050397Sobrien#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \ 35150397Sobrien fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR)) 35250397Sobrien#endif 35350397Sobrien 35450397Sobrien#ifndef ASM_OUTPUT_DWARF_OFFSET4 35550397Sobrien#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ 35650397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ 35750397Sobrien assemble_name (FILE, LABEL); \ 35850397Sobrien } while (0) 35950397Sobrien#endif 36050397Sobrien 36150397Sobrien#ifndef ASM_OUTPUT_DWARF_OFFSET 36250397Sobrien#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ 36350397Sobrien do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ 36450397Sobrien assemble_name (FILE, LABEL); \ 36550397Sobrien } while (0) 36650397Sobrien#endif 36750397Sobrien 36850397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA2 36950397Sobrien#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \ 37050397Sobrien fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE)) 37150397Sobrien#endif 37250397Sobrien 37350397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA4 37450397Sobrien#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ 37550397Sobrien fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE)) 37650397Sobrien#endif 37750397Sobrien 37850397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA 37950397Sobrien#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \ 38050397Sobrien fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \ 38150397Sobrien (unsigned long) (VALUE)) 38250397Sobrien#endif 38350397Sobrien 38450397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR_DATA 38550397Sobrien#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \ 38650397Sobrien fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \ 38750397Sobrien (unsigned long) (VALUE)) 38850397Sobrien#endif 38950397Sobrien 39050397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA8 39150397Sobrien#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \ 39250397Sobrien do { \ 39350397Sobrien if (WORDS_BIG_ENDIAN) \ 39450397Sobrien { \ 39550397Sobrien fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\ 39650397Sobrien fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\ 39750397Sobrien } \ 39850397Sobrien else \ 39950397Sobrien { \ 40050397Sobrien fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \ 40150397Sobrien fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \ 40250397Sobrien } \ 40350397Sobrien } while (0) 40450397Sobrien#endif 40550397Sobrien 40650397Sobrien#else /* UNALIGNED_INT_ASM_OP */ 40750397Sobrien 40850397Sobrien/* We don't have unaligned support, let's hope the normal output works for 40950397Sobrien .debug_frame. */ 41050397Sobrien 41150397Sobrien#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ 41250397Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1) 41350397Sobrien 41450397Sobrien#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ 41550397Sobrien assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) 41650397Sobrien 41750397Sobrien#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ 41850397Sobrien assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) 41950397Sobrien 42050397Sobrien#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ 42150397Sobrien assemble_integer (gen_rtx_MINUS (HImode, \ 42250397Sobrien gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ 42350397Sobrien gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ 42450397Sobrien 2, 1) 42550397Sobrien 42650397Sobrien#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ 42750397Sobrien assemble_integer (gen_rtx_MINUS (SImode, \ 42850397Sobrien gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ 42950397Sobrien gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ 43050397Sobrien 4, 1) 43150397Sobrien 43250397Sobrien#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ 43350397Sobrien assemble_integer (gen_rtx_MINUS (Pmode, \ 43450397Sobrien gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ 43550397Sobrien gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ 43650397Sobrien PTR_SIZE, 1) 43750397Sobrien 43850397Sobrien#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ 43950397Sobrien ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2) 44050397Sobrien 44150397Sobrien#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ 44250397Sobrien assemble_integer (GEN_INT (VALUE), 4, 1) 44350397Sobrien 44450397Sobrien#endif /* UNALIGNED_INT_ASM_OP */ 44550397Sobrien 44650397Sobrien#ifdef SET_ASM_OP 44750397Sobrien#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL 44850397Sobrien#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \ 44950397Sobrien do { \ 45050397Sobrien fprintf (FILE, "\t%s\t", SET_ASM_OP); \ 45150397Sobrien assemble_name (FILE, SY); \ 45250397Sobrien fputc (',', FILE); \ 45350397Sobrien assemble_name (FILE, HI); \ 45450397Sobrien fputc ('-', FILE); \ 45550397Sobrien assemble_name (FILE, LO); \ 45650397Sobrien } while (0) 45750397Sobrien#endif 45850397Sobrien#endif /* SET_ASM_OP */ 45950397Sobrien 46050397Sobrien/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing 46150397Sobrien newline is produced. When flag_debug_asm is asserted, we add commentary 46250397Sobrien at the end of the line, so we must avoid output of a newline here. */ 46350397Sobrien#ifndef ASM_OUTPUT_DWARF_STRING 46450397Sobrien#define ASM_OUTPUT_DWARF_STRING(FILE,P) \ 46550397Sobrien do { \ 46650397Sobrien register int slen = strlen(P); \ 46750397Sobrien register char *p = (P); \ 46850397Sobrien register int i; \ 46950397Sobrien fprintf (FILE, "\t.ascii \""); \ 47050397Sobrien for (i = 0; i < slen; i++) \ 47150397Sobrien { \ 47250397Sobrien register int c = p[i]; \ 47350397Sobrien if (c == '\"' || c == '\\') \ 47450397Sobrien putc ('\\', FILE); \ 47550397Sobrien if (c >= ' ' && c < 0177) \ 47650397Sobrien putc (c, FILE); \ 47750397Sobrien else \ 47850397Sobrien { \ 47950397Sobrien fprintf (FILE, "\\%o", c); \ 48050397Sobrien } \ 48150397Sobrien } \ 48250397Sobrien fprintf (FILE, "\\0\""); \ 48350397Sobrien } \ 48450397Sobrien while (0) 48550397Sobrien#endif 48650397Sobrien 48750397Sobrien/* The DWARF 2 CFA column which tracks the return address. Normally this 48850397Sobrien is the column for PC, or the first column after all of the hard 48950397Sobrien registers. */ 49050397Sobrien#ifndef DWARF_FRAME_RETURN_COLUMN 49150397Sobrien#ifdef PC_REGNUM 49250397Sobrien#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM) 49350397Sobrien#else 49450397Sobrien#define DWARF_FRAME_RETURN_COLUMN FIRST_PSEUDO_REGISTER 49550397Sobrien#endif 49650397Sobrien#endif 49750397Sobrien 49850397Sobrien/* The mapping from gcc register number to DWARF 2 CFA column number. By 49950397Sobrien default, we just provide columns for all registers. */ 50050397Sobrien#ifndef DWARF_FRAME_REGNUM 50150397Sobrien#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) 50250397Sobrien#endif 50350397Sobrien 50450397Sobrien/* Hook used by __throw. */ 50550397Sobrien 50650397Sobrienrtx 50750397Sobrienexpand_builtin_dwarf_fp_regnum () 50850397Sobrien{ 50950397Sobrien return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM)); 51050397Sobrien} 51150397Sobrien 51250397Sobrien/* The offset from the incoming value of %sp to the top of the stack frame 51350397Sobrien for the current function. */ 51450397Sobrien#ifndef INCOMING_FRAME_SP_OFFSET 51550397Sobrien#define INCOMING_FRAME_SP_OFFSET 0 51650397Sobrien#endif 51750397Sobrien 51850397Sobrien/* Return a pointer to a copy of the section string name S with all 51950397Sobrien attributes stripped off, and an asterisk prepended (for assemble_name). */ 52050397Sobrien 52150397Sobrienstatic inline char * 52250397Sobrienstripattributes (s) 52350397Sobrien char *s; 52450397Sobrien{ 52550397Sobrien char *stripped = xmalloc (strlen (s) + 2); 52650397Sobrien char *p = stripped; 52750397Sobrien 52850397Sobrien *p++ = '*'; 52950397Sobrien 53050397Sobrien while (*s && *s != ',') 53150397Sobrien *p++ = *s++; 53250397Sobrien 53350397Sobrien *p = '\0'; 53450397Sobrien return stripped; 53550397Sobrien} 53650397Sobrien 53750397Sobrien/* Return the register number described by a given RTL node. */ 53850397Sobrien 53950397Sobrienstatic unsigned 54050397Sobrienreg_number (rtl) 54150397Sobrien register rtx rtl; 54250397Sobrien{ 54350397Sobrien register unsigned regno = REGNO (rtl); 54450397Sobrien 54550397Sobrien if (regno >= FIRST_PSEUDO_REGISTER) 54650397Sobrien { 54750397Sobrien warning ("internal regno botch: regno = %d\n", regno); 54850397Sobrien regno = 0; 54950397Sobrien } 55050397Sobrien 55150397Sobrien regno = DBX_REGISTER_NUMBER (regno); 55250397Sobrien return regno; 55350397Sobrien} 55450397Sobrien 55550397Sobrienstruct reg_size_range 55650397Sobrien{ 55750397Sobrien int beg; 55850397Sobrien int end; 55950397Sobrien int size; 56050397Sobrien}; 56150397Sobrien 56250397Sobrien/* Given a register number in REG_TREE, return an rtx for its size in bytes. 56350397Sobrien We do this in kind of a roundabout way, by building up a list of 56450397Sobrien register size ranges and seeing where our register falls in one of those 56550397Sobrien ranges. We need to do it this way because REG_TREE is not a constant, 56650397Sobrien and the target macros were not designed to make this task easy. */ 56750397Sobrien 56850397Sobrienrtx 56950397Sobrienexpand_builtin_dwarf_reg_size (reg_tree, target) 57050397Sobrien tree reg_tree; 57150397Sobrien rtx target; 57250397Sobrien{ 57350397Sobrien enum machine_mode mode; 57450397Sobrien int size; 57550397Sobrien struct reg_size_range ranges[5]; 57650397Sobrien tree t, t2; 57750397Sobrien 57850397Sobrien int i = 0; 57950397Sobrien int n_ranges = 0; 58050397Sobrien int last_size = -1; 58150397Sobrien 58250397Sobrien for (; i < FIRST_PSEUDO_REGISTER; ++i) 58350397Sobrien { 58450397Sobrien /* The return address is out of order on the MIPS, and we don't use 58550397Sobrien copy_reg for it anyway, so we don't care here how large it is. */ 58650397Sobrien if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN) 58750397Sobrien continue; 58850397Sobrien 58950397Sobrien mode = reg_raw_mode[i]; 59050397Sobrien 59150397Sobrien /* CCmode is arbitrarily given a size of 4 bytes. It is more useful 59250397Sobrien to use the same size as word_mode, since that reduces the number 59350397Sobrien of ranges we need. It should not matter, since the result should 59450397Sobrien never be used for a condition code register anyways. */ 59550397Sobrien if (GET_MODE_CLASS (mode) == MODE_CC) 59650397Sobrien mode = word_mode; 59750397Sobrien 59850397Sobrien size = GET_MODE_SIZE (mode); 59950397Sobrien 60050397Sobrien /* If this register is not valid in the specified mode and 60150397Sobrien we have a previous size, use that for the size of this 60250397Sobrien register to avoid making junk tiny ranges. */ 60350397Sobrien if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1) 60450397Sobrien size = last_size; 60550397Sobrien 60650397Sobrien if (size != last_size) 60750397Sobrien { 60850397Sobrien ranges[n_ranges].beg = i; 60950397Sobrien ranges[n_ranges].size = last_size = size; 61050397Sobrien ++n_ranges; 61150397Sobrien if (n_ranges >= 5) 61250397Sobrien abort (); 61350397Sobrien } 61450397Sobrien ranges[n_ranges-1].end = i; 61550397Sobrien } 61650397Sobrien 61750397Sobrien /* The usual case: fp regs surrounded by general regs. */ 61850397Sobrien if (n_ranges == 3 && ranges[0].size == ranges[2].size) 61950397Sobrien { 62050397Sobrien if ((DWARF_FRAME_REGNUM (ranges[1].end) 62150397Sobrien - DWARF_FRAME_REGNUM (ranges[1].beg)) 62250397Sobrien != ranges[1].end - ranges[1].beg) 62350397Sobrien abort (); 62450397Sobrien t = fold (build (GE_EXPR, integer_type_node, reg_tree, 62550397Sobrien build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0))); 62650397Sobrien t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, 62750397Sobrien build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0))); 62850397Sobrien t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2)); 62950397Sobrien t = fold (build (COND_EXPR, integer_type_node, t, 63050397Sobrien build_int_2 (ranges[1].size, 0), 63150397Sobrien build_int_2 (ranges[0].size, 0))); 63250397Sobrien } 63350397Sobrien else 63450397Sobrien { 63550397Sobrien --n_ranges; 63650397Sobrien t = build_int_2 (ranges[n_ranges].size, 0); 63750397Sobrien size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg); 63850397Sobrien for (; n_ranges--; ) 63950397Sobrien { 64050397Sobrien if ((DWARF_FRAME_REGNUM (ranges[n_ranges].end) 64150397Sobrien - DWARF_FRAME_REGNUM (ranges[n_ranges].beg)) 64250397Sobrien != ranges[n_ranges].end - ranges[n_ranges].beg) 64350397Sobrien abort (); 64450397Sobrien if (DWARF_FRAME_REGNUM (ranges[n_ranges].beg) >= size) 64550397Sobrien abort (); 64650397Sobrien size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg); 64750397Sobrien t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, 64850397Sobrien build_int_2 (DWARF_FRAME_REGNUM 64950397Sobrien (ranges[n_ranges].end), 0))); 65050397Sobrien t = fold (build (COND_EXPR, integer_type_node, t2, 65150397Sobrien build_int_2 (ranges[n_ranges].size, 0), t)); 65250397Sobrien } 65350397Sobrien } 65450397Sobrien return expand_expr (t, target, Pmode, 0); 65550397Sobrien} 65650397Sobrien 65750397Sobrien/* Convert a DWARF call frame info. operation to its string name */ 65850397Sobrien 65950397Sobrienstatic char * 66050397Sobriendwarf_cfi_name (cfi_opc) 66150397Sobrien register unsigned cfi_opc; 66250397Sobrien{ 66350397Sobrien switch (cfi_opc) 66450397Sobrien { 66550397Sobrien case DW_CFA_advance_loc: 66650397Sobrien return "DW_CFA_advance_loc"; 66750397Sobrien case DW_CFA_offset: 66850397Sobrien return "DW_CFA_offset"; 66950397Sobrien case DW_CFA_restore: 67050397Sobrien return "DW_CFA_restore"; 67150397Sobrien case DW_CFA_nop: 67250397Sobrien return "DW_CFA_nop"; 67350397Sobrien case DW_CFA_set_loc: 67450397Sobrien return "DW_CFA_set_loc"; 67550397Sobrien case DW_CFA_advance_loc1: 67650397Sobrien return "DW_CFA_advance_loc1"; 67750397Sobrien case DW_CFA_advance_loc2: 67850397Sobrien return "DW_CFA_advance_loc2"; 67950397Sobrien case DW_CFA_advance_loc4: 68050397Sobrien return "DW_CFA_advance_loc4"; 68150397Sobrien case DW_CFA_offset_extended: 68250397Sobrien return "DW_CFA_offset_extended"; 68350397Sobrien case DW_CFA_restore_extended: 68450397Sobrien return "DW_CFA_restore_extended"; 68550397Sobrien case DW_CFA_undefined: 68650397Sobrien return "DW_CFA_undefined"; 68750397Sobrien case DW_CFA_same_value: 68850397Sobrien return "DW_CFA_same_value"; 68950397Sobrien case DW_CFA_register: 69050397Sobrien return "DW_CFA_register"; 69150397Sobrien case DW_CFA_remember_state: 69250397Sobrien return "DW_CFA_remember_state"; 69350397Sobrien case DW_CFA_restore_state: 69450397Sobrien return "DW_CFA_restore_state"; 69550397Sobrien case DW_CFA_def_cfa: 69650397Sobrien return "DW_CFA_def_cfa"; 69750397Sobrien case DW_CFA_def_cfa_register: 69850397Sobrien return "DW_CFA_def_cfa_register"; 69950397Sobrien case DW_CFA_def_cfa_offset: 70050397Sobrien return "DW_CFA_def_cfa_offset"; 70150397Sobrien 70250397Sobrien /* SGI/MIPS specific */ 70350397Sobrien case DW_CFA_MIPS_advance_loc8: 70450397Sobrien return "DW_CFA_MIPS_advance_loc8"; 70550397Sobrien 70650397Sobrien /* GNU extensions */ 70750397Sobrien case DW_CFA_GNU_window_save: 70850397Sobrien return "DW_CFA_GNU_window_save"; 70950397Sobrien case DW_CFA_GNU_args_size: 71050397Sobrien return "DW_CFA_GNU_args_size"; 71150397Sobrien 71250397Sobrien default: 71350397Sobrien return "DW_CFA_<unknown>"; 71450397Sobrien } 71550397Sobrien} 71650397Sobrien 71750397Sobrien/* Return a pointer to a newly allocated Call Frame Instruction. */ 71850397Sobrien 71950397Sobrienstatic inline dw_cfi_ref 72050397Sobriennew_cfi () 72150397Sobrien{ 72250397Sobrien register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node)); 72350397Sobrien 72450397Sobrien cfi->dw_cfi_next = NULL; 72550397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; 72650397Sobrien cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0; 72750397Sobrien 72850397Sobrien return cfi; 72950397Sobrien} 73050397Sobrien 73150397Sobrien/* Add a Call Frame Instruction to list of instructions. */ 73250397Sobrien 73350397Sobrienstatic inline void 73450397Sobrienadd_cfi (list_head, cfi) 73550397Sobrien register dw_cfi_ref *list_head; 73650397Sobrien register dw_cfi_ref cfi; 73750397Sobrien{ 73850397Sobrien register dw_cfi_ref *p; 73950397Sobrien 74050397Sobrien /* Find the end of the chain. */ 74150397Sobrien for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next) 74250397Sobrien ; 74350397Sobrien 74450397Sobrien *p = cfi; 74550397Sobrien} 74650397Sobrien 74750397Sobrien/* Generate a new label for the CFI info to refer to. */ 74850397Sobrien 74950397Sobrienchar * 75050397Sobriendwarf2out_cfi_label () 75150397Sobrien{ 75250397Sobrien static char label[20]; 75350397Sobrien static unsigned long label_num = 0; 75450397Sobrien 75550397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++); 75650397Sobrien ASM_OUTPUT_LABEL (asm_out_file, label); 75750397Sobrien 75850397Sobrien return label; 75950397Sobrien} 76050397Sobrien 76150397Sobrien/* Add CFI to the current fde at the PC value indicated by LABEL if specified, 76250397Sobrien or to the CIE if LABEL is NULL. */ 76350397Sobrien 76450397Sobrienstatic void 76550397Sobrienadd_fde_cfi (label, cfi) 76650397Sobrien register char *label; 76750397Sobrien register dw_cfi_ref cfi; 76850397Sobrien{ 76950397Sobrien if (label) 77050397Sobrien { 77150397Sobrien register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; 77250397Sobrien 77350397Sobrien if (*label == 0) 77450397Sobrien label = dwarf2out_cfi_label (); 77550397Sobrien 77650397Sobrien if (fde->dw_fde_current_label == NULL 77750397Sobrien || strcmp (label, fde->dw_fde_current_label) != 0) 77850397Sobrien { 77950397Sobrien register dw_cfi_ref xcfi; 78050397Sobrien 78150397Sobrien fde->dw_fde_current_label = label = xstrdup (label); 78250397Sobrien 78350397Sobrien /* Set the location counter to the new label. */ 78450397Sobrien xcfi = new_cfi (); 78550397Sobrien xcfi->dw_cfi_opc = DW_CFA_advance_loc4; 78650397Sobrien xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; 78750397Sobrien add_cfi (&fde->dw_fde_cfi, xcfi); 78850397Sobrien } 78950397Sobrien 79050397Sobrien add_cfi (&fde->dw_fde_cfi, cfi); 79150397Sobrien } 79250397Sobrien 79350397Sobrien else 79450397Sobrien add_cfi (&cie_cfi_head, cfi); 79550397Sobrien} 79650397Sobrien 79750397Sobrien/* Subroutine of lookup_cfa. */ 79850397Sobrien 79950397Sobrienstatic inline void 80050397Sobrienlookup_cfa_1 (cfi, regp, offsetp) 80150397Sobrien register dw_cfi_ref cfi; 80250397Sobrien register unsigned long *regp; 80350397Sobrien register long *offsetp; 80450397Sobrien{ 80550397Sobrien switch (cfi->dw_cfi_opc) 80650397Sobrien { 80750397Sobrien case DW_CFA_def_cfa_offset: 80850397Sobrien *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset; 80950397Sobrien break; 81050397Sobrien case DW_CFA_def_cfa_register: 81150397Sobrien *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; 81250397Sobrien break; 81350397Sobrien case DW_CFA_def_cfa: 81450397Sobrien *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; 81550397Sobrien *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset; 81650397Sobrien break; 81750397Sobrien default: 81850397Sobrien break; 81950397Sobrien } 82050397Sobrien} 82150397Sobrien 82250397Sobrien/* Find the previous value for the CFA. */ 82350397Sobrien 82450397Sobrienstatic void 82550397Sobrienlookup_cfa (regp, offsetp) 82650397Sobrien register unsigned long *regp; 82750397Sobrien register long *offsetp; 82850397Sobrien{ 82950397Sobrien register dw_cfi_ref cfi; 83050397Sobrien 83150397Sobrien *regp = (unsigned long) -1; 83250397Sobrien *offsetp = 0; 83350397Sobrien 83450397Sobrien for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) 83550397Sobrien lookup_cfa_1 (cfi, regp, offsetp); 83650397Sobrien 83750397Sobrien if (fde_table_in_use) 83850397Sobrien { 83950397Sobrien register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; 84050397Sobrien for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) 84150397Sobrien lookup_cfa_1 (cfi, regp, offsetp); 84250397Sobrien } 84350397Sobrien} 84450397Sobrien 84550397Sobrien/* The current rule for calculating the DWARF2 canonical frame address. */ 84650397Sobrienstatic unsigned long cfa_reg; 84750397Sobrienstatic long cfa_offset; 84850397Sobrien 84950397Sobrien/* The register used for saving registers to the stack, and its offset 85050397Sobrien from the CFA. */ 85150397Sobrienstatic unsigned cfa_store_reg; 85250397Sobrienstatic long cfa_store_offset; 85350397Sobrien 85450397Sobrien/* The running total of the size of arguments pushed onto the stack. */ 85550397Sobrienstatic long args_size; 85650397Sobrien 85750397Sobrien/* The last args_size we actually output. */ 85850397Sobrienstatic long old_args_size; 85950397Sobrien 86050397Sobrien/* Entry point to update the canonical frame address (CFA). 86150397Sobrien LABEL is passed to add_fde_cfi. The value of CFA is now to be 86250397Sobrien calculated from REG+OFFSET. */ 86350397Sobrien 86450397Sobrienvoid 86550397Sobriendwarf2out_def_cfa (label, reg, offset) 86650397Sobrien register char *label; 86750397Sobrien register unsigned reg; 86850397Sobrien register long offset; 86950397Sobrien{ 87050397Sobrien register dw_cfi_ref cfi; 87150397Sobrien unsigned long old_reg; 87250397Sobrien long old_offset; 87350397Sobrien 87450397Sobrien cfa_reg = reg; 87550397Sobrien cfa_offset = offset; 87650397Sobrien if (cfa_store_reg == reg) 87750397Sobrien cfa_store_offset = offset; 87850397Sobrien 87950397Sobrien reg = DWARF_FRAME_REGNUM (reg); 88050397Sobrien lookup_cfa (&old_reg, &old_offset); 88150397Sobrien 88250397Sobrien if (reg == old_reg && offset == old_offset) 88350397Sobrien return; 88450397Sobrien 88550397Sobrien cfi = new_cfi (); 88650397Sobrien 88750397Sobrien if (reg == old_reg) 88850397Sobrien { 88950397Sobrien cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; 89050397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_offset = offset; 89150397Sobrien } 89250397Sobrien 89350397Sobrien#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ 89450397Sobrien else if (offset == old_offset && old_reg != (unsigned long) -1) 89550397Sobrien { 89650397Sobrien cfi->dw_cfi_opc = DW_CFA_def_cfa_register; 89750397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; 89850397Sobrien } 89950397Sobrien#endif 90050397Sobrien 90150397Sobrien else 90250397Sobrien { 90350397Sobrien cfi->dw_cfi_opc = DW_CFA_def_cfa; 90450397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; 90550397Sobrien cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; 90650397Sobrien } 90750397Sobrien 90850397Sobrien add_fde_cfi (label, cfi); 90950397Sobrien} 91050397Sobrien 91150397Sobrien/* Add the CFI for saving a register. REG is the CFA column number. 91250397Sobrien LABEL is passed to add_fde_cfi. 91350397Sobrien If SREG is -1, the register is saved at OFFSET from the CFA; 91450397Sobrien otherwise it is saved in SREG. */ 91550397Sobrien 91650397Sobrienstatic void 91750397Sobrienreg_save (label, reg, sreg, offset) 91850397Sobrien register char * label; 91950397Sobrien register unsigned reg; 92050397Sobrien register unsigned sreg; 92150397Sobrien register long offset; 92250397Sobrien{ 92350397Sobrien register dw_cfi_ref cfi = new_cfi (); 92450397Sobrien 92550397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; 92650397Sobrien 92750397Sobrien /* The following comparison is correct. -1 is used to indicate that 92850397Sobrien the value isn't a register number. */ 92950397Sobrien if (sreg == (unsigned int) -1) 93050397Sobrien { 93150397Sobrien if (reg & ~0x3f) 93250397Sobrien /* The register number won't fit in 6 bits, so we have to use 93350397Sobrien the long form. */ 93450397Sobrien cfi->dw_cfi_opc = DW_CFA_offset_extended; 93550397Sobrien else 93650397Sobrien cfi->dw_cfi_opc = DW_CFA_offset; 93750397Sobrien 93850397Sobrien offset /= DWARF_CIE_DATA_ALIGNMENT; 93950397Sobrien if (offset < 0) 94050397Sobrien abort (); 94150397Sobrien cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; 94250397Sobrien } 94350397Sobrien else 94450397Sobrien { 94550397Sobrien cfi->dw_cfi_opc = DW_CFA_register; 94650397Sobrien cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg; 94750397Sobrien } 94850397Sobrien 94950397Sobrien add_fde_cfi (label, cfi); 95050397Sobrien} 95150397Sobrien 95250397Sobrien/* Add the CFI for saving a register window. LABEL is passed to reg_save. 95350397Sobrien This CFI tells the unwinder that it needs to restore the window registers 95450397Sobrien from the previous frame's window save area. 95550397Sobrien 95650397Sobrien ??? Perhaps we should note in the CIE where windows are saved (instead of 95750397Sobrien assuming 0(cfa)) and what registers are in the window. */ 95850397Sobrien 95950397Sobrienvoid 96050397Sobriendwarf2out_window_save (label) 96150397Sobrien register char * label; 96250397Sobrien{ 96350397Sobrien register dw_cfi_ref cfi = new_cfi (); 96450397Sobrien cfi->dw_cfi_opc = DW_CFA_GNU_window_save; 96550397Sobrien add_fde_cfi (label, cfi); 96650397Sobrien} 96750397Sobrien 96850397Sobrien/* Add a CFI to update the running total of the size of arguments 96950397Sobrien pushed onto the stack. */ 97050397Sobrien 97150397Sobrienvoid 97250397Sobriendwarf2out_args_size (label, size) 97350397Sobrien char *label; 97450397Sobrien long size; 97550397Sobrien{ 97650397Sobrien register dw_cfi_ref cfi; 97750397Sobrien 97850397Sobrien if (size == old_args_size) 97950397Sobrien return; 98050397Sobrien old_args_size = size; 98150397Sobrien 98250397Sobrien cfi = new_cfi (); 98350397Sobrien cfi->dw_cfi_opc = DW_CFA_GNU_args_size; 98450397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_offset = size; 98550397Sobrien add_fde_cfi (label, cfi); 98650397Sobrien} 98750397Sobrien 98850397Sobrien/* Entry point for saving a register to the stack. REG is the GCC register 98950397Sobrien number. LABEL and OFFSET are passed to reg_save. */ 99050397Sobrien 99150397Sobrienvoid 99250397Sobriendwarf2out_reg_save (label, reg, offset) 99350397Sobrien register char * label; 99450397Sobrien register unsigned reg; 99550397Sobrien register long offset; 99650397Sobrien{ 99750397Sobrien reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset); 99850397Sobrien} 99950397Sobrien 100050397Sobrien/* Entry point for saving the return address in the stack. 100150397Sobrien LABEL and OFFSET are passed to reg_save. */ 100250397Sobrien 100350397Sobrienvoid 100450397Sobriendwarf2out_return_save (label, offset) 100550397Sobrien register char * label; 100650397Sobrien register long offset; 100750397Sobrien{ 100850397Sobrien reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset); 100950397Sobrien} 101050397Sobrien 101150397Sobrien/* Entry point for saving the return address in a register. 101250397Sobrien LABEL and SREG are passed to reg_save. */ 101350397Sobrien 101450397Sobrienvoid 101550397Sobriendwarf2out_return_reg (label, sreg) 101650397Sobrien register char * label; 101750397Sobrien register unsigned sreg; 101850397Sobrien{ 101950397Sobrien reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0); 102050397Sobrien} 102150397Sobrien 102250397Sobrien/* Record the initial position of the return address. RTL is 102350397Sobrien INCOMING_RETURN_ADDR_RTX. */ 102450397Sobrien 102550397Sobrienstatic void 102650397Sobrieninitial_return_save (rtl) 102750397Sobrien register rtx rtl; 102850397Sobrien{ 102950397Sobrien unsigned reg = -1; 103050397Sobrien long offset = 0; 103150397Sobrien 103250397Sobrien switch (GET_CODE (rtl)) 103350397Sobrien { 103450397Sobrien case REG: 103550397Sobrien /* RA is in a register. */ 103650397Sobrien reg = reg_number (rtl); 103750397Sobrien break; 103850397Sobrien case MEM: 103950397Sobrien /* RA is on the stack. */ 104050397Sobrien rtl = XEXP (rtl, 0); 104150397Sobrien switch (GET_CODE (rtl)) 104250397Sobrien { 104350397Sobrien case REG: 104450397Sobrien if (REGNO (rtl) != STACK_POINTER_REGNUM) 104550397Sobrien abort (); 104650397Sobrien offset = 0; 104750397Sobrien break; 104850397Sobrien case PLUS: 104950397Sobrien if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) 105050397Sobrien abort (); 105150397Sobrien offset = INTVAL (XEXP (rtl, 1)); 105250397Sobrien break; 105350397Sobrien case MINUS: 105450397Sobrien if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) 105550397Sobrien abort (); 105650397Sobrien offset = -INTVAL (XEXP (rtl, 1)); 105750397Sobrien break; 105850397Sobrien default: 105950397Sobrien abort (); 106050397Sobrien } 106150397Sobrien break; 106250397Sobrien case PLUS: 106350397Sobrien /* The return address is at some offset from any value we can 106450397Sobrien actually load. For instance, on the SPARC it is in %i7+8. Just 106550397Sobrien ignore the offset for now; it doesn't matter for unwinding frames. */ 106650397Sobrien if (GET_CODE (XEXP (rtl, 1)) != CONST_INT) 106750397Sobrien abort (); 106850397Sobrien initial_return_save (XEXP (rtl, 0)); 106950397Sobrien return; 107050397Sobrien default: 107150397Sobrien abort (); 107250397Sobrien } 107350397Sobrien 107450397Sobrien reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset); 107550397Sobrien} 107650397Sobrien 107750397Sobrien/* Check INSN to see if it looks like a push or a stack adjustment, and 107850397Sobrien make a note of it if it does. EH uses this information to find out how 107950397Sobrien much extra space it needs to pop off the stack. */ 108050397Sobrien 108150397Sobrienstatic void 108250397Sobriendwarf2out_stack_adjust (insn) 108350397Sobrien rtx insn; 108450397Sobrien{ 108550397Sobrien long offset; 108650397Sobrien char *label; 108750397Sobrien 108850397Sobrien if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN) 108950397Sobrien { 109050397Sobrien /* Extract the size of the args from the CALL rtx itself. */ 109150397Sobrien 109250397Sobrien insn = PATTERN (insn); 109350397Sobrien if (GET_CODE (insn) == PARALLEL) 109450397Sobrien insn = XVECEXP (insn, 0, 0); 109550397Sobrien if (GET_CODE (insn) == SET) 109650397Sobrien insn = SET_SRC (insn); 109750397Sobrien assert (GET_CODE (insn) == CALL); 109850397Sobrien dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); 109950397Sobrien return; 110050397Sobrien } 110150397Sobrien 110250397Sobrien /* If only calls can throw, and we have a frame pointer, 110350397Sobrien save up adjustments until we see the CALL_INSN. */ 110450397Sobrien else if (! asynchronous_exceptions 110550397Sobrien && cfa_reg != STACK_POINTER_REGNUM) 110650397Sobrien return; 110750397Sobrien 110850397Sobrien if (GET_CODE (insn) == BARRIER) 110950397Sobrien { 111050397Sobrien /* When we see a BARRIER, we know to reset args_size to 0. Usually 111150397Sobrien the compiler will have already emitted a stack adjustment, but 111250397Sobrien doesn't bother for calls to noreturn functions. */ 111350397Sobrien#ifdef STACK_GROWS_DOWNWARD 111450397Sobrien offset = -args_size; 111550397Sobrien#else 111650397Sobrien offset = args_size; 111750397Sobrien#endif 111850397Sobrien } 111950397Sobrien else if (GET_CODE (PATTERN (insn)) == SET) 112050397Sobrien { 112150397Sobrien rtx src, dest; 112250397Sobrien enum rtx_code code; 112350397Sobrien 112450397Sobrien insn = PATTERN (insn); 112550397Sobrien src = SET_SRC (insn); 112650397Sobrien dest = SET_DEST (insn); 112750397Sobrien 112850397Sobrien if (dest == stack_pointer_rtx) 112950397Sobrien { 113050397Sobrien /* (set (reg sp) (plus (reg sp) (const_int))) */ 113150397Sobrien code = GET_CODE (src); 113250397Sobrien if (! (code == PLUS || code == MINUS) 113350397Sobrien || XEXP (src, 0) != stack_pointer_rtx 113450397Sobrien || GET_CODE (XEXP (src, 1)) != CONST_INT) 113550397Sobrien return; 113650397Sobrien 113750397Sobrien offset = INTVAL (XEXP (src, 1)); 113850397Sobrien } 113950397Sobrien else if (GET_CODE (dest) == MEM) 114050397Sobrien { 114150397Sobrien /* (set (mem (pre_dec (reg sp))) (foo)) */ 114250397Sobrien src = XEXP (dest, 0); 114350397Sobrien code = GET_CODE (src); 114450397Sobrien 114550397Sobrien if (! (code == PRE_DEC || code == PRE_INC) 114650397Sobrien || XEXP (src, 0) != stack_pointer_rtx) 114750397Sobrien return; 114850397Sobrien 114950397Sobrien offset = GET_MODE_SIZE (GET_MODE (dest)); 115050397Sobrien } 115150397Sobrien else 115250397Sobrien return; 115350397Sobrien 115450397Sobrien if (code == PLUS || code == PRE_INC) 115550397Sobrien offset = -offset; 115650397Sobrien } 115750397Sobrien else 115850397Sobrien return; 115950397Sobrien 116050397Sobrien if (offset == 0) 116150397Sobrien return; 116250397Sobrien 116350397Sobrien if (cfa_reg == STACK_POINTER_REGNUM) 116450397Sobrien cfa_offset += offset; 116550397Sobrien 116650397Sobrien#ifndef STACK_GROWS_DOWNWARD 116750397Sobrien offset = -offset; 116850397Sobrien#endif 116950397Sobrien args_size += offset; 117050397Sobrien if (args_size < 0) 117150397Sobrien args_size = 0; 117250397Sobrien 117350397Sobrien label = dwarf2out_cfi_label (); 117450397Sobrien dwarf2out_def_cfa (label, cfa_reg, cfa_offset); 117550397Sobrien dwarf2out_args_size (label, args_size); 117650397Sobrien} 117750397Sobrien 117850397Sobrien/* Record call frame debugging information for INSN, which either 117950397Sobrien sets SP or FP (adjusting how we calculate the frame address) or saves a 118050397Sobrien register to the stack. If INSN is NULL_RTX, initialize our state. */ 118150397Sobrien 118250397Sobrienvoid 118350397Sobriendwarf2out_frame_debug (insn) 118450397Sobrien rtx insn; 118550397Sobrien{ 118650397Sobrien char *label; 118750397Sobrien rtx src, dest; 118850397Sobrien long offset; 118950397Sobrien 119050397Sobrien /* A temporary register used in adjusting SP or setting up the store_reg. */ 119150397Sobrien static unsigned cfa_temp_reg; 119250397Sobrien static long cfa_temp_value; 119350397Sobrien 119450397Sobrien if (insn == NULL_RTX) 119550397Sobrien { 119650397Sobrien /* Set up state for generating call frame debug info. */ 119750397Sobrien lookup_cfa (&cfa_reg, &cfa_offset); 119850397Sobrien if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)) 119950397Sobrien abort (); 120050397Sobrien cfa_reg = STACK_POINTER_REGNUM; 120150397Sobrien cfa_store_reg = cfa_reg; 120250397Sobrien cfa_store_offset = cfa_offset; 120350397Sobrien cfa_temp_reg = -1; 120450397Sobrien cfa_temp_value = 0; 120550397Sobrien return; 120650397Sobrien } 120750397Sobrien 120850397Sobrien if (! RTX_FRAME_RELATED_P (insn)) 120950397Sobrien { 121050397Sobrien dwarf2out_stack_adjust (insn); 121150397Sobrien return; 121250397Sobrien } 121350397Sobrien 121450397Sobrien label = dwarf2out_cfi_label (); 121550397Sobrien 121650397Sobrien insn = PATTERN (insn); 121750397Sobrien /* Assume that in a PARALLEL prologue insn, only the first elt is 121850397Sobrien significant. Currently this is true. */ 121950397Sobrien if (GET_CODE (insn) == PARALLEL) 122050397Sobrien insn = XVECEXP (insn, 0, 0); 122150397Sobrien if (GET_CODE (insn) != SET) 122250397Sobrien abort (); 122350397Sobrien 122450397Sobrien src = SET_SRC (insn); 122550397Sobrien dest = SET_DEST (insn); 122650397Sobrien 122750397Sobrien switch (GET_CODE (dest)) 122850397Sobrien { 122950397Sobrien case REG: 123050397Sobrien /* Update the CFA rule wrt SP or FP. Make sure src is 123150397Sobrien relative to the current CFA register. */ 123250397Sobrien switch (GET_CODE (src)) 123350397Sobrien { 123450397Sobrien /* Setting FP from SP. */ 123550397Sobrien case REG: 123650397Sobrien if (cfa_reg != REGNO (src)) 123750397Sobrien abort (); 123850397Sobrien if (REGNO (dest) != STACK_POINTER_REGNUM 123950397Sobrien && !(frame_pointer_needed 124050397Sobrien && REGNO (dest) == HARD_FRAME_POINTER_REGNUM)) 124150397Sobrien abort (); 124250397Sobrien cfa_reg = REGNO (dest); 124350397Sobrien break; 124450397Sobrien 124550397Sobrien case PLUS: 124650397Sobrien case MINUS: 124750397Sobrien if (dest == stack_pointer_rtx) 124850397Sobrien { 124950397Sobrien /* Adjusting SP. */ 125050397Sobrien switch (GET_CODE (XEXP (src, 1))) 125150397Sobrien { 125250397Sobrien case CONST_INT: 125350397Sobrien offset = INTVAL (XEXP (src, 1)); 125450397Sobrien break; 125550397Sobrien case REG: 125650397Sobrien if (REGNO (XEXP (src, 1)) != cfa_temp_reg) 125750397Sobrien abort (); 125850397Sobrien offset = cfa_temp_value; 125950397Sobrien break; 126050397Sobrien default: 126150397Sobrien abort (); 126250397Sobrien } 126350397Sobrien 126450397Sobrien if (XEXP (src, 0) == hard_frame_pointer_rtx) 126550397Sobrien { 126650397Sobrien /* Restoring SP from FP in the epilogue. */ 126750397Sobrien if (cfa_reg != HARD_FRAME_POINTER_REGNUM) 126850397Sobrien abort (); 126950397Sobrien cfa_reg = STACK_POINTER_REGNUM; 127050397Sobrien } 127150397Sobrien else if (XEXP (src, 0) != stack_pointer_rtx) 127250397Sobrien abort (); 127350397Sobrien 127450397Sobrien if (GET_CODE (src) == PLUS) 127550397Sobrien offset = -offset; 127650397Sobrien if (cfa_reg == STACK_POINTER_REGNUM) 127750397Sobrien cfa_offset += offset; 127850397Sobrien if (cfa_store_reg == STACK_POINTER_REGNUM) 127950397Sobrien cfa_store_offset += offset; 128050397Sobrien } 128150397Sobrien else if (dest == hard_frame_pointer_rtx) 128250397Sobrien { 128350397Sobrien /* Either setting the FP from an offset of the SP, 128450397Sobrien or adjusting the FP */ 128550397Sobrien if (! frame_pointer_needed 128650397Sobrien || REGNO (dest) != HARD_FRAME_POINTER_REGNUM) 128750397Sobrien abort (); 128850397Sobrien 128950397Sobrien if (XEXP (src, 0) == stack_pointer_rtx 129050397Sobrien && GET_CODE (XEXP (src, 1)) == CONST_INT) 129150397Sobrien { 129250397Sobrien if (cfa_reg != STACK_POINTER_REGNUM) 129350397Sobrien abort (); 129450397Sobrien offset = INTVAL (XEXP (src, 1)); 129550397Sobrien if (GET_CODE (src) == PLUS) 129650397Sobrien offset = -offset; 129750397Sobrien cfa_offset += offset; 129850397Sobrien cfa_reg = HARD_FRAME_POINTER_REGNUM; 129950397Sobrien } 130050397Sobrien else if (XEXP (src, 0) == hard_frame_pointer_rtx 130150397Sobrien && GET_CODE (XEXP (src, 1)) == CONST_INT) 130250397Sobrien { 130350397Sobrien if (cfa_reg != HARD_FRAME_POINTER_REGNUM) 130450397Sobrien abort (); 130550397Sobrien offset = INTVAL (XEXP (src, 1)); 130650397Sobrien if (GET_CODE (src) == PLUS) 130750397Sobrien offset = -offset; 130850397Sobrien cfa_offset += offset; 130950397Sobrien } 131050397Sobrien 131150397Sobrien else 131250397Sobrien abort(); 131350397Sobrien } 131450397Sobrien else 131550397Sobrien { 131650397Sobrien if (GET_CODE (src) != PLUS 131750397Sobrien || XEXP (src, 1) != stack_pointer_rtx) 131850397Sobrien abort (); 131950397Sobrien if (GET_CODE (XEXP (src, 0)) != REG 132050397Sobrien || REGNO (XEXP (src, 0)) != cfa_temp_reg) 132150397Sobrien abort (); 132250397Sobrien if (cfa_reg != STACK_POINTER_REGNUM) 132350397Sobrien abort (); 132450397Sobrien cfa_store_reg = REGNO (dest); 132550397Sobrien cfa_store_offset = cfa_offset - cfa_temp_value; 132650397Sobrien } 132750397Sobrien break; 132850397Sobrien 132950397Sobrien case CONST_INT: 133050397Sobrien cfa_temp_reg = REGNO (dest); 133150397Sobrien cfa_temp_value = INTVAL (src); 133250397Sobrien break; 133350397Sobrien 133450397Sobrien case IOR: 133550397Sobrien if (GET_CODE (XEXP (src, 0)) != REG 133650397Sobrien || REGNO (XEXP (src, 0)) != cfa_temp_reg 133750397Sobrien || REGNO (dest) != cfa_temp_reg 133850397Sobrien || GET_CODE (XEXP (src, 1)) != CONST_INT) 133950397Sobrien abort (); 134050397Sobrien cfa_temp_value |= INTVAL (XEXP (src, 1)); 134150397Sobrien break; 134250397Sobrien 134350397Sobrien default: 134450397Sobrien abort (); 134550397Sobrien } 134650397Sobrien dwarf2out_def_cfa (label, cfa_reg, cfa_offset); 134750397Sobrien break; 134850397Sobrien 134950397Sobrien case MEM: 135050397Sobrien /* Saving a register to the stack. Make sure dest is relative to the 135150397Sobrien CFA register. */ 135250397Sobrien if (GET_CODE (src) != REG) 135350397Sobrien abort (); 135450397Sobrien switch (GET_CODE (XEXP (dest, 0))) 135550397Sobrien { 135650397Sobrien /* With a push. */ 135750397Sobrien case PRE_INC: 135850397Sobrien case PRE_DEC: 135950397Sobrien offset = GET_MODE_SIZE (GET_MODE (dest)); 136050397Sobrien if (GET_CODE (XEXP (dest, 0)) == PRE_INC) 136150397Sobrien offset = -offset; 136250397Sobrien 136350397Sobrien if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM 136450397Sobrien || cfa_store_reg != STACK_POINTER_REGNUM) 136550397Sobrien abort (); 136650397Sobrien cfa_store_offset += offset; 136750397Sobrien if (cfa_reg == STACK_POINTER_REGNUM) 136850397Sobrien cfa_offset = cfa_store_offset; 136950397Sobrien 137050397Sobrien offset = -cfa_store_offset; 137150397Sobrien break; 137250397Sobrien 137350397Sobrien /* With an offset. */ 137450397Sobrien case PLUS: 137550397Sobrien case MINUS: 137650397Sobrien offset = INTVAL (XEXP (XEXP (dest, 0), 1)); 137750397Sobrien if (GET_CODE (src) == MINUS) 137850397Sobrien offset = -offset; 137950397Sobrien 138050397Sobrien if (cfa_store_reg != REGNO (XEXP (XEXP (dest, 0), 0))) 138150397Sobrien abort (); 138250397Sobrien offset -= cfa_store_offset; 138350397Sobrien break; 138450397Sobrien 138550397Sobrien default: 138650397Sobrien abort (); 138750397Sobrien } 138850397Sobrien dwarf2out_def_cfa (label, cfa_reg, cfa_offset); 138950397Sobrien dwarf2out_reg_save (label, REGNO (src), offset); 139050397Sobrien break; 139150397Sobrien 139250397Sobrien default: 139350397Sobrien abort (); 139450397Sobrien } 139550397Sobrien} 139650397Sobrien 139750397Sobrien/* Return the size of an unsigned LEB128 quantity. */ 139850397Sobrien 139950397Sobrienstatic inline unsigned long 140050397Sobriensize_of_uleb128 (value) 140150397Sobrien register unsigned long value; 140250397Sobrien{ 140350397Sobrien register unsigned long size = 0; 140450397Sobrien register unsigned byte; 140550397Sobrien 140650397Sobrien do 140750397Sobrien { 140850397Sobrien byte = (value & 0x7f); 140950397Sobrien value >>= 7; 141050397Sobrien size += 1; 141150397Sobrien } 141250397Sobrien while (value != 0); 141350397Sobrien 141450397Sobrien return size; 141550397Sobrien} 141650397Sobrien 141750397Sobrien/* Return the size of a signed LEB128 quantity. */ 141850397Sobrien 141950397Sobrienstatic inline unsigned long 142050397Sobriensize_of_sleb128 (value) 142150397Sobrien register long value; 142250397Sobrien{ 142350397Sobrien register unsigned long size = 0; 142450397Sobrien register unsigned byte; 142550397Sobrien 142650397Sobrien do 142750397Sobrien { 142850397Sobrien byte = (value & 0x7f); 142950397Sobrien value >>= 7; 143050397Sobrien size += 1; 143150397Sobrien } 143250397Sobrien while (!(((value == 0) && ((byte & 0x40) == 0)) 143350397Sobrien || ((value == -1) && ((byte & 0x40) != 0)))); 143450397Sobrien 143550397Sobrien return size; 143650397Sobrien} 143750397Sobrien 143850397Sobrien/* Output an unsigned LEB128 quantity. */ 143950397Sobrien 144050397Sobrienstatic void 144150397Sobrienoutput_uleb128 (value) 144250397Sobrien register unsigned long value; 144350397Sobrien{ 144450397Sobrien unsigned long save_value = value; 144550397Sobrien 144650397Sobrien fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); 144750397Sobrien do 144850397Sobrien { 144950397Sobrien register unsigned byte = (value & 0x7f); 145050397Sobrien value >>= 7; 145150397Sobrien if (value != 0) 145250397Sobrien /* More bytes to follow. */ 145350397Sobrien byte |= 0x80; 145450397Sobrien 145550397Sobrien fprintf (asm_out_file, "0x%x", byte); 145650397Sobrien if (value != 0) 145750397Sobrien fprintf (asm_out_file, ","); 145850397Sobrien } 145950397Sobrien while (value != 0); 146050397Sobrien 146150397Sobrien if (flag_debug_asm) 146250397Sobrien fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value); 146350397Sobrien} 146450397Sobrien 146550397Sobrien/* Output an signed LEB128 quantity. */ 146650397Sobrien 146750397Sobrienstatic void 146850397Sobrienoutput_sleb128 (value) 146950397Sobrien register long value; 147050397Sobrien{ 147150397Sobrien register int more; 147250397Sobrien register unsigned byte; 147350397Sobrien long save_value = value; 147450397Sobrien 147550397Sobrien fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); 147650397Sobrien do 147750397Sobrien { 147850397Sobrien byte = (value & 0x7f); 147950397Sobrien /* arithmetic shift */ 148050397Sobrien value >>= 7; 148150397Sobrien more = !((((value == 0) && ((byte & 0x40) == 0)) 148250397Sobrien || ((value == -1) && ((byte & 0x40) != 0)))); 148350397Sobrien if (more) 148450397Sobrien byte |= 0x80; 148550397Sobrien 148650397Sobrien fprintf (asm_out_file, "0x%x", byte); 148750397Sobrien if (more) 148850397Sobrien fprintf (asm_out_file, ","); 148950397Sobrien } 149050397Sobrien 149150397Sobrien while (more); 149250397Sobrien if (flag_debug_asm) 149350397Sobrien fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value); 149450397Sobrien} 149550397Sobrien 149650397Sobrien/* Output a Call Frame Information opcode and its operand(s). */ 149750397Sobrien 149850397Sobrienstatic void 149950397Sobrienoutput_cfi (cfi, fde) 150050397Sobrien register dw_cfi_ref cfi; 150150397Sobrien register dw_fde_ref fde; 150250397Sobrien{ 150350397Sobrien if (cfi->dw_cfi_opc == DW_CFA_advance_loc) 150450397Sobrien { 150550397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 150650397Sobrien cfi->dw_cfi_opc 150750397Sobrien | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)); 150850397Sobrien if (flag_debug_asm) 150950397Sobrien fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx", 151050397Sobrien ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); 151150397Sobrien fputc ('\n', asm_out_file); 151250397Sobrien } 151350397Sobrien 151450397Sobrien else if (cfi->dw_cfi_opc == DW_CFA_offset) 151550397Sobrien { 151650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 151750397Sobrien cfi->dw_cfi_opc 151850397Sobrien | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); 151950397Sobrien if (flag_debug_asm) 152050397Sobrien fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx", 152150397Sobrien ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); 152250397Sobrien 152350397Sobrien fputc ('\n', asm_out_file); 152450397Sobrien output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); 152550397Sobrien fputc ('\n', asm_out_file); 152650397Sobrien } 152750397Sobrien else if (cfi->dw_cfi_opc == DW_CFA_restore) 152850397Sobrien { 152950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 153050397Sobrien cfi->dw_cfi_opc 153150397Sobrien | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); 153250397Sobrien if (flag_debug_asm) 153350397Sobrien fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx", 153450397Sobrien ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); 153550397Sobrien 153650397Sobrien fputc ('\n', asm_out_file); 153750397Sobrien } 153850397Sobrien else 153950397Sobrien { 154050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc); 154150397Sobrien if (flag_debug_asm) 154250397Sobrien fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, 154350397Sobrien dwarf_cfi_name (cfi->dw_cfi_opc)); 154450397Sobrien 154550397Sobrien fputc ('\n', asm_out_file); 154650397Sobrien switch (cfi->dw_cfi_opc) 154750397Sobrien { 154850397Sobrien case DW_CFA_set_loc: 154950397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr); 155050397Sobrien fputc ('\n', asm_out_file); 155150397Sobrien break; 155250397Sobrien case DW_CFA_advance_loc1: 155350397Sobrien ASM_OUTPUT_DWARF_DELTA1 (asm_out_file, 155450397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_addr, 155550397Sobrien fde->dw_fde_current_label); 155650397Sobrien fputc ('\n', asm_out_file); 155750397Sobrien fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; 155850397Sobrien break; 155950397Sobrien case DW_CFA_advance_loc2: 156050397Sobrien ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, 156150397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_addr, 156250397Sobrien fde->dw_fde_current_label); 156350397Sobrien fputc ('\n', asm_out_file); 156450397Sobrien fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; 156550397Sobrien break; 156650397Sobrien case DW_CFA_advance_loc4: 156750397Sobrien ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, 156850397Sobrien cfi->dw_cfi_oprnd1.dw_cfi_addr, 156950397Sobrien fde->dw_fde_current_label); 157050397Sobrien fputc ('\n', asm_out_file); 157150397Sobrien fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; 157250397Sobrien break; 157350397Sobrien#ifdef MIPS_DEBUGGING_INFO 157450397Sobrien case DW_CFA_MIPS_advance_loc8: 157550397Sobrien /* TODO: not currently implemented. */ 157650397Sobrien abort (); 157750397Sobrien break; 157850397Sobrien#endif 157950397Sobrien case DW_CFA_offset_extended: 158050397Sobrien case DW_CFA_def_cfa: 158150397Sobrien output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); 158250397Sobrien fputc ('\n', asm_out_file); 158350397Sobrien output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); 158450397Sobrien fputc ('\n', asm_out_file); 158550397Sobrien break; 158650397Sobrien case DW_CFA_restore_extended: 158750397Sobrien case DW_CFA_undefined: 158850397Sobrien output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); 158950397Sobrien fputc ('\n', asm_out_file); 159050397Sobrien break; 159150397Sobrien case DW_CFA_same_value: 159250397Sobrien case DW_CFA_def_cfa_register: 159350397Sobrien output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); 159450397Sobrien fputc ('\n', asm_out_file); 159550397Sobrien break; 159650397Sobrien case DW_CFA_register: 159750397Sobrien output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); 159850397Sobrien fputc ('\n', asm_out_file); 159950397Sobrien output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num); 160050397Sobrien fputc ('\n', asm_out_file); 160150397Sobrien break; 160250397Sobrien case DW_CFA_def_cfa_offset: 160350397Sobrien output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); 160450397Sobrien fputc ('\n', asm_out_file); 160550397Sobrien break; 160650397Sobrien case DW_CFA_GNU_window_save: 160750397Sobrien break; 160850397Sobrien case DW_CFA_GNU_args_size: 160950397Sobrien output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); 161050397Sobrien fputc ('\n', asm_out_file); 161150397Sobrien break; 161250397Sobrien default: 161350397Sobrien break; 161450397Sobrien } 161550397Sobrien } 161650397Sobrien} 161750397Sobrien 161850397Sobrien#if !defined (EH_FRAME_SECTION) 161950397Sobrien#if defined (EH_FRAME_SECTION_ASM_OP) 162050397Sobrien#define EH_FRAME_SECTION() eh_frame_section(); 162150397Sobrien#else 162250397Sobrien#if defined (ASM_OUTPUT_SECTION_NAME) 162350397Sobrien#define EH_FRAME_SECTION() \ 162450397Sobrien do { \ 162550397Sobrien named_section (NULL_TREE, ".eh_frame", 0); \ 162650397Sobrien } while (0) 162750397Sobrien#endif 162850397Sobrien#endif 162950397Sobrien#endif 163050397Sobrien 163150397Sobrien/* If we aren't using crtstuff to run ctors, don't use it for EH. */ 163250397Sobrien#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP) 163350397Sobrien#undef EH_FRAME_SECTION 163450397Sobrien#endif 163550397Sobrien 163650397Sobrien/* Output the call frame information used to used to record information 163750397Sobrien that relates to calculating the frame pointer, and records the 163850397Sobrien location of saved registers. */ 163950397Sobrien 164050397Sobrienstatic void 164150397Sobrienoutput_call_frame_info (for_eh) 164250397Sobrien int for_eh; 164350397Sobrien{ 164450397Sobrien register unsigned long i; 164550397Sobrien register dw_fde_ref fde; 164650397Sobrien register dw_cfi_ref cfi; 164750397Sobrien char l1[20], l2[20]; 164850397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL 164950397Sobrien char ld[20]; 165050397Sobrien#endif 165150397Sobrien 165250397Sobrien /* Do we want to include a pointer to the exception table? */ 165350397Sobrien int eh_ptr = for_eh && exception_table_p (); 165450397Sobrien 165550397Sobrien fputc ('\n', asm_out_file); 165650397Sobrien 165750397Sobrien /* We're going to be generating comments, so turn on app. */ 165850397Sobrien if (flag_debug_asm) 165950397Sobrien app_enable (); 166050397Sobrien 166150397Sobrien if (for_eh) 166250397Sobrien { 166350397Sobrien#ifdef EH_FRAME_SECTION 166450397Sobrien EH_FRAME_SECTION (); 166550397Sobrien#else 166650397Sobrien tree label = get_file_function_name ('F'); 166750397Sobrien 166850397Sobrien data_section (); 166950397Sobrien ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); 167050397Sobrien ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); 167150397Sobrien ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); 167250397Sobrien#endif 167350397Sobrien assemble_label ("__FRAME_BEGIN__"); 167450397Sobrien } 167550397Sobrien else 167650397Sobrien ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION); 167750397Sobrien 167850397Sobrien /* Output the CIE. */ 167950397Sobrien ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh); 168050397Sobrien ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh); 168150397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL 168250397Sobrien ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh); 168350397Sobrien if (for_eh) 168450397Sobrien ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); 168550397Sobrien else 168650397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); 168750397Sobrien#else 168850397Sobrien if (for_eh) 168950397Sobrien ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); 169050397Sobrien else 169150397Sobrien ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); 169250397Sobrien#endif 169350397Sobrien if (flag_debug_asm) 169450397Sobrien fprintf (asm_out_file, "\t%s Length of Common Information Entry", 169550397Sobrien ASM_COMMENT_START); 169650397Sobrien 169750397Sobrien fputc ('\n', asm_out_file); 169850397Sobrien ASM_OUTPUT_LABEL (asm_out_file, l1); 169950397Sobrien 170050397Sobrien if (for_eh) 170150397Sobrien /* Now that the CIE pointer is PC-relative for EH, 170250397Sobrien use 0 to identify the CIE. */ 170350397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); 170450397Sobrien else 170550397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); 170650397Sobrien 170750397Sobrien if (flag_debug_asm) 170850397Sobrien fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START); 170950397Sobrien 171050397Sobrien fputc ('\n', asm_out_file); 171150397Sobrien if (! for_eh && DWARF_OFFSET_SIZE == 8) 171250397Sobrien { 171350397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); 171450397Sobrien fputc ('\n', asm_out_file); 171550397Sobrien } 171650397Sobrien 171750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION); 171850397Sobrien if (flag_debug_asm) 171950397Sobrien fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START); 172050397Sobrien 172150397Sobrien fputc ('\n', asm_out_file); 172250397Sobrien if (eh_ptr) 172350397Sobrien { 172450397Sobrien /* The CIE contains a pointer to the exception region info for the 172550397Sobrien frame. Make the augmentation string three bytes (including the 172650397Sobrien trailing null) so the pointer is 4-byte aligned. The Solaris ld 172750397Sobrien can't handle unaligned relocs. */ 172850397Sobrien if (flag_debug_asm) 172950397Sobrien { 173050397Sobrien ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh"); 173150397Sobrien fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START); 173250397Sobrien } 173350397Sobrien else 173450397Sobrien { 173550397Sobrien ASM_OUTPUT_ASCII (asm_out_file, "eh", 3); 173650397Sobrien } 173750397Sobrien fputc ('\n', asm_out_file); 173850397Sobrien 173950397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__"); 174050397Sobrien if (flag_debug_asm) 174150397Sobrien fprintf (asm_out_file, "\t%s pointer to exception region info", 174250397Sobrien ASM_COMMENT_START); 174350397Sobrien } 174450397Sobrien else 174550397Sobrien { 174650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 174750397Sobrien if (flag_debug_asm) 174850397Sobrien fprintf (asm_out_file, "\t%s CIE Augmentation (none)", 174950397Sobrien ASM_COMMENT_START); 175050397Sobrien } 175150397Sobrien 175250397Sobrien fputc ('\n', asm_out_file); 175350397Sobrien output_uleb128 (1); 175450397Sobrien if (flag_debug_asm) 175550397Sobrien fprintf (asm_out_file, " (CIE Code Alignment Factor)"); 175650397Sobrien 175750397Sobrien fputc ('\n', asm_out_file); 175850397Sobrien output_sleb128 (DWARF_CIE_DATA_ALIGNMENT); 175950397Sobrien if (flag_debug_asm) 176050397Sobrien fprintf (asm_out_file, " (CIE Data Alignment Factor)"); 176150397Sobrien 176250397Sobrien fputc ('\n', asm_out_file); 176350397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN); 176450397Sobrien if (flag_debug_asm) 176550397Sobrien fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START); 176650397Sobrien 176750397Sobrien fputc ('\n', asm_out_file); 176850397Sobrien 176950397Sobrien for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next) 177050397Sobrien output_cfi (cfi, NULL); 177150397Sobrien 177250397Sobrien /* Pad the CIE out to an address sized boundary. */ 177350397Sobrien ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); 177450397Sobrien ASM_OUTPUT_LABEL (asm_out_file, l2); 177550397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL 177650397Sobrien ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); 177750397Sobrien if (flag_debug_asm) 177850397Sobrien fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START); 177950397Sobrien fputc ('\n', asm_out_file); 178050397Sobrien#endif 178150397Sobrien 178250397Sobrien /* Loop through all of the FDE's. */ 178350397Sobrien for (i = 0; i < fde_table_in_use; ++i) 178450397Sobrien { 178550397Sobrien fde = &fde_table[i]; 178650397Sobrien 178750397Sobrien ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2); 178850397Sobrien ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2); 178950397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL 179050397Sobrien ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2); 179150397Sobrien if (for_eh) 179250397Sobrien ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); 179350397Sobrien else 179450397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); 179550397Sobrien#else 179650397Sobrien if (for_eh) 179750397Sobrien ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); 179850397Sobrien else 179950397Sobrien ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); 180050397Sobrien#endif 180150397Sobrien if (flag_debug_asm) 180250397Sobrien fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START); 180350397Sobrien fputc ('\n', asm_out_file); 180450397Sobrien ASM_OUTPUT_LABEL (asm_out_file, l1); 180550397Sobrien 180650397Sobrien if (for_eh) 180750397Sobrien ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, "__FRAME_BEGIN__"); 180850397Sobrien else 180950397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION)); 181050397Sobrien if (flag_debug_asm) 181150397Sobrien fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START); 181250397Sobrien 181350397Sobrien fputc ('\n', asm_out_file); 181450397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin); 181550397Sobrien if (flag_debug_asm) 181650397Sobrien fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START); 181750397Sobrien 181850397Sobrien fputc ('\n', asm_out_file); 181950397Sobrien ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, 182050397Sobrien fde->dw_fde_end, fde->dw_fde_begin); 182150397Sobrien if (flag_debug_asm) 182250397Sobrien fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START); 182350397Sobrien 182450397Sobrien fputc ('\n', asm_out_file); 182550397Sobrien 182650397Sobrien /* Loop through the Call Frame Instructions associated with 182750397Sobrien this FDE. */ 182850397Sobrien fde->dw_fde_current_label = fde->dw_fde_begin; 182950397Sobrien for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) 183050397Sobrien output_cfi (cfi, fde); 183150397Sobrien 183250397Sobrien /* Pad the FDE out to an address sized boundary. */ 183350397Sobrien ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); 183450397Sobrien ASM_OUTPUT_LABEL (asm_out_file, l2); 183550397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL 183650397Sobrien ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); 183750397Sobrien if (flag_debug_asm) 183850397Sobrien fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START); 183950397Sobrien fputc ('\n', asm_out_file); 184050397Sobrien#endif 184150397Sobrien } 184250397Sobrien#ifndef EH_FRAME_SECTION 184350397Sobrien if (for_eh) 184450397Sobrien { 184550397Sobrien /* Emit terminating zero for table. */ 184650397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); 184750397Sobrien fputc ('\n', asm_out_file); 184850397Sobrien } 184950397Sobrien#endif 185050397Sobrien#ifdef MIPS_DEBUGGING_INFO 185150397Sobrien /* Work around Irix 6 assembler bug whereby labels at the end of a section 185250397Sobrien get a value of 0. Putting .align 0 after the label fixes it. */ 185350397Sobrien ASM_OUTPUT_ALIGN (asm_out_file, 0); 185450397Sobrien#endif 185550397Sobrien 185650397Sobrien /* Turn off app to make assembly quicker. */ 185750397Sobrien if (flag_debug_asm) 185850397Sobrien app_disable (); 185950397Sobrien} 186050397Sobrien 186150397Sobrien/* Output a marker (i.e. a label) for the beginning of a function, before 186250397Sobrien the prologue. */ 186350397Sobrien 186450397Sobrienvoid 186550397Sobriendwarf2out_begin_prologue () 186650397Sobrien{ 186750397Sobrien char label[MAX_ARTIFICIAL_LABEL_BYTES]; 186850397Sobrien register dw_fde_ref fde; 186950397Sobrien 187050397Sobrien ++current_funcdef_number; 187150397Sobrien 187250397Sobrien function_section (current_function_decl); 187350397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL, 187450397Sobrien current_funcdef_number); 187550397Sobrien ASM_OUTPUT_LABEL (asm_out_file, label); 187650397Sobrien 187750397Sobrien /* Expand the fde table if necessary. */ 187850397Sobrien if (fde_table_in_use == fde_table_allocated) 187950397Sobrien { 188050397Sobrien fde_table_allocated += FDE_TABLE_INCREMENT; 188150397Sobrien fde_table 188250397Sobrien = (dw_fde_ref) xrealloc (fde_table, 188350397Sobrien fde_table_allocated * sizeof (dw_fde_node)); 188450397Sobrien } 188550397Sobrien 188650397Sobrien /* Record the FDE associated with this function. */ 188750397Sobrien current_funcdef_fde = fde_table_in_use; 188850397Sobrien 188950397Sobrien /* Add the new FDE at the end of the fde_table. */ 189050397Sobrien fde = &fde_table[fde_table_in_use++]; 189150397Sobrien fde->dw_fde_begin = xstrdup (label); 189250397Sobrien fde->dw_fde_current_label = NULL; 189350397Sobrien fde->dw_fde_end = NULL; 189450397Sobrien fde->dw_fde_cfi = NULL; 189550397Sobrien 189650397Sobrien args_size = old_args_size = 0; 189750397Sobrien} 189850397Sobrien 189950397Sobrien/* Output a marker (i.e. a label) for the absolute end of the generated code 190050397Sobrien for a function definition. This gets called *after* the epilogue code has 190150397Sobrien been generated. */ 190250397Sobrien 190350397Sobrienvoid 190450397Sobriendwarf2out_end_epilogue () 190550397Sobrien{ 190650397Sobrien dw_fde_ref fde; 190750397Sobrien char label[MAX_ARTIFICIAL_LABEL_BYTES]; 190850397Sobrien 190950397Sobrien /* Output a label to mark the endpoint of the code generated for this 191050397Sobrien function. */ 191150397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number); 191250397Sobrien ASM_OUTPUT_LABEL (asm_out_file, label); 191350397Sobrien fde = &fde_table[fde_table_in_use - 1]; 191450397Sobrien fde->dw_fde_end = xstrdup (label); 191550397Sobrien} 191650397Sobrien 191750397Sobrienvoid 191850397Sobriendwarf2out_frame_init () 191950397Sobrien{ 192050397Sobrien /* Allocate the initial hunk of the fde_table. */ 192150397Sobrien fde_table 192250397Sobrien = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); 192350397Sobrien bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); 192450397Sobrien fde_table_allocated = FDE_TABLE_INCREMENT; 192550397Sobrien fde_table_in_use = 0; 192650397Sobrien 192750397Sobrien /* Generate the CFA instructions common to all FDE's. Do it now for the 192850397Sobrien sake of lookup_cfa. */ 192950397Sobrien 193050397Sobrien#ifdef DWARF2_UNWIND_INFO 193150397Sobrien /* On entry, the Canonical Frame Address is at SP. */ 193250397Sobrien dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); 193350397Sobrien initial_return_save (INCOMING_RETURN_ADDR_RTX); 193450397Sobrien#endif 193550397Sobrien} 193650397Sobrien 193750397Sobrienvoid 193850397Sobriendwarf2out_frame_finish () 193950397Sobrien{ 194050397Sobrien /* Output call frame information. */ 194150397Sobrien#ifdef MIPS_DEBUGGING_INFO 194250397Sobrien if (write_symbols == DWARF2_DEBUG) 194350397Sobrien output_call_frame_info (0); 194450397Sobrien if (flag_exceptions && ! exceptions_via_longjmp) 194550397Sobrien output_call_frame_info (1); 194650397Sobrien#else 194750397Sobrien if (write_symbols == DWARF2_DEBUG 194850397Sobrien || (flag_exceptions && ! exceptions_via_longjmp)) 194950397Sobrien output_call_frame_info (1); 195050397Sobrien#endif 195150397Sobrien} 195250397Sobrien 195350397Sobrien#endif /* .debug_frame support */ 195450397Sobrien 195550397Sobrien/* And now, the support for symbolic debugging information. */ 195650397Sobrien#ifdef DWARF2_DEBUGGING_INFO 195750397Sobrien 195850397Sobrienextern char *getpwd PROTO((void)); 195950397Sobrien 196050397Sobrien/* NOTE: In the comments in this file, many references are made to 196150397Sobrien "Debugging Information Entries". This term is abbreviated as `DIE' 196250397Sobrien throughout the remainder of this file. */ 196350397Sobrien 196450397Sobrien/* An internal representation of the DWARF output is built, and then 196550397Sobrien walked to generate the DWARF debugging info. The walk of the internal 196650397Sobrien representation is done after the entire program has been compiled. 196750397Sobrien The types below are used to describe the internal representation. */ 196850397Sobrien 196950397Sobrien/* Each DIE may have a series of attribute/value pairs. Values 197050397Sobrien can take on several forms. The forms that are used in this 197150397Sobrien implementation are listed below. */ 197250397Sobrien 197350397Sobrientypedef enum 197450397Sobrien{ 197550397Sobrien dw_val_class_addr, 197650397Sobrien dw_val_class_loc, 197750397Sobrien dw_val_class_const, 197850397Sobrien dw_val_class_unsigned_const, 197950397Sobrien dw_val_class_long_long, 198050397Sobrien dw_val_class_float, 198150397Sobrien dw_val_class_flag, 198250397Sobrien dw_val_class_die_ref, 198350397Sobrien dw_val_class_fde_ref, 198450397Sobrien dw_val_class_lbl_id, 198550397Sobrien dw_val_class_section_offset, 198650397Sobrien dw_val_class_str 198750397Sobrien} 198850397Sobriendw_val_class; 198950397Sobrien 199050397Sobrien/* Various DIE's use offsets relative to the beginning of the 199150397Sobrien .debug_info section to refer to each other. */ 199250397Sobrien 199350397Sobrientypedef long int dw_offset; 199450397Sobrien 199550397Sobrien/* Define typedefs here to avoid circular dependencies. */ 199650397Sobrien 199750397Sobrientypedef struct die_struct *dw_die_ref; 199850397Sobrientypedef struct dw_attr_struct *dw_attr_ref; 199950397Sobrientypedef struct dw_val_struct *dw_val_ref; 200050397Sobrientypedef struct dw_line_info_struct *dw_line_info_ref; 200150397Sobrientypedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; 200250397Sobrientypedef struct dw_loc_descr_struct *dw_loc_descr_ref; 200350397Sobrientypedef struct pubname_struct *pubname_ref; 200450397Sobrientypedef dw_die_ref *arange_ref; 200550397Sobrien 200650397Sobrien/* Describe a double word constant value. */ 200750397Sobrien 200850397Sobrientypedef struct dw_long_long_struct 200950397Sobrien{ 201050397Sobrien unsigned long hi; 201150397Sobrien unsigned long low; 201250397Sobrien} 201350397Sobriendw_long_long_const; 201450397Sobrien 201550397Sobrien/* Describe a floating point constant value. */ 201650397Sobrien 201750397Sobrientypedef struct dw_fp_struct 201850397Sobrien{ 201950397Sobrien long *array; 202050397Sobrien unsigned length; 202150397Sobrien} 202250397Sobriendw_float_const; 202350397Sobrien 202450397Sobrien/* Each entry in the line_info_table maintains the file and 202550397Sobrien line number associated with the label generated for that 202650397Sobrien entry. The label gives the PC value associated with 202750397Sobrien the line number entry. */ 202850397Sobrien 202950397Sobrientypedef struct dw_line_info_struct 203050397Sobrien{ 203150397Sobrien unsigned long dw_file_num; 203250397Sobrien unsigned long dw_line_num; 203350397Sobrien} 203450397Sobriendw_line_info_entry; 203550397Sobrien 203650397Sobrien/* Line information for functions in separate sections; each one gets its 203750397Sobrien own sequence. */ 203850397Sobrientypedef struct dw_separate_line_info_struct 203950397Sobrien{ 204050397Sobrien unsigned long dw_file_num; 204150397Sobrien unsigned long dw_line_num; 204250397Sobrien unsigned long function; 204350397Sobrien} 204450397Sobriendw_separate_line_info_entry; 204550397Sobrien 204650397Sobrien/* The dw_val_node describes an attribute's value, as it is 204750397Sobrien represented internally. */ 204850397Sobrien 204950397Sobrientypedef struct dw_val_struct 205050397Sobrien{ 205150397Sobrien dw_val_class val_class; 205250397Sobrien union 205350397Sobrien { 205450397Sobrien char *val_addr; 205550397Sobrien dw_loc_descr_ref val_loc; 205650397Sobrien long int val_int; 205750397Sobrien long unsigned val_unsigned; 205850397Sobrien dw_long_long_const val_long_long; 205950397Sobrien dw_float_const val_float; 206050397Sobrien dw_die_ref val_die_ref; 206150397Sobrien unsigned val_fde_index; 206250397Sobrien char *val_str; 206350397Sobrien char *val_lbl_id; 206450397Sobrien char *val_section; 206550397Sobrien unsigned char val_flag; 206650397Sobrien } 206750397Sobrien v; 206850397Sobrien} 206950397Sobriendw_val_node; 207050397Sobrien 207150397Sobrien/* Locations in memory are described using a sequence of stack machine 207250397Sobrien operations. */ 207350397Sobrien 207450397Sobrientypedef struct dw_loc_descr_struct 207550397Sobrien{ 207650397Sobrien dw_loc_descr_ref dw_loc_next; 207750397Sobrien enum dwarf_location_atom dw_loc_opc; 207850397Sobrien dw_val_node dw_loc_oprnd1; 207950397Sobrien dw_val_node dw_loc_oprnd2; 208050397Sobrien} 208150397Sobriendw_loc_descr_node; 208250397Sobrien 208350397Sobrien/* Each DIE attribute has a field specifying the attribute kind, 208450397Sobrien a link to the next attribute in the chain, and an attribute value. 208550397Sobrien Attributes are typically linked below the DIE they modify. */ 208650397Sobrien 208750397Sobrientypedef struct dw_attr_struct 208850397Sobrien{ 208950397Sobrien enum dwarf_attribute dw_attr; 209050397Sobrien dw_attr_ref dw_attr_next; 209150397Sobrien dw_val_node dw_attr_val; 209250397Sobrien} 209350397Sobriendw_attr_node; 209450397Sobrien 209550397Sobrien/* The Debugging Information Entry (DIE) structure */ 209650397Sobrien 209750397Sobrientypedef struct die_struct 209850397Sobrien{ 209950397Sobrien enum dwarf_tag die_tag; 210050397Sobrien dw_attr_ref die_attr; 210150397Sobrien dw_attr_ref die_attr_last; 210250397Sobrien dw_die_ref die_parent; 210350397Sobrien dw_die_ref die_child; 210450397Sobrien dw_die_ref die_child_last; 210550397Sobrien dw_die_ref die_sib; 210650397Sobrien dw_offset die_offset; 210750397Sobrien unsigned long die_abbrev; 210850397Sobrien} 210950397Sobriendie_node; 211050397Sobrien 211150397Sobrien/* The pubname structure */ 211250397Sobrien 211350397Sobrientypedef struct pubname_struct 211450397Sobrien{ 211550397Sobrien dw_die_ref die; 211650397Sobrien char * name; 211750397Sobrien} 211850397Sobrienpubname_entry; 211950397Sobrien 212050397Sobrien/* The limbo die list structure. */ 212150397Sobrientypedef struct limbo_die_struct 212250397Sobrien{ 212350397Sobrien dw_die_ref die; 212450397Sobrien struct limbo_die_struct *next; 212550397Sobrien} 212650397Sobrienlimbo_die_node; 212750397Sobrien 212850397Sobrien/* How to start an assembler comment. */ 212950397Sobrien#ifndef ASM_COMMENT_START 213050397Sobrien#define ASM_COMMENT_START ";#" 213150397Sobrien#endif 213250397Sobrien 213350397Sobrien/* Define a macro which returns non-zero for a TYPE_DECL which was 213450397Sobrien implicitly generated for a tagged type. 213550397Sobrien 213650397Sobrien Note that unlike the gcc front end (which generates a NULL named 213750397Sobrien TYPE_DECL node for each complete tagged type, each array type, and 213850397Sobrien each function type node created) the g++ front end generates a 213950397Sobrien _named_ TYPE_DECL node for each tagged type node created. 214050397Sobrien These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to 214150397Sobrien generate a DW_TAG_typedef DIE for them. */ 214250397Sobrien 214350397Sobrien#define TYPE_DECL_IS_STUB(decl) \ 214450397Sobrien (DECL_NAME (decl) == NULL_TREE \ 214550397Sobrien || (DECL_ARTIFICIAL (decl) \ 214650397Sobrien && is_tagged_type (TREE_TYPE (decl)) \ 214750397Sobrien && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \ 214850397Sobrien /* This is necessary for stub decls that \ 214950397Sobrien appear in nested inline functions. */ \ 215050397Sobrien || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \ 215150397Sobrien && (decl_ultimate_origin (decl) \ 215250397Sobrien == TYPE_STUB_DECL (TREE_TYPE (decl))))))) 215350397Sobrien 215450397Sobrien/* Information concerning the compilation unit's programming 215550397Sobrien language, and compiler version. */ 215650397Sobrien 215750397Sobrienextern int flag_traditional; 215850397Sobrienextern char *version_string; 215950397Sobrienextern char *language_string; 216050397Sobrien 216150397Sobrien/* Fixed size portion of the DWARF compilation unit header. */ 216250397Sobrien#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3) 216350397Sobrien 216450397Sobrien/* Fixed size portion of debugging line information prolog. */ 216550397Sobrien#define DWARF_LINE_PROLOG_HEADER_SIZE 5 216650397Sobrien 216750397Sobrien/* Fixed size portion of public names info. */ 216850397Sobrien#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) 216950397Sobrien 217050397Sobrien/* Fixed size portion of the address range info. */ 217150397Sobrien#define DWARF_ARANGES_HEADER_SIZE \ 217250397Sobrien (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE) 217350397Sobrien 217450397Sobrien/* Define the architecture-dependent minimum instruction length (in bytes). 217550397Sobrien In this implementation of DWARF, this field is used for information 217650397Sobrien purposes only. Since GCC generates assembly language, we have 217750397Sobrien no a priori knowledge of how many instruction bytes are generated 217850397Sobrien for each source line, and therefore can use only the DW_LNE_set_address 217950397Sobrien and DW_LNS_fixed_advance_pc line information commands. */ 218050397Sobrien 218150397Sobrien#ifndef DWARF_LINE_MIN_INSTR_LENGTH 218250397Sobrien#define DWARF_LINE_MIN_INSTR_LENGTH 4 218350397Sobrien#endif 218450397Sobrien 218550397Sobrien/* Minimum line offset in a special line info. opcode. 218650397Sobrien This value was chosen to give a reasonable range of values. */ 218750397Sobrien#define DWARF_LINE_BASE -10 218850397Sobrien 218950397Sobrien/* First special line opcde - leave room for the standard opcodes. */ 219050397Sobrien#define DWARF_LINE_OPCODE_BASE 10 219150397Sobrien 219250397Sobrien/* Range of line offsets in a special line info. opcode. */ 219350397Sobrien#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1) 219450397Sobrien 219550397Sobrien/* Flag that indicates the initial value of the is_stmt_start flag. 219650397Sobrien In the present implementation, we do not mark any lines as 219750397Sobrien the beginning of a source statement, because that information 219850397Sobrien is not made available by the GCC front-end. */ 219950397Sobrien#define DWARF_LINE_DEFAULT_IS_STMT_START 1 220050397Sobrien 220150397Sobrien/* This location is used by calc_die_sizes() to keep track 220250397Sobrien the offset of each DIE within the .debug_info section. */ 220350397Sobrienstatic unsigned long next_die_offset; 220450397Sobrien 220550397Sobrien/* Record the root of the DIE's built for the current compilation unit. */ 220650397Sobrienstatic dw_die_ref comp_unit_die; 220750397Sobrien 220850397Sobrien/* A list of DIEs with a NULL parent waiting to be relocated. */ 220950397Sobrienstatic limbo_die_node *limbo_die_list = 0; 221050397Sobrien 221150397Sobrien/* Pointer to an array of filenames referenced by this compilation unit. */ 221250397Sobrienstatic char **file_table; 221350397Sobrien 221450397Sobrien/* Total number of entries in the table (i.e. array) pointed to by 221550397Sobrien `file_table'. This is the *total* and includes both used and unused 221650397Sobrien slots. */ 221750397Sobrienstatic unsigned file_table_allocated; 221850397Sobrien 221950397Sobrien/* Number of entries in the file_table which are actually in use. */ 222050397Sobrienstatic unsigned file_table_in_use; 222150397Sobrien 222250397Sobrien/* Size (in elements) of increments by which we may expand the filename 222350397Sobrien table. */ 222450397Sobrien#define FILE_TABLE_INCREMENT 64 222550397Sobrien 222650397Sobrien/* Local pointer to the name of the main input file. Initialized in 222750397Sobrien dwarf2out_init. */ 222850397Sobrienstatic char *primary_filename; 222950397Sobrien 223050397Sobrien/* For Dwarf output, we must assign lexical-blocks id numbers in the order in 223150397Sobrien which their beginnings are encountered. We output Dwarf debugging info 223250397Sobrien that refers to the beginnings and ends of the ranges of code for each 223350397Sobrien lexical block. The labels themselves are generated in final.c, which 223450397Sobrien assigns numbers to the blocks in the same way. */ 223550397Sobrienstatic unsigned next_block_number = 2; 223650397Sobrien 223750397Sobrien/* A pointer to the base of a table of references to DIE's that describe 223850397Sobrien declarations. The table is indexed by DECL_UID() which is a unique 223950397Sobrien number identifying each decl. */ 224050397Sobrienstatic dw_die_ref *decl_die_table; 224150397Sobrien 224250397Sobrien/* Number of elements currently allocated for the decl_die_table. */ 224350397Sobrienstatic unsigned decl_die_table_allocated; 224450397Sobrien 224550397Sobrien/* Number of elements in decl_die_table currently in use. */ 224650397Sobrienstatic unsigned decl_die_table_in_use; 224750397Sobrien 224850397Sobrien/* Size (in elements) of increments by which we may expand the 224950397Sobrien decl_die_table. */ 225050397Sobrien#define DECL_DIE_TABLE_INCREMENT 256 225150397Sobrien 225250397Sobrien/* Structure used for the decl_scope table. scope is the current declaration 225350397Sobrien scope, and previous is the entry that is the parent of this scope. This 225450397Sobrien is usually but not always the immediately preceeding entry. */ 225550397Sobrien 225650397Sobrientypedef struct decl_scope_struct 225750397Sobrien{ 225850397Sobrien tree scope; 225950397Sobrien int previous; 226050397Sobrien} 226150397Sobriendecl_scope_node; 226250397Sobrien 226350397Sobrien/* A pointer to the base of a table of references to declaration 226450397Sobrien scopes. This table is a display which tracks the nesting 226550397Sobrien of declaration scopes at the current scope and containing 226650397Sobrien scopes. This table is used to find the proper place to 226750397Sobrien define type declaration DIE's. */ 226850397Sobrienstatic decl_scope_node *decl_scope_table; 226950397Sobrien 227050397Sobrien/* Number of elements currently allocated for the decl_scope_table. */ 227150397Sobrienstatic int decl_scope_table_allocated; 227250397Sobrien 227350397Sobrien/* Current level of nesting of declaration scopes. */ 227450397Sobrienstatic int decl_scope_depth; 227550397Sobrien 227650397Sobrien/* Size (in elements) of increments by which we may expand the 227750397Sobrien decl_scope_table. */ 227850397Sobrien#define DECL_SCOPE_TABLE_INCREMENT 64 227950397Sobrien 228050397Sobrien/* A pointer to the base of a list of references to DIE's that 228150397Sobrien are uniquely identified by their tag, presence/absence of 228250397Sobrien children DIE's, and list of attribute/value pairs. */ 228350397Sobrienstatic dw_die_ref *abbrev_die_table; 228450397Sobrien 228550397Sobrien/* Number of elements currently allocated for abbrev_die_table. */ 228650397Sobrienstatic unsigned abbrev_die_table_allocated; 228750397Sobrien 228850397Sobrien/* Number of elements in type_die_table currently in use. */ 228950397Sobrienstatic unsigned abbrev_die_table_in_use; 229050397Sobrien 229150397Sobrien/* Size (in elements) of increments by which we may expand the 229250397Sobrien abbrev_die_table. */ 229350397Sobrien#define ABBREV_DIE_TABLE_INCREMENT 256 229450397Sobrien 229550397Sobrien/* A pointer to the base of a table that contains line information 229650397Sobrien for each source code line in .text in the compilation unit. */ 229750397Sobrienstatic dw_line_info_ref line_info_table; 229850397Sobrien 229950397Sobrien/* Number of elements currently allocated for line_info_table. */ 230050397Sobrienstatic unsigned line_info_table_allocated; 230150397Sobrien 230250397Sobrien/* Number of elements in separate_line_info_table currently in use. */ 230350397Sobrienstatic unsigned separate_line_info_table_in_use; 230450397Sobrien 230550397Sobrien/* A pointer to the base of a table that contains line information 230650397Sobrien for each source code line outside of .text in the compilation unit. */ 230750397Sobrienstatic dw_separate_line_info_ref separate_line_info_table; 230850397Sobrien 230950397Sobrien/* Number of elements currently allocated for separate_line_info_table. */ 231050397Sobrienstatic unsigned separate_line_info_table_allocated; 231150397Sobrien 231250397Sobrien/* Number of elements in line_info_table currently in use. */ 231350397Sobrienstatic unsigned line_info_table_in_use; 231450397Sobrien 231550397Sobrien/* Size (in elements) of increments by which we may expand the 231650397Sobrien line_info_table. */ 231750397Sobrien#define LINE_INFO_TABLE_INCREMENT 1024 231850397Sobrien 231950397Sobrien/* A pointer to the base of a table that contains a list of publicly 232050397Sobrien accessible names. */ 232150397Sobrienstatic pubname_ref pubname_table; 232250397Sobrien 232350397Sobrien/* Number of elements currently allocated for pubname_table. */ 232450397Sobrienstatic unsigned pubname_table_allocated; 232550397Sobrien 232650397Sobrien/* Number of elements in pubname_table currently in use. */ 232750397Sobrienstatic unsigned pubname_table_in_use; 232850397Sobrien 232950397Sobrien/* Size (in elements) of increments by which we may expand the 233050397Sobrien pubname_table. */ 233150397Sobrien#define PUBNAME_TABLE_INCREMENT 64 233250397Sobrien 233350397Sobrien/* A pointer to the base of a table that contains a list of publicly 233450397Sobrien accessible names. */ 233550397Sobrienstatic arange_ref arange_table; 233650397Sobrien 233750397Sobrien/* Number of elements currently allocated for arange_table. */ 233850397Sobrienstatic unsigned arange_table_allocated; 233950397Sobrien 234050397Sobrien/* Number of elements in arange_table currently in use. */ 234150397Sobrienstatic unsigned arange_table_in_use; 234250397Sobrien 234350397Sobrien/* Size (in elements) of increments by which we may expand the 234450397Sobrien arange_table. */ 234550397Sobrien#define ARANGE_TABLE_INCREMENT 64 234650397Sobrien 234750397Sobrien/* A pointer to the base of a list of pending types which we haven't 234850397Sobrien generated DIEs for yet, but which we will have to come back to 234950397Sobrien later on. */ 235050397Sobrien 235150397Sobrienstatic tree *pending_types_list; 235250397Sobrien 235350397Sobrien/* Number of elements currently allocated for the pending_types_list. */ 235450397Sobrienstatic unsigned pending_types_allocated; 235550397Sobrien 235650397Sobrien/* Number of elements of pending_types_list currently in use. */ 235750397Sobrienstatic unsigned pending_types; 235850397Sobrien 235950397Sobrien/* Size (in elements) of increments by which we may expand the pending 236050397Sobrien types list. Actually, a single hunk of space of this size should 236150397Sobrien be enough for most typical programs. */ 236250397Sobrien#define PENDING_TYPES_INCREMENT 64 236350397Sobrien 236450397Sobrien/* Record whether the function being analyzed contains inlined functions. */ 236550397Sobrienstatic int current_function_has_inlines; 236650397Sobrien#if 0 && defined (MIPS_DEBUGGING_INFO) 236750397Sobrienstatic int comp_unit_has_inlines; 236850397Sobrien#endif 236950397Sobrien 237050397Sobrien/* A pointer to the ..._DECL node which we have most recently been working 237150397Sobrien on. We keep this around just in case something about it looks screwy and 237250397Sobrien we want to tell the user what the source coordinates for the actual 237350397Sobrien declaration are. */ 237450397Sobrienstatic tree dwarf_last_decl; 237550397Sobrien 237650397Sobrien/* Forward declarations for functions defined in this file. */ 237750397Sobrien 237850397Sobrienstatic void addr_const_to_string PROTO((dyn_string_t, rtx)); 237950397Sobrienstatic char *addr_to_string PROTO((rtx)); 238050397Sobrienstatic int is_pseudo_reg PROTO((rtx)); 238150397Sobrienstatic tree type_main_variant PROTO((tree)); 238250397Sobrienstatic int is_tagged_type PROTO((tree)); 238350397Sobrienstatic char *dwarf_tag_name PROTO((unsigned)); 238450397Sobrienstatic char *dwarf_attr_name PROTO((unsigned)); 238550397Sobrienstatic char *dwarf_form_name PROTO((unsigned)); 238650397Sobrienstatic char *dwarf_stack_op_name PROTO((unsigned)); 238750397Sobrien#if 0 238850397Sobrienstatic char *dwarf_type_encoding_name PROTO((unsigned)); 238950397Sobrien#endif 239050397Sobrienstatic tree decl_ultimate_origin PROTO((tree)); 239150397Sobrienstatic tree block_ultimate_origin PROTO((tree)); 239250397Sobrienstatic tree decl_class_context PROTO((tree)); 239350397Sobrienstatic void add_dwarf_attr PROTO((dw_die_ref, dw_attr_ref)); 239450397Sobrienstatic void add_AT_flag PROTO((dw_die_ref, 239550397Sobrien enum dwarf_attribute, 239650397Sobrien unsigned)); 239750397Sobrienstatic void add_AT_int PROTO((dw_die_ref, 239850397Sobrien enum dwarf_attribute, long)); 239950397Sobrienstatic void add_AT_unsigned PROTO((dw_die_ref, 240050397Sobrien enum dwarf_attribute, 240150397Sobrien unsigned long)); 240250397Sobrienstatic void add_AT_long_long PROTO((dw_die_ref, 240350397Sobrien enum dwarf_attribute, 240450397Sobrien unsigned long, unsigned long)); 240550397Sobrienstatic void add_AT_float PROTO((dw_die_ref, 240650397Sobrien enum dwarf_attribute, 240750397Sobrien unsigned, long *)); 240850397Sobrienstatic void add_AT_string PROTO((dw_die_ref, 240950397Sobrien enum dwarf_attribute, char *)); 241050397Sobrienstatic void add_AT_die_ref PROTO((dw_die_ref, 241150397Sobrien enum dwarf_attribute, 241250397Sobrien dw_die_ref)); 241350397Sobrienstatic void add_AT_fde_ref PROTO((dw_die_ref, 241450397Sobrien enum dwarf_attribute, 241550397Sobrien unsigned)); 241650397Sobrienstatic void add_AT_loc PROTO((dw_die_ref, 241750397Sobrien enum dwarf_attribute, 241850397Sobrien dw_loc_descr_ref)); 241950397Sobrienstatic void add_AT_addr PROTO((dw_die_ref, 242050397Sobrien enum dwarf_attribute, char *)); 242150397Sobrienstatic void add_AT_lbl_id PROTO((dw_die_ref, 242250397Sobrien enum dwarf_attribute, char *)); 242350397Sobrienstatic void add_AT_section_offset PROTO((dw_die_ref, 242450397Sobrien enum dwarf_attribute, char *)); 242550397Sobrienstatic int is_extern_subr_die PROTO((dw_die_ref)); 242650397Sobrienstatic dw_attr_ref get_AT PROTO((dw_die_ref, 242750397Sobrien enum dwarf_attribute)); 242850397Sobrienstatic char *get_AT_low_pc PROTO((dw_die_ref)); 242950397Sobrienstatic char *get_AT_hi_pc PROTO((dw_die_ref)); 243050397Sobrienstatic char *get_AT_string PROTO((dw_die_ref, 243150397Sobrien enum dwarf_attribute)); 243250397Sobrienstatic int get_AT_flag PROTO((dw_die_ref, 243350397Sobrien enum dwarf_attribute)); 243450397Sobrienstatic unsigned get_AT_unsigned PROTO((dw_die_ref, 243550397Sobrien enum dwarf_attribute)); 243650397Sobrienstatic int is_c_family PROTO((void)); 243750397Sobrienstatic int is_fortran PROTO((void)); 243850397Sobrienstatic void remove_AT PROTO((dw_die_ref, 243950397Sobrien enum dwarf_attribute)); 244050397Sobrienstatic void remove_children PROTO((dw_die_ref)); 244150397Sobrienstatic void add_child_die PROTO((dw_die_ref, dw_die_ref)); 244250397Sobrienstatic dw_die_ref new_die PROTO((enum dwarf_tag, dw_die_ref)); 244350397Sobrienstatic dw_die_ref lookup_type_die PROTO((tree)); 244450397Sobrienstatic void equate_type_number_to_die PROTO((tree, dw_die_ref)); 244550397Sobrienstatic dw_die_ref lookup_decl_die PROTO((tree)); 244650397Sobrienstatic void equate_decl_number_to_die PROTO((tree, dw_die_ref)); 244750397Sobrienstatic dw_loc_descr_ref new_loc_descr PROTO((enum dwarf_location_atom, 244850397Sobrien unsigned long, unsigned long)); 244950397Sobrienstatic void add_loc_descr PROTO((dw_loc_descr_ref *, 245050397Sobrien dw_loc_descr_ref)); 245150397Sobrienstatic void print_spaces PROTO((FILE *)); 245250397Sobrienstatic void print_die PROTO((dw_die_ref, FILE *)); 245350397Sobrienstatic void print_dwarf_line_table PROTO((FILE *)); 245450397Sobrienstatic void add_sibling_attributes PROTO((dw_die_ref)); 245550397Sobrienstatic void build_abbrev_table PROTO((dw_die_ref)); 245650397Sobrienstatic unsigned long size_of_string PROTO((char *)); 245750397Sobrienstatic unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref)); 245850397Sobrienstatic unsigned long size_of_locs PROTO((dw_loc_descr_ref)); 245950397Sobrienstatic int constant_size PROTO((long unsigned)); 246050397Sobrienstatic unsigned long size_of_die PROTO((dw_die_ref)); 246150397Sobrienstatic void calc_die_sizes PROTO((dw_die_ref)); 246250397Sobrienstatic unsigned long size_of_line_prolog PROTO((void)); 246350397Sobrienstatic unsigned long size_of_line_info PROTO((void)); 246450397Sobrienstatic unsigned long size_of_pubnames PROTO((void)); 246550397Sobrienstatic unsigned long size_of_aranges PROTO((void)); 246650397Sobrienstatic enum dwarf_form value_format PROTO((dw_val_ref)); 246750397Sobrienstatic void output_value_format PROTO((dw_val_ref)); 246850397Sobrienstatic void output_abbrev_section PROTO((void)); 246950397Sobrienstatic void output_loc_operands PROTO((dw_loc_descr_ref)); 247050397Sobrienstatic unsigned long sibling_offset PROTO((dw_die_ref)); 247150397Sobrienstatic void output_die PROTO((dw_die_ref)); 247250397Sobrienstatic void output_compilation_unit_header PROTO((void)); 247350397Sobrienstatic char *dwarf2_name PROTO((tree, int)); 247450397Sobrienstatic void add_pubname PROTO((tree, dw_die_ref)); 247550397Sobrienstatic void output_pubnames PROTO((void)); 247650397Sobrienstatic void add_arange PROTO((tree, dw_die_ref)); 247750397Sobrienstatic void output_aranges PROTO((void)); 247850397Sobrienstatic void output_line_info PROTO((void)); 247950397Sobrienstatic int is_body_block PROTO((tree)); 248050397Sobrienstatic dw_die_ref base_type_die PROTO((tree)); 248150397Sobrienstatic tree root_type PROTO((tree)); 248250397Sobrienstatic int is_base_type PROTO((tree)); 248350397Sobrienstatic dw_die_ref modified_type_die PROTO((tree, int, int, dw_die_ref)); 248450397Sobrienstatic int type_is_enum PROTO((tree)); 248550397Sobrienstatic dw_loc_descr_ref reg_loc_descriptor PROTO((rtx)); 248650397Sobrienstatic dw_loc_descr_ref based_loc_descr PROTO((unsigned, long)); 248750397Sobrienstatic int is_based_loc PROTO((rtx)); 248850397Sobrienstatic dw_loc_descr_ref mem_loc_descriptor PROTO((rtx)); 248950397Sobrienstatic dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx)); 249050397Sobrienstatic dw_loc_descr_ref loc_descriptor PROTO((rtx)); 249150397Sobrienstatic unsigned ceiling PROTO((unsigned, unsigned)); 249250397Sobrienstatic tree field_type PROTO((tree)); 249350397Sobrienstatic unsigned simple_type_align_in_bits PROTO((tree)); 249450397Sobrienstatic unsigned simple_type_size_in_bits PROTO((tree)); 249550397Sobrienstatic unsigned field_byte_offset PROTO((tree)); 249650397Sobrienstatic void add_AT_location_description PROTO((dw_die_ref, 249750397Sobrien enum dwarf_attribute, rtx)); 249850397Sobrienstatic void add_data_member_location_attribute PROTO((dw_die_ref, tree)); 249950397Sobrienstatic void add_const_value_attribute PROTO((dw_die_ref, rtx)); 250050397Sobrienstatic void add_location_or_const_value_attribute PROTO((dw_die_ref, tree)); 250150397Sobrienstatic void add_name_attribute PROTO((dw_die_ref, char *)); 250250397Sobrienstatic void add_bound_info PROTO((dw_die_ref, 250350397Sobrien enum dwarf_attribute, tree)); 250450397Sobrienstatic void add_subscript_info PROTO((dw_die_ref, tree)); 250550397Sobrienstatic void add_byte_size_attribute PROTO((dw_die_ref, tree)); 250650397Sobrienstatic void add_bit_offset_attribute PROTO((dw_die_ref, tree)); 250750397Sobrienstatic void add_bit_size_attribute PROTO((dw_die_ref, tree)); 250850397Sobrienstatic void add_prototyped_attribute PROTO((dw_die_ref, tree)); 250950397Sobrienstatic void add_abstract_origin_attribute PROTO((dw_die_ref, tree)); 251050397Sobrienstatic void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree)); 251150397Sobrienstatic void add_src_coords_attributes PROTO((dw_die_ref, tree)); 251250397Sobrienstatic void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree)); 251350397Sobrienstatic void push_decl_scope PROTO((tree)); 251450397Sobrienstatic dw_die_ref scope_die_for PROTO((tree, dw_die_ref)); 251550397Sobrienstatic void pop_decl_scope PROTO((void)); 251650397Sobrienstatic void add_type_attribute PROTO((dw_die_ref, tree, int, int, 251750397Sobrien dw_die_ref)); 251850397Sobrienstatic char *type_tag PROTO((tree)); 251950397Sobrienstatic tree member_declared_type PROTO((tree)); 252050397Sobrien#if 0 252150397Sobrienstatic char *decl_start_label PROTO((tree)); 252250397Sobrien#endif 252350397Sobrienstatic void gen_array_type_die PROTO((tree, dw_die_ref)); 252450397Sobrienstatic void gen_set_type_die PROTO((tree, dw_die_ref)); 252550397Sobrien#if 0 252650397Sobrienstatic void gen_entry_point_die PROTO((tree, dw_die_ref)); 252750397Sobrien#endif 252850397Sobrienstatic void pend_type PROTO((tree)); 252950397Sobrienstatic void output_pending_types_for_scope PROTO((dw_die_ref)); 253050397Sobrienstatic void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref)); 253150397Sobrienstatic void gen_inlined_structure_type_die PROTO((tree, dw_die_ref)); 253250397Sobrienstatic void gen_inlined_union_type_die PROTO((tree, dw_die_ref)); 253350397Sobrienstatic void gen_enumeration_type_die PROTO((tree, dw_die_ref)); 253450397Sobrienstatic dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref)); 253550397Sobrienstatic void gen_unspecified_parameters_die PROTO((tree, dw_die_ref)); 253650397Sobrienstatic void gen_formal_types_die PROTO((tree, dw_die_ref)); 253750397Sobrienstatic void gen_subprogram_die PROTO((tree, dw_die_ref)); 253850397Sobrienstatic void gen_variable_die PROTO((tree, dw_die_ref)); 253950397Sobrienstatic void gen_label_die PROTO((tree, dw_die_ref)); 254050397Sobrienstatic void gen_lexical_block_die PROTO((tree, dw_die_ref, int)); 254150397Sobrienstatic void gen_inlined_subroutine_die PROTO((tree, dw_die_ref, int)); 254250397Sobrienstatic void gen_field_die PROTO((tree, dw_die_ref)); 254350397Sobrienstatic void gen_ptr_to_mbr_type_die PROTO((tree, dw_die_ref)); 254450397Sobrienstatic void gen_compile_unit_die PROTO((char *)); 254550397Sobrienstatic void gen_string_type_die PROTO((tree, dw_die_ref)); 254650397Sobrienstatic void gen_inheritance_die PROTO((tree, dw_die_ref)); 254750397Sobrienstatic void gen_member_die PROTO((tree, dw_die_ref)); 254850397Sobrienstatic void gen_struct_or_union_type_die PROTO((tree, dw_die_ref)); 254950397Sobrienstatic void gen_subroutine_type_die PROTO((tree, dw_die_ref)); 255050397Sobrienstatic void gen_typedef_die PROTO((tree, dw_die_ref)); 255150397Sobrienstatic void gen_type_die PROTO((tree, dw_die_ref)); 255250397Sobrienstatic void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref)); 255350397Sobrienstatic void gen_block_die PROTO((tree, dw_die_ref, int)); 255450397Sobrienstatic void decls_for_scope PROTO((tree, dw_die_ref, int)); 255550397Sobrienstatic int is_redundant_typedef PROTO((tree)); 255650397Sobrienstatic void gen_decl_die PROTO((tree, dw_die_ref)); 255750397Sobrienstatic unsigned lookup_filename PROTO((char *)); 255850397Sobrien 255950397Sobrien/* Section names used to hold DWARF debugging information. */ 256050397Sobrien#ifndef DEBUG_INFO_SECTION 256150397Sobrien#define DEBUG_INFO_SECTION ".debug_info" 256250397Sobrien#endif 256350397Sobrien#ifndef ABBREV_SECTION 256450397Sobrien#define ABBREV_SECTION ".debug_abbrev" 256550397Sobrien#endif 256650397Sobrien#ifndef ARANGES_SECTION 256750397Sobrien#define ARANGES_SECTION ".debug_aranges" 256850397Sobrien#endif 256950397Sobrien#ifndef DW_MACINFO_SECTION 257050397Sobrien#define DW_MACINFO_SECTION ".debug_macinfo" 257150397Sobrien#endif 257250397Sobrien#ifndef DEBUG_LINE_SECTION 257350397Sobrien#define DEBUG_LINE_SECTION ".debug_line" 257450397Sobrien#endif 257550397Sobrien#ifndef LOC_SECTION 257650397Sobrien#define LOC_SECTION ".debug_loc" 257750397Sobrien#endif 257850397Sobrien#ifndef PUBNAMES_SECTION 257950397Sobrien#define PUBNAMES_SECTION ".debug_pubnames" 258050397Sobrien#endif 258150397Sobrien#ifndef STR_SECTION 258250397Sobrien#define STR_SECTION ".debug_str" 258350397Sobrien#endif 258450397Sobrien 258550397Sobrien/* Standard ELF section names for compiled code and data. */ 258650397Sobrien#ifndef TEXT_SECTION 258750397Sobrien#define TEXT_SECTION ".text" 258850397Sobrien#endif 258950397Sobrien#ifndef DATA_SECTION 259050397Sobrien#define DATA_SECTION ".data" 259150397Sobrien#endif 259250397Sobrien#ifndef BSS_SECTION 259350397Sobrien#define BSS_SECTION ".bss" 259450397Sobrien#endif 259550397Sobrien 259650397Sobrien 259750397Sobrien/* Definitions of defaults for formats and names of various special 259850397Sobrien (artificial) labels which may be generated within this file (when the -g 259950397Sobrien options is used and DWARF_DEBUGGING_INFO is in effect. 260050397Sobrien If necessary, these may be overridden from within the tm.h file, but 260150397Sobrien typically, overriding these defaults is unnecessary. */ 260250397Sobrien 260350397Sobrienstatic char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; 260450397Sobrien 260550397Sobrien#ifndef TEXT_END_LABEL 260650397Sobrien#define TEXT_END_LABEL "Letext" 260750397Sobrien#endif 260850397Sobrien#ifndef DATA_END_LABEL 260950397Sobrien#define DATA_END_LABEL "Ledata" 261050397Sobrien#endif 261150397Sobrien#ifndef BSS_END_LABEL 261250397Sobrien#define BSS_END_LABEL "Lebss" 261350397Sobrien#endif 261450397Sobrien#ifndef INSN_LABEL_FMT 261550397Sobrien#define INSN_LABEL_FMT "LI%u_" 261650397Sobrien#endif 261750397Sobrien#ifndef BLOCK_BEGIN_LABEL 261850397Sobrien#define BLOCK_BEGIN_LABEL "LBB" 261950397Sobrien#endif 262050397Sobrien#ifndef BLOCK_END_LABEL 262150397Sobrien#define BLOCK_END_LABEL "LBE" 262250397Sobrien#endif 262350397Sobrien#ifndef BODY_BEGIN_LABEL 262450397Sobrien#define BODY_BEGIN_LABEL "Lbb" 262550397Sobrien#endif 262650397Sobrien#ifndef BODY_END_LABEL 262750397Sobrien#define BODY_END_LABEL "Lbe" 262850397Sobrien#endif 262950397Sobrien#ifndef LINE_CODE_LABEL 263050397Sobrien#define LINE_CODE_LABEL "LM" 263150397Sobrien#endif 263250397Sobrien#ifndef SEPARATE_LINE_CODE_LABEL 263350397Sobrien#define SEPARATE_LINE_CODE_LABEL "LSM" 263450397Sobrien#endif 263550397Sobrien 263650397Sobrien/* Convert a reference to the assembler name of a C-level name. This 263750397Sobrien macro has the same effect as ASM_OUTPUT_LABELREF, but copies to 263850397Sobrien a string rather than writing to a file. */ 263950397Sobrien#ifndef ASM_NAME_TO_STRING 264050397Sobrien#define ASM_NAME_TO_STRING(STR, NAME) \ 264150397Sobrien do { \ 264250397Sobrien if ((NAME)[0] == '*') \ 264350397Sobrien dyn_string_append (STR, NAME + 1); \ 264450397Sobrien else \ 264550397Sobrien dyn_string_append (STR, NAME); \ 264650397Sobrien } \ 264750397Sobrien while (0) 264850397Sobrien#endif 264950397Sobrien 265050397Sobrien/* Convert an integer constant expression into assembler syntax. Addition 265150397Sobrien and subtraction are the only arithmetic that may appear in these 265250397Sobrien expressions. This is an adaptation of output_addr_const in final.c. 265350397Sobrien Here, the target of the conversion is a string buffer. We can't use 265450397Sobrien output_addr_const directly, because it writes to a file. */ 265550397Sobrien 265650397Sobrienstatic void 265750397Sobrienaddr_const_to_string (str, x) 265850397Sobrien dyn_string_t str; 265950397Sobrien rtx x; 266050397Sobrien{ 266150397Sobrien char buf1[256]; 266250397Sobrien 266350397Sobrienrestart: 266450397Sobrien switch (GET_CODE (x)) 266550397Sobrien { 266650397Sobrien case PC: 266750397Sobrien if (flag_pic) 266850397Sobrien dyn_string_append (str, ","); 266950397Sobrien else 267050397Sobrien abort (); 267150397Sobrien break; 267250397Sobrien 267350397Sobrien case SYMBOL_REF: 267450397Sobrien ASM_NAME_TO_STRING (str, XSTR (x, 0)); 267550397Sobrien break; 267650397Sobrien 267750397Sobrien case LABEL_REF: 267850397Sobrien ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); 267950397Sobrien ASM_NAME_TO_STRING (str, buf1); 268050397Sobrien break; 268150397Sobrien 268250397Sobrien case CODE_LABEL: 268350397Sobrien ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x)); 268450397Sobrien ASM_NAME_TO_STRING (str, buf1); 268550397Sobrien break; 268650397Sobrien 268750397Sobrien case CONST_INT: 268850397Sobrien sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 268950397Sobrien dyn_string_append (str, buf1); 269050397Sobrien break; 269150397Sobrien 269250397Sobrien case CONST: 269350397Sobrien /* This used to output parentheses around the expression, but that does 269450397Sobrien not work on the 386 (either ATT or BSD assembler). */ 269550397Sobrien addr_const_to_string (str, XEXP (x, 0)); 269650397Sobrien break; 269750397Sobrien 269850397Sobrien case CONST_DOUBLE: 269950397Sobrien if (GET_MODE (x) == VOIDmode) 270050397Sobrien { 270150397Sobrien /* We can use %d if the number is one word and positive. */ 270250397Sobrien if (CONST_DOUBLE_HIGH (x)) 270350397Sobrien sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX, 270450397Sobrien CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 270550397Sobrien else if (CONST_DOUBLE_LOW (x) < 0) 270650397Sobrien sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); 270750397Sobrien else 270850397Sobrien sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, 270950397Sobrien CONST_DOUBLE_LOW (x)); 271050397Sobrien dyn_string_append (str, buf1); 271150397Sobrien } 271250397Sobrien else 271350397Sobrien /* We can't handle floating point constants; PRINT_OPERAND must 271450397Sobrien handle them. */ 271550397Sobrien output_operand_lossage ("floating constant misused"); 271650397Sobrien break; 271750397Sobrien 271850397Sobrien case PLUS: 271950397Sobrien /* Some assemblers need integer constants to appear last (eg masm). */ 272050397Sobrien if (GET_CODE (XEXP (x, 0)) == CONST_INT) 272150397Sobrien { 272250397Sobrien addr_const_to_string (str, XEXP (x, 1)); 272350397Sobrien if (INTVAL (XEXP (x, 0)) >= 0) 272450397Sobrien dyn_string_append (str, "+"); 272550397Sobrien 272650397Sobrien addr_const_to_string (str, XEXP (x, 0)); 272750397Sobrien } 272850397Sobrien else 272950397Sobrien { 273050397Sobrien addr_const_to_string (str, XEXP (x, 0)); 273150397Sobrien if (INTVAL (XEXP (x, 1)) >= 0) 273250397Sobrien dyn_string_append (str, "+"); 273350397Sobrien 273450397Sobrien addr_const_to_string (str, XEXP (x, 1)); 273550397Sobrien } 273650397Sobrien break; 273750397Sobrien 273850397Sobrien case MINUS: 273950397Sobrien /* Avoid outputting things like x-x or x+5-x, since some assemblers 274050397Sobrien can't handle that. */ 274150397Sobrien x = simplify_subtraction (x); 274250397Sobrien if (GET_CODE (x) != MINUS) 274350397Sobrien goto restart; 274450397Sobrien 274550397Sobrien addr_const_to_string (str, XEXP (x, 0)); 274650397Sobrien dyn_string_append (str, "-"); 274750397Sobrien if (GET_CODE (XEXP (x, 1)) == CONST_INT 274850397Sobrien && INTVAL (XEXP (x, 1)) < 0) 274950397Sobrien { 275050397Sobrien dyn_string_append (str, ASM_OPEN_PAREN); 275150397Sobrien addr_const_to_string (str, XEXP (x, 1)); 275250397Sobrien dyn_string_append (str, ASM_CLOSE_PAREN); 275350397Sobrien } 275450397Sobrien else 275550397Sobrien addr_const_to_string (str, XEXP (x, 1)); 275650397Sobrien break; 275750397Sobrien 275850397Sobrien case ZERO_EXTEND: 275950397Sobrien case SIGN_EXTEND: 276050397Sobrien addr_const_to_string (str, XEXP (x, 0)); 276150397Sobrien break; 276250397Sobrien 276350397Sobrien default: 276450397Sobrien output_operand_lossage ("invalid expression as operand"); 276550397Sobrien } 276650397Sobrien} 276750397Sobrien 276850397Sobrien/* Convert an address constant to a string, and return a pointer to 276950397Sobrien a copy of the result, located on the heap. */ 277050397Sobrien 277150397Sobrienstatic char * 277250397Sobrienaddr_to_string (x) 277350397Sobrien rtx x; 277450397Sobrien{ 277550397Sobrien dyn_string_t ds = dyn_string_new (256); 277650397Sobrien char *s; 277750397Sobrien 277850397Sobrien addr_const_to_string (ds, x); 277950397Sobrien 278050397Sobrien /* Return the dynamically allocated string, but free the 278150397Sobrien dyn_string_t itself. */ 278250397Sobrien s = ds->s; 278350397Sobrien free (ds); 278450397Sobrien return s; 278550397Sobrien} 278650397Sobrien 278750397Sobrien/* Test if rtl node points to a pseudo register. */ 278850397Sobrien 278950397Sobrienstatic inline int 279050397Sobrienis_pseudo_reg (rtl) 279150397Sobrien register rtx rtl; 279250397Sobrien{ 279350397Sobrien return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) 279450397Sobrien || ((GET_CODE (rtl) == SUBREG) 279550397Sobrien && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER))); 279650397Sobrien} 279750397Sobrien 279850397Sobrien/* Return a reference to a type, with its const and volatile qualifiers 279950397Sobrien removed. */ 280050397Sobrien 280150397Sobrienstatic inline tree 280250397Sobrientype_main_variant (type) 280350397Sobrien register tree type; 280450397Sobrien{ 280550397Sobrien type = TYPE_MAIN_VARIANT (type); 280650397Sobrien 280750397Sobrien /* There really should be only one main variant among any group of variants 280850397Sobrien of a given type (and all of the MAIN_VARIANT values for all members of 280950397Sobrien the group should point to that one type) but sometimes the C front-end 281050397Sobrien messes this up for array types, so we work around that bug here. */ 281150397Sobrien 281250397Sobrien if (TREE_CODE (type) == ARRAY_TYPE) 281350397Sobrien while (type != TYPE_MAIN_VARIANT (type)) 281450397Sobrien type = TYPE_MAIN_VARIANT (type); 281550397Sobrien 281650397Sobrien return type; 281750397Sobrien} 281850397Sobrien 281950397Sobrien/* Return non-zero if the given type node represents a tagged type. */ 282050397Sobrien 282150397Sobrienstatic inline int 282250397Sobrienis_tagged_type (type) 282350397Sobrien register tree type; 282450397Sobrien{ 282550397Sobrien register enum tree_code code = TREE_CODE (type); 282650397Sobrien 282750397Sobrien return (code == RECORD_TYPE || code == UNION_TYPE 282850397Sobrien || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE); 282950397Sobrien} 283050397Sobrien 283150397Sobrien/* Convert a DIE tag into its string name. */ 283250397Sobrien 283350397Sobrienstatic char * 283450397Sobriendwarf_tag_name (tag) 283550397Sobrien register unsigned tag; 283650397Sobrien{ 283750397Sobrien switch (tag) 283850397Sobrien { 283950397Sobrien case DW_TAG_padding: 284050397Sobrien return "DW_TAG_padding"; 284150397Sobrien case DW_TAG_array_type: 284250397Sobrien return "DW_TAG_array_type"; 284350397Sobrien case DW_TAG_class_type: 284450397Sobrien return "DW_TAG_class_type"; 284550397Sobrien case DW_TAG_entry_point: 284650397Sobrien return "DW_TAG_entry_point"; 284750397Sobrien case DW_TAG_enumeration_type: 284850397Sobrien return "DW_TAG_enumeration_type"; 284950397Sobrien case DW_TAG_formal_parameter: 285050397Sobrien return "DW_TAG_formal_parameter"; 285150397Sobrien case DW_TAG_imported_declaration: 285250397Sobrien return "DW_TAG_imported_declaration"; 285350397Sobrien case DW_TAG_label: 285450397Sobrien return "DW_TAG_label"; 285550397Sobrien case DW_TAG_lexical_block: 285650397Sobrien return "DW_TAG_lexical_block"; 285750397Sobrien case DW_TAG_member: 285850397Sobrien return "DW_TAG_member"; 285950397Sobrien case DW_TAG_pointer_type: 286050397Sobrien return "DW_TAG_pointer_type"; 286150397Sobrien case DW_TAG_reference_type: 286250397Sobrien return "DW_TAG_reference_type"; 286350397Sobrien case DW_TAG_compile_unit: 286450397Sobrien return "DW_TAG_compile_unit"; 286550397Sobrien case DW_TAG_string_type: 286650397Sobrien return "DW_TAG_string_type"; 286750397Sobrien case DW_TAG_structure_type: 286850397Sobrien return "DW_TAG_structure_type"; 286950397Sobrien case DW_TAG_subroutine_type: 287050397Sobrien return "DW_TAG_subroutine_type"; 287150397Sobrien case DW_TAG_typedef: 287250397Sobrien return "DW_TAG_typedef"; 287350397Sobrien case DW_TAG_union_type: 287450397Sobrien return "DW_TAG_union_type"; 287550397Sobrien case DW_TAG_unspecified_parameters: 287650397Sobrien return "DW_TAG_unspecified_parameters"; 287750397Sobrien case DW_TAG_variant: 287850397Sobrien return "DW_TAG_variant"; 287950397Sobrien case DW_TAG_common_block: 288050397Sobrien return "DW_TAG_common_block"; 288150397Sobrien case DW_TAG_common_inclusion: 288250397Sobrien return "DW_TAG_common_inclusion"; 288350397Sobrien case DW_TAG_inheritance: 288450397Sobrien return "DW_TAG_inheritance"; 288550397Sobrien case DW_TAG_inlined_subroutine: 288650397Sobrien return "DW_TAG_inlined_subroutine"; 288750397Sobrien case DW_TAG_module: 288850397Sobrien return "DW_TAG_module"; 288950397Sobrien case DW_TAG_ptr_to_member_type: 289050397Sobrien return "DW_TAG_ptr_to_member_type"; 289150397Sobrien case DW_TAG_set_type: 289250397Sobrien return "DW_TAG_set_type"; 289350397Sobrien case DW_TAG_subrange_type: 289450397Sobrien return "DW_TAG_subrange_type"; 289550397Sobrien case DW_TAG_with_stmt: 289650397Sobrien return "DW_TAG_with_stmt"; 289750397Sobrien case DW_TAG_access_declaration: 289850397Sobrien return "DW_TAG_access_declaration"; 289950397Sobrien case DW_TAG_base_type: 290050397Sobrien return "DW_TAG_base_type"; 290150397Sobrien case DW_TAG_catch_block: 290250397Sobrien return "DW_TAG_catch_block"; 290350397Sobrien case DW_TAG_const_type: 290450397Sobrien return "DW_TAG_const_type"; 290550397Sobrien case DW_TAG_constant: 290650397Sobrien return "DW_TAG_constant"; 290750397Sobrien case DW_TAG_enumerator: 290850397Sobrien return "DW_TAG_enumerator"; 290950397Sobrien case DW_TAG_file_type: 291050397Sobrien return "DW_TAG_file_type"; 291150397Sobrien case DW_TAG_friend: 291250397Sobrien return "DW_TAG_friend"; 291350397Sobrien case DW_TAG_namelist: 291450397Sobrien return "DW_TAG_namelist"; 291550397Sobrien case DW_TAG_namelist_item: 291650397Sobrien return "DW_TAG_namelist_item"; 291750397Sobrien case DW_TAG_packed_type: 291850397Sobrien return "DW_TAG_packed_type"; 291950397Sobrien case DW_TAG_subprogram: 292050397Sobrien return "DW_TAG_subprogram"; 292150397Sobrien case DW_TAG_template_type_param: 292250397Sobrien return "DW_TAG_template_type_param"; 292350397Sobrien case DW_TAG_template_value_param: 292450397Sobrien return "DW_TAG_template_value_param"; 292550397Sobrien case DW_TAG_thrown_type: 292650397Sobrien return "DW_TAG_thrown_type"; 292750397Sobrien case DW_TAG_try_block: 292850397Sobrien return "DW_TAG_try_block"; 292950397Sobrien case DW_TAG_variant_part: 293050397Sobrien return "DW_TAG_variant_part"; 293150397Sobrien case DW_TAG_variable: 293250397Sobrien return "DW_TAG_variable"; 293350397Sobrien case DW_TAG_volatile_type: 293450397Sobrien return "DW_TAG_volatile_type"; 293550397Sobrien case DW_TAG_MIPS_loop: 293650397Sobrien return "DW_TAG_MIPS_loop"; 293750397Sobrien case DW_TAG_format_label: 293850397Sobrien return "DW_TAG_format_label"; 293950397Sobrien case DW_TAG_function_template: 294050397Sobrien return "DW_TAG_function_template"; 294150397Sobrien case DW_TAG_class_template: 294250397Sobrien return "DW_TAG_class_template"; 294350397Sobrien default: 294450397Sobrien return "DW_TAG_<unknown>"; 294550397Sobrien } 294650397Sobrien} 294750397Sobrien 294850397Sobrien/* Convert a DWARF attribute code into its string name. */ 294950397Sobrien 295050397Sobrienstatic char * 295150397Sobriendwarf_attr_name (attr) 295250397Sobrien register unsigned attr; 295350397Sobrien{ 295450397Sobrien switch (attr) 295550397Sobrien { 295650397Sobrien case DW_AT_sibling: 295750397Sobrien return "DW_AT_sibling"; 295850397Sobrien case DW_AT_location: 295950397Sobrien return "DW_AT_location"; 296050397Sobrien case DW_AT_name: 296150397Sobrien return "DW_AT_name"; 296250397Sobrien case DW_AT_ordering: 296350397Sobrien return "DW_AT_ordering"; 296450397Sobrien case DW_AT_subscr_data: 296550397Sobrien return "DW_AT_subscr_data"; 296650397Sobrien case DW_AT_byte_size: 296750397Sobrien return "DW_AT_byte_size"; 296850397Sobrien case DW_AT_bit_offset: 296950397Sobrien return "DW_AT_bit_offset"; 297050397Sobrien case DW_AT_bit_size: 297150397Sobrien return "DW_AT_bit_size"; 297250397Sobrien case DW_AT_element_list: 297350397Sobrien return "DW_AT_element_list"; 297450397Sobrien case DW_AT_stmt_list: 297550397Sobrien return "DW_AT_stmt_list"; 297650397Sobrien case DW_AT_low_pc: 297750397Sobrien return "DW_AT_low_pc"; 297850397Sobrien case DW_AT_high_pc: 297950397Sobrien return "DW_AT_high_pc"; 298050397Sobrien case DW_AT_language: 298150397Sobrien return "DW_AT_language"; 298250397Sobrien case DW_AT_member: 298350397Sobrien return "DW_AT_member"; 298450397Sobrien case DW_AT_discr: 298550397Sobrien return "DW_AT_discr"; 298650397Sobrien case DW_AT_discr_value: 298750397Sobrien return "DW_AT_discr_value"; 298850397Sobrien case DW_AT_visibility: 298950397Sobrien return "DW_AT_visibility"; 299050397Sobrien case DW_AT_import: 299150397Sobrien return "DW_AT_import"; 299250397Sobrien case DW_AT_string_length: 299350397Sobrien return "DW_AT_string_length"; 299450397Sobrien case DW_AT_common_reference: 299550397Sobrien return "DW_AT_common_reference"; 299650397Sobrien case DW_AT_comp_dir: 299750397Sobrien return "DW_AT_comp_dir"; 299850397Sobrien case DW_AT_const_value: 299950397Sobrien return "DW_AT_const_value"; 300050397Sobrien case DW_AT_containing_type: 300150397Sobrien return "DW_AT_containing_type"; 300250397Sobrien case DW_AT_default_value: 300350397Sobrien return "DW_AT_default_value"; 300450397Sobrien case DW_AT_inline: 300550397Sobrien return "DW_AT_inline"; 300650397Sobrien case DW_AT_is_optional: 300750397Sobrien return "DW_AT_is_optional"; 300850397Sobrien case DW_AT_lower_bound: 300950397Sobrien return "DW_AT_lower_bound"; 301050397Sobrien case DW_AT_producer: 301150397Sobrien return "DW_AT_producer"; 301250397Sobrien case DW_AT_prototyped: 301350397Sobrien return "DW_AT_prototyped"; 301450397Sobrien case DW_AT_return_addr: 301550397Sobrien return "DW_AT_return_addr"; 301650397Sobrien case DW_AT_start_scope: 301750397Sobrien return "DW_AT_start_scope"; 301850397Sobrien case DW_AT_stride_size: 301950397Sobrien return "DW_AT_stride_size"; 302050397Sobrien case DW_AT_upper_bound: 302150397Sobrien return "DW_AT_upper_bound"; 302250397Sobrien case DW_AT_abstract_origin: 302350397Sobrien return "DW_AT_abstract_origin"; 302450397Sobrien case DW_AT_accessibility: 302550397Sobrien return "DW_AT_accessibility"; 302650397Sobrien case DW_AT_address_class: 302750397Sobrien return "DW_AT_address_class"; 302850397Sobrien case DW_AT_artificial: 302950397Sobrien return "DW_AT_artificial"; 303050397Sobrien case DW_AT_base_types: 303150397Sobrien return "DW_AT_base_types"; 303250397Sobrien case DW_AT_calling_convention: 303350397Sobrien return "DW_AT_calling_convention"; 303450397Sobrien case DW_AT_count: 303550397Sobrien return "DW_AT_count"; 303650397Sobrien case DW_AT_data_member_location: 303750397Sobrien return "DW_AT_data_member_location"; 303850397Sobrien case DW_AT_decl_column: 303950397Sobrien return "DW_AT_decl_column"; 304050397Sobrien case DW_AT_decl_file: 304150397Sobrien return "DW_AT_decl_file"; 304250397Sobrien case DW_AT_decl_line: 304350397Sobrien return "DW_AT_decl_line"; 304450397Sobrien case DW_AT_declaration: 304550397Sobrien return "DW_AT_declaration"; 304650397Sobrien case DW_AT_discr_list: 304750397Sobrien return "DW_AT_discr_list"; 304850397Sobrien case DW_AT_encoding: 304950397Sobrien return "DW_AT_encoding"; 305050397Sobrien case DW_AT_external: 305150397Sobrien return "DW_AT_external"; 305250397Sobrien case DW_AT_frame_base: 305350397Sobrien return "DW_AT_frame_base"; 305450397Sobrien case DW_AT_friend: 305550397Sobrien return "DW_AT_friend"; 305650397Sobrien case DW_AT_identifier_case: 305750397Sobrien return "DW_AT_identifier_case"; 305850397Sobrien case DW_AT_macro_info: 305950397Sobrien return "DW_AT_macro_info"; 306050397Sobrien case DW_AT_namelist_items: 306150397Sobrien return "DW_AT_namelist_items"; 306250397Sobrien case DW_AT_priority: 306350397Sobrien return "DW_AT_priority"; 306450397Sobrien case DW_AT_segment: 306550397Sobrien return "DW_AT_segment"; 306650397Sobrien case DW_AT_specification: 306750397Sobrien return "DW_AT_specification"; 306850397Sobrien case DW_AT_static_link: 306950397Sobrien return "DW_AT_static_link"; 307050397Sobrien case DW_AT_type: 307150397Sobrien return "DW_AT_type"; 307250397Sobrien case DW_AT_use_location: 307350397Sobrien return "DW_AT_use_location"; 307450397Sobrien case DW_AT_variable_parameter: 307550397Sobrien return "DW_AT_variable_parameter"; 307650397Sobrien case DW_AT_virtuality: 307750397Sobrien return "DW_AT_virtuality"; 307850397Sobrien case DW_AT_vtable_elem_location: 307950397Sobrien return "DW_AT_vtable_elem_location"; 308050397Sobrien 308150397Sobrien case DW_AT_MIPS_fde: 308250397Sobrien return "DW_AT_MIPS_fde"; 308350397Sobrien case DW_AT_MIPS_loop_begin: 308450397Sobrien return "DW_AT_MIPS_loop_begin"; 308550397Sobrien case DW_AT_MIPS_tail_loop_begin: 308650397Sobrien return "DW_AT_MIPS_tail_loop_begin"; 308750397Sobrien case DW_AT_MIPS_epilog_begin: 308850397Sobrien return "DW_AT_MIPS_epilog_begin"; 308950397Sobrien case DW_AT_MIPS_loop_unroll_factor: 309050397Sobrien return "DW_AT_MIPS_loop_unroll_factor"; 309150397Sobrien case DW_AT_MIPS_software_pipeline_depth: 309250397Sobrien return "DW_AT_MIPS_software_pipeline_depth"; 309350397Sobrien case DW_AT_MIPS_linkage_name: 309450397Sobrien return "DW_AT_MIPS_linkage_name"; 309550397Sobrien case DW_AT_MIPS_stride: 309650397Sobrien return "DW_AT_MIPS_stride"; 309750397Sobrien case DW_AT_MIPS_abstract_name: 309850397Sobrien return "DW_AT_MIPS_abstract_name"; 309950397Sobrien case DW_AT_MIPS_clone_origin: 310050397Sobrien return "DW_AT_MIPS_clone_origin"; 310150397Sobrien case DW_AT_MIPS_has_inlines: 310250397Sobrien return "DW_AT_MIPS_has_inlines"; 310350397Sobrien 310450397Sobrien case DW_AT_sf_names: 310550397Sobrien return "DW_AT_sf_names"; 310650397Sobrien case DW_AT_src_info: 310750397Sobrien return "DW_AT_src_info"; 310850397Sobrien case DW_AT_mac_info: 310950397Sobrien return "DW_AT_mac_info"; 311050397Sobrien case DW_AT_src_coords: 311150397Sobrien return "DW_AT_src_coords"; 311250397Sobrien case DW_AT_body_begin: 311350397Sobrien return "DW_AT_body_begin"; 311450397Sobrien case DW_AT_body_end: 311550397Sobrien return "DW_AT_body_end"; 311650397Sobrien default: 311750397Sobrien return "DW_AT_<unknown>"; 311850397Sobrien } 311950397Sobrien} 312050397Sobrien 312150397Sobrien/* Convert a DWARF value form code into its string name. */ 312250397Sobrien 312350397Sobrienstatic char * 312450397Sobriendwarf_form_name (form) 312550397Sobrien register unsigned form; 312650397Sobrien{ 312750397Sobrien switch (form) 312850397Sobrien { 312950397Sobrien case DW_FORM_addr: 313050397Sobrien return "DW_FORM_addr"; 313150397Sobrien case DW_FORM_block2: 313250397Sobrien return "DW_FORM_block2"; 313350397Sobrien case DW_FORM_block4: 313450397Sobrien return "DW_FORM_block4"; 313550397Sobrien case DW_FORM_data2: 313650397Sobrien return "DW_FORM_data2"; 313750397Sobrien case DW_FORM_data4: 313850397Sobrien return "DW_FORM_data4"; 313950397Sobrien case DW_FORM_data8: 314050397Sobrien return "DW_FORM_data8"; 314150397Sobrien case DW_FORM_string: 314250397Sobrien return "DW_FORM_string"; 314350397Sobrien case DW_FORM_block: 314450397Sobrien return "DW_FORM_block"; 314550397Sobrien case DW_FORM_block1: 314650397Sobrien return "DW_FORM_block1"; 314750397Sobrien case DW_FORM_data1: 314850397Sobrien return "DW_FORM_data1"; 314950397Sobrien case DW_FORM_flag: 315050397Sobrien return "DW_FORM_flag"; 315150397Sobrien case DW_FORM_sdata: 315250397Sobrien return "DW_FORM_sdata"; 315350397Sobrien case DW_FORM_strp: 315450397Sobrien return "DW_FORM_strp"; 315550397Sobrien case DW_FORM_udata: 315650397Sobrien return "DW_FORM_udata"; 315750397Sobrien case DW_FORM_ref_addr: 315850397Sobrien return "DW_FORM_ref_addr"; 315950397Sobrien case DW_FORM_ref1: 316050397Sobrien return "DW_FORM_ref1"; 316150397Sobrien case DW_FORM_ref2: 316250397Sobrien return "DW_FORM_ref2"; 316350397Sobrien case DW_FORM_ref4: 316450397Sobrien return "DW_FORM_ref4"; 316550397Sobrien case DW_FORM_ref8: 316650397Sobrien return "DW_FORM_ref8"; 316750397Sobrien case DW_FORM_ref_udata: 316850397Sobrien return "DW_FORM_ref_udata"; 316950397Sobrien case DW_FORM_indirect: 317050397Sobrien return "DW_FORM_indirect"; 317150397Sobrien default: 317250397Sobrien return "DW_FORM_<unknown>"; 317350397Sobrien } 317450397Sobrien} 317550397Sobrien 317650397Sobrien/* Convert a DWARF stack opcode into its string name. */ 317750397Sobrien 317850397Sobrienstatic char * 317950397Sobriendwarf_stack_op_name (op) 318050397Sobrien register unsigned op; 318150397Sobrien{ 318250397Sobrien switch (op) 318350397Sobrien { 318450397Sobrien case DW_OP_addr: 318550397Sobrien return "DW_OP_addr"; 318650397Sobrien case DW_OP_deref: 318750397Sobrien return "DW_OP_deref"; 318850397Sobrien case DW_OP_const1u: 318950397Sobrien return "DW_OP_const1u"; 319050397Sobrien case DW_OP_const1s: 319150397Sobrien return "DW_OP_const1s"; 319250397Sobrien case DW_OP_const2u: 319350397Sobrien return "DW_OP_const2u"; 319450397Sobrien case DW_OP_const2s: 319550397Sobrien return "DW_OP_const2s"; 319650397Sobrien case DW_OP_const4u: 319750397Sobrien return "DW_OP_const4u"; 319850397Sobrien case DW_OP_const4s: 319950397Sobrien return "DW_OP_const4s"; 320050397Sobrien case DW_OP_const8u: 320150397Sobrien return "DW_OP_const8u"; 320250397Sobrien case DW_OP_const8s: 320350397Sobrien return "DW_OP_const8s"; 320450397Sobrien case DW_OP_constu: 320550397Sobrien return "DW_OP_constu"; 320650397Sobrien case DW_OP_consts: 320750397Sobrien return "DW_OP_consts"; 320850397Sobrien case DW_OP_dup: 320950397Sobrien return "DW_OP_dup"; 321050397Sobrien case DW_OP_drop: 321150397Sobrien return "DW_OP_drop"; 321250397Sobrien case DW_OP_over: 321350397Sobrien return "DW_OP_over"; 321450397Sobrien case DW_OP_pick: 321550397Sobrien return "DW_OP_pick"; 321650397Sobrien case DW_OP_swap: 321750397Sobrien return "DW_OP_swap"; 321850397Sobrien case DW_OP_rot: 321950397Sobrien return "DW_OP_rot"; 322050397Sobrien case DW_OP_xderef: 322150397Sobrien return "DW_OP_xderef"; 322250397Sobrien case DW_OP_abs: 322350397Sobrien return "DW_OP_abs"; 322450397Sobrien case DW_OP_and: 322550397Sobrien return "DW_OP_and"; 322650397Sobrien case DW_OP_div: 322750397Sobrien return "DW_OP_div"; 322850397Sobrien case DW_OP_minus: 322950397Sobrien return "DW_OP_minus"; 323050397Sobrien case DW_OP_mod: 323150397Sobrien return "DW_OP_mod"; 323250397Sobrien case DW_OP_mul: 323350397Sobrien return "DW_OP_mul"; 323450397Sobrien case DW_OP_neg: 323550397Sobrien return "DW_OP_neg"; 323650397Sobrien case DW_OP_not: 323750397Sobrien return "DW_OP_not"; 323850397Sobrien case DW_OP_or: 323950397Sobrien return "DW_OP_or"; 324050397Sobrien case DW_OP_plus: 324150397Sobrien return "DW_OP_plus"; 324250397Sobrien case DW_OP_plus_uconst: 324350397Sobrien return "DW_OP_plus_uconst"; 324450397Sobrien case DW_OP_shl: 324550397Sobrien return "DW_OP_shl"; 324650397Sobrien case DW_OP_shr: 324750397Sobrien return "DW_OP_shr"; 324850397Sobrien case DW_OP_shra: 324950397Sobrien return "DW_OP_shra"; 325050397Sobrien case DW_OP_xor: 325150397Sobrien return "DW_OP_xor"; 325250397Sobrien case DW_OP_bra: 325350397Sobrien return "DW_OP_bra"; 325450397Sobrien case DW_OP_eq: 325550397Sobrien return "DW_OP_eq"; 325650397Sobrien case DW_OP_ge: 325750397Sobrien return "DW_OP_ge"; 325850397Sobrien case DW_OP_gt: 325950397Sobrien return "DW_OP_gt"; 326050397Sobrien case DW_OP_le: 326150397Sobrien return "DW_OP_le"; 326250397Sobrien case DW_OP_lt: 326350397Sobrien return "DW_OP_lt"; 326450397Sobrien case DW_OP_ne: 326550397Sobrien return "DW_OP_ne"; 326650397Sobrien case DW_OP_skip: 326750397Sobrien return "DW_OP_skip"; 326850397Sobrien case DW_OP_lit0: 326950397Sobrien return "DW_OP_lit0"; 327050397Sobrien case DW_OP_lit1: 327150397Sobrien return "DW_OP_lit1"; 327250397Sobrien case DW_OP_lit2: 327350397Sobrien return "DW_OP_lit2"; 327450397Sobrien case DW_OP_lit3: 327550397Sobrien return "DW_OP_lit3"; 327650397Sobrien case DW_OP_lit4: 327750397Sobrien return "DW_OP_lit4"; 327850397Sobrien case DW_OP_lit5: 327950397Sobrien return "DW_OP_lit5"; 328050397Sobrien case DW_OP_lit6: 328150397Sobrien return "DW_OP_lit6"; 328250397Sobrien case DW_OP_lit7: 328350397Sobrien return "DW_OP_lit7"; 328450397Sobrien case DW_OP_lit8: 328550397Sobrien return "DW_OP_lit8"; 328650397Sobrien case DW_OP_lit9: 328750397Sobrien return "DW_OP_lit9"; 328850397Sobrien case DW_OP_lit10: 328950397Sobrien return "DW_OP_lit10"; 329050397Sobrien case DW_OP_lit11: 329150397Sobrien return "DW_OP_lit11"; 329250397Sobrien case DW_OP_lit12: 329350397Sobrien return "DW_OP_lit12"; 329450397Sobrien case DW_OP_lit13: 329550397Sobrien return "DW_OP_lit13"; 329650397Sobrien case DW_OP_lit14: 329750397Sobrien return "DW_OP_lit14"; 329850397Sobrien case DW_OP_lit15: 329950397Sobrien return "DW_OP_lit15"; 330050397Sobrien case DW_OP_lit16: 330150397Sobrien return "DW_OP_lit16"; 330250397Sobrien case DW_OP_lit17: 330350397Sobrien return "DW_OP_lit17"; 330450397Sobrien case DW_OP_lit18: 330550397Sobrien return "DW_OP_lit18"; 330650397Sobrien case DW_OP_lit19: 330750397Sobrien return "DW_OP_lit19"; 330850397Sobrien case DW_OP_lit20: 330950397Sobrien return "DW_OP_lit20"; 331050397Sobrien case DW_OP_lit21: 331150397Sobrien return "DW_OP_lit21"; 331250397Sobrien case DW_OP_lit22: 331350397Sobrien return "DW_OP_lit22"; 331450397Sobrien case DW_OP_lit23: 331550397Sobrien return "DW_OP_lit23"; 331650397Sobrien case DW_OP_lit24: 331750397Sobrien return "DW_OP_lit24"; 331850397Sobrien case DW_OP_lit25: 331950397Sobrien return "DW_OP_lit25"; 332050397Sobrien case DW_OP_lit26: 332150397Sobrien return "DW_OP_lit26"; 332250397Sobrien case DW_OP_lit27: 332350397Sobrien return "DW_OP_lit27"; 332450397Sobrien case DW_OP_lit28: 332550397Sobrien return "DW_OP_lit28"; 332650397Sobrien case DW_OP_lit29: 332750397Sobrien return "DW_OP_lit29"; 332850397Sobrien case DW_OP_lit30: 332950397Sobrien return "DW_OP_lit30"; 333050397Sobrien case DW_OP_lit31: 333150397Sobrien return "DW_OP_lit31"; 333250397Sobrien case DW_OP_reg0: 333350397Sobrien return "DW_OP_reg0"; 333450397Sobrien case DW_OP_reg1: 333550397Sobrien return "DW_OP_reg1"; 333650397Sobrien case DW_OP_reg2: 333750397Sobrien return "DW_OP_reg2"; 333850397Sobrien case DW_OP_reg3: 333950397Sobrien return "DW_OP_reg3"; 334050397Sobrien case DW_OP_reg4: 334150397Sobrien return "DW_OP_reg4"; 334250397Sobrien case DW_OP_reg5: 334350397Sobrien return "DW_OP_reg5"; 334450397Sobrien case DW_OP_reg6: 334550397Sobrien return "DW_OP_reg6"; 334650397Sobrien case DW_OP_reg7: 334750397Sobrien return "DW_OP_reg7"; 334850397Sobrien case DW_OP_reg8: 334950397Sobrien return "DW_OP_reg8"; 335050397Sobrien case DW_OP_reg9: 335150397Sobrien return "DW_OP_reg9"; 335250397Sobrien case DW_OP_reg10: 335350397Sobrien return "DW_OP_reg10"; 335450397Sobrien case DW_OP_reg11: 335550397Sobrien return "DW_OP_reg11"; 335650397Sobrien case DW_OP_reg12: 335750397Sobrien return "DW_OP_reg12"; 335850397Sobrien case DW_OP_reg13: 335950397Sobrien return "DW_OP_reg13"; 336050397Sobrien case DW_OP_reg14: 336150397Sobrien return "DW_OP_reg14"; 336250397Sobrien case DW_OP_reg15: 336350397Sobrien return "DW_OP_reg15"; 336450397Sobrien case DW_OP_reg16: 336550397Sobrien return "DW_OP_reg16"; 336650397Sobrien case DW_OP_reg17: 336750397Sobrien return "DW_OP_reg17"; 336850397Sobrien case DW_OP_reg18: 336950397Sobrien return "DW_OP_reg18"; 337050397Sobrien case DW_OP_reg19: 337150397Sobrien return "DW_OP_reg19"; 337250397Sobrien case DW_OP_reg20: 337350397Sobrien return "DW_OP_reg20"; 337450397Sobrien case DW_OP_reg21: 337550397Sobrien return "DW_OP_reg21"; 337650397Sobrien case DW_OP_reg22: 337750397Sobrien return "DW_OP_reg22"; 337850397Sobrien case DW_OP_reg23: 337950397Sobrien return "DW_OP_reg23"; 338050397Sobrien case DW_OP_reg24: 338150397Sobrien return "DW_OP_reg24"; 338250397Sobrien case DW_OP_reg25: 338350397Sobrien return "DW_OP_reg25"; 338450397Sobrien case DW_OP_reg26: 338550397Sobrien return "DW_OP_reg26"; 338650397Sobrien case DW_OP_reg27: 338750397Sobrien return "DW_OP_reg27"; 338850397Sobrien case DW_OP_reg28: 338950397Sobrien return "DW_OP_reg28"; 339050397Sobrien case DW_OP_reg29: 339150397Sobrien return "DW_OP_reg29"; 339250397Sobrien case DW_OP_reg30: 339350397Sobrien return "DW_OP_reg30"; 339450397Sobrien case DW_OP_reg31: 339550397Sobrien return "DW_OP_reg31"; 339650397Sobrien case DW_OP_breg0: 339750397Sobrien return "DW_OP_breg0"; 339850397Sobrien case DW_OP_breg1: 339950397Sobrien return "DW_OP_breg1"; 340050397Sobrien case DW_OP_breg2: 340150397Sobrien return "DW_OP_breg2"; 340250397Sobrien case DW_OP_breg3: 340350397Sobrien return "DW_OP_breg3"; 340450397Sobrien case DW_OP_breg4: 340550397Sobrien return "DW_OP_breg4"; 340650397Sobrien case DW_OP_breg5: 340750397Sobrien return "DW_OP_breg5"; 340850397Sobrien case DW_OP_breg6: 340950397Sobrien return "DW_OP_breg6"; 341050397Sobrien case DW_OP_breg7: 341150397Sobrien return "DW_OP_breg7"; 341250397Sobrien case DW_OP_breg8: 341350397Sobrien return "DW_OP_breg8"; 341450397Sobrien case DW_OP_breg9: 341550397Sobrien return "DW_OP_breg9"; 341650397Sobrien case DW_OP_breg10: 341750397Sobrien return "DW_OP_breg10"; 341850397Sobrien case DW_OP_breg11: 341950397Sobrien return "DW_OP_breg11"; 342050397Sobrien case DW_OP_breg12: 342150397Sobrien return "DW_OP_breg12"; 342250397Sobrien case DW_OP_breg13: 342350397Sobrien return "DW_OP_breg13"; 342450397Sobrien case DW_OP_breg14: 342550397Sobrien return "DW_OP_breg14"; 342650397Sobrien case DW_OP_breg15: 342750397Sobrien return "DW_OP_breg15"; 342850397Sobrien case DW_OP_breg16: 342950397Sobrien return "DW_OP_breg16"; 343050397Sobrien case DW_OP_breg17: 343150397Sobrien return "DW_OP_breg17"; 343250397Sobrien case DW_OP_breg18: 343350397Sobrien return "DW_OP_breg18"; 343450397Sobrien case DW_OP_breg19: 343550397Sobrien return "DW_OP_breg19"; 343650397Sobrien case DW_OP_breg20: 343750397Sobrien return "DW_OP_breg20"; 343850397Sobrien case DW_OP_breg21: 343950397Sobrien return "DW_OP_breg21"; 344050397Sobrien case DW_OP_breg22: 344150397Sobrien return "DW_OP_breg22"; 344250397Sobrien case DW_OP_breg23: 344350397Sobrien return "DW_OP_breg23"; 344450397Sobrien case DW_OP_breg24: 344550397Sobrien return "DW_OP_breg24"; 344650397Sobrien case DW_OP_breg25: 344750397Sobrien return "DW_OP_breg25"; 344850397Sobrien case DW_OP_breg26: 344950397Sobrien return "DW_OP_breg26"; 345050397Sobrien case DW_OP_breg27: 345150397Sobrien return "DW_OP_breg27"; 345250397Sobrien case DW_OP_breg28: 345350397Sobrien return "DW_OP_breg28"; 345450397Sobrien case DW_OP_breg29: 345550397Sobrien return "DW_OP_breg29"; 345650397Sobrien case DW_OP_breg30: 345750397Sobrien return "DW_OP_breg30"; 345850397Sobrien case DW_OP_breg31: 345950397Sobrien return "DW_OP_breg31"; 346050397Sobrien case DW_OP_regx: 346150397Sobrien return "DW_OP_regx"; 346250397Sobrien case DW_OP_fbreg: 346350397Sobrien return "DW_OP_fbreg"; 346450397Sobrien case DW_OP_bregx: 346550397Sobrien return "DW_OP_bregx"; 346650397Sobrien case DW_OP_piece: 346750397Sobrien return "DW_OP_piece"; 346850397Sobrien case DW_OP_deref_size: 346950397Sobrien return "DW_OP_deref_size"; 347050397Sobrien case DW_OP_xderef_size: 347150397Sobrien return "DW_OP_xderef_size"; 347250397Sobrien case DW_OP_nop: 347350397Sobrien return "DW_OP_nop"; 347450397Sobrien default: 347550397Sobrien return "OP_<unknown>"; 347650397Sobrien } 347750397Sobrien} 347850397Sobrien 347950397Sobrien/* Convert a DWARF type code into its string name. */ 348050397Sobrien 348150397Sobrien#if 0 348250397Sobrienstatic char * 348350397Sobriendwarf_type_encoding_name (enc) 348450397Sobrien register unsigned enc; 348550397Sobrien{ 348650397Sobrien switch (enc) 348750397Sobrien { 348850397Sobrien case DW_ATE_address: 348950397Sobrien return "DW_ATE_address"; 349050397Sobrien case DW_ATE_boolean: 349150397Sobrien return "DW_ATE_boolean"; 349250397Sobrien case DW_ATE_complex_float: 349350397Sobrien return "DW_ATE_complex_float"; 349450397Sobrien case DW_ATE_float: 349550397Sobrien return "DW_ATE_float"; 349650397Sobrien case DW_ATE_signed: 349750397Sobrien return "DW_ATE_signed"; 349850397Sobrien case DW_ATE_signed_char: 349950397Sobrien return "DW_ATE_signed_char"; 350050397Sobrien case DW_ATE_unsigned: 350150397Sobrien return "DW_ATE_unsigned"; 350250397Sobrien case DW_ATE_unsigned_char: 350350397Sobrien return "DW_ATE_unsigned_char"; 350450397Sobrien default: 350550397Sobrien return "DW_ATE_<unknown>"; 350650397Sobrien } 350750397Sobrien} 350850397Sobrien#endif 350950397Sobrien 351050397Sobrien/* Determine the "ultimate origin" of a decl. The decl may be an inlined 351150397Sobrien instance of an inlined instance of a decl which is local to an inline 351250397Sobrien function, so we have to trace all of the way back through the origin chain 351350397Sobrien to find out what sort of node actually served as the original seed for the 351450397Sobrien given block. */ 351550397Sobrien 351650397Sobrienstatic tree 351750397Sobriendecl_ultimate_origin (decl) 351850397Sobrien register tree decl; 351950397Sobrien{ 352050397Sobrien register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl); 352150397Sobrien 352250397Sobrien if (immediate_origin == NULL_TREE) 352350397Sobrien return NULL_TREE; 352450397Sobrien else 352550397Sobrien { 352650397Sobrien register tree ret_val; 352750397Sobrien register tree lookahead = immediate_origin; 352850397Sobrien 352950397Sobrien do 353050397Sobrien { 353150397Sobrien ret_val = lookahead; 353250397Sobrien lookahead = DECL_ABSTRACT_ORIGIN (ret_val); 353350397Sobrien } 353450397Sobrien while (lookahead != NULL && lookahead != ret_val); 353550397Sobrien 353650397Sobrien return ret_val; 353750397Sobrien } 353850397Sobrien} 353950397Sobrien 354050397Sobrien/* Determine the "ultimate origin" of a block. The block may be an inlined 354150397Sobrien instance of an inlined instance of a block which is local to an inline 354250397Sobrien function, so we have to trace all of the way back through the origin chain 354350397Sobrien to find out what sort of node actually served as the original seed for the 354450397Sobrien given block. */ 354550397Sobrien 354650397Sobrienstatic tree 354750397Sobrienblock_ultimate_origin (block) 354850397Sobrien register tree block; 354950397Sobrien{ 355050397Sobrien register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); 355150397Sobrien 355250397Sobrien if (immediate_origin == NULL_TREE) 355350397Sobrien return NULL_TREE; 355450397Sobrien else 355550397Sobrien { 355650397Sobrien register tree ret_val; 355750397Sobrien register tree lookahead = immediate_origin; 355850397Sobrien 355950397Sobrien do 356050397Sobrien { 356150397Sobrien ret_val = lookahead; 356250397Sobrien lookahead = (TREE_CODE (ret_val) == BLOCK) 356350397Sobrien ? BLOCK_ABSTRACT_ORIGIN (ret_val) 356450397Sobrien : NULL; 356550397Sobrien } 356650397Sobrien while (lookahead != NULL && lookahead != ret_val); 356750397Sobrien 356850397Sobrien return ret_val; 356950397Sobrien } 357050397Sobrien} 357150397Sobrien 357250397Sobrien/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT 357350397Sobrien of a virtual function may refer to a base class, so we check the 'this' 357450397Sobrien parameter. */ 357550397Sobrien 357650397Sobrienstatic tree 357750397Sobriendecl_class_context (decl) 357850397Sobrien tree decl; 357950397Sobrien{ 358050397Sobrien tree context = NULL_TREE; 358150397Sobrien 358250397Sobrien if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl)) 358350397Sobrien context = DECL_CONTEXT (decl); 358450397Sobrien else 358550397Sobrien context = TYPE_MAIN_VARIANT 358650397Sobrien (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))))); 358750397Sobrien 358850397Sobrien if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't') 358950397Sobrien context = NULL_TREE; 359050397Sobrien 359150397Sobrien return context; 359250397Sobrien} 359350397Sobrien 359450397Sobrien/* Add an attribute/value pair to a DIE */ 359550397Sobrien 359650397Sobrienstatic inline void 359750397Sobrienadd_dwarf_attr (die, attr) 359850397Sobrien register dw_die_ref die; 359950397Sobrien register dw_attr_ref attr; 360050397Sobrien{ 360150397Sobrien if (die != NULL && attr != NULL) 360250397Sobrien { 360350397Sobrien if (die->die_attr == NULL) 360450397Sobrien { 360550397Sobrien die->die_attr = attr; 360650397Sobrien die->die_attr_last = attr; 360750397Sobrien } 360850397Sobrien else 360950397Sobrien { 361050397Sobrien die->die_attr_last->dw_attr_next = attr; 361150397Sobrien die->die_attr_last = attr; 361250397Sobrien } 361350397Sobrien } 361450397Sobrien} 361550397Sobrien 361650397Sobrien/* Add a flag value attribute to a DIE. */ 361750397Sobrien 361850397Sobrienstatic inline void 361950397Sobrienadd_AT_flag (die, attr_kind, flag) 362050397Sobrien register dw_die_ref die; 362150397Sobrien register enum dwarf_attribute attr_kind; 362250397Sobrien register unsigned flag; 362350397Sobrien{ 362450397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 362550397Sobrien 362650397Sobrien attr->dw_attr_next = NULL; 362750397Sobrien attr->dw_attr = attr_kind; 362850397Sobrien attr->dw_attr_val.val_class = dw_val_class_flag; 362950397Sobrien attr->dw_attr_val.v.val_flag = flag; 363050397Sobrien add_dwarf_attr (die, attr); 363150397Sobrien} 363250397Sobrien 363350397Sobrien/* Add a signed integer attribute value to a DIE. */ 363450397Sobrien 363550397Sobrienstatic inline void 363650397Sobrienadd_AT_int (die, attr_kind, int_val) 363750397Sobrien register dw_die_ref die; 363850397Sobrien register enum dwarf_attribute attr_kind; 363950397Sobrien register long int int_val; 364050397Sobrien{ 364150397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 364250397Sobrien 364350397Sobrien attr->dw_attr_next = NULL; 364450397Sobrien attr->dw_attr = attr_kind; 364550397Sobrien attr->dw_attr_val.val_class = dw_val_class_const; 364650397Sobrien attr->dw_attr_val.v.val_int = int_val; 364750397Sobrien add_dwarf_attr (die, attr); 364850397Sobrien} 364950397Sobrien 365050397Sobrien/* Add an unsigned integer attribute value to a DIE. */ 365150397Sobrien 365250397Sobrienstatic inline void 365350397Sobrienadd_AT_unsigned (die, attr_kind, unsigned_val) 365450397Sobrien register dw_die_ref die; 365550397Sobrien register enum dwarf_attribute attr_kind; 365650397Sobrien register unsigned long unsigned_val; 365750397Sobrien{ 365850397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 365950397Sobrien 366050397Sobrien attr->dw_attr_next = NULL; 366150397Sobrien attr->dw_attr = attr_kind; 366250397Sobrien attr->dw_attr_val.val_class = dw_val_class_unsigned_const; 366350397Sobrien attr->dw_attr_val.v.val_unsigned = unsigned_val; 366450397Sobrien add_dwarf_attr (die, attr); 366550397Sobrien} 366650397Sobrien 366750397Sobrien/* Add an unsigned double integer attribute value to a DIE. */ 366850397Sobrien 366950397Sobrienstatic inline void 367050397Sobrienadd_AT_long_long (die, attr_kind, val_hi, val_low) 367150397Sobrien register dw_die_ref die; 367250397Sobrien register enum dwarf_attribute attr_kind; 367350397Sobrien register unsigned long val_hi; 367450397Sobrien register unsigned long val_low; 367550397Sobrien{ 367650397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 367750397Sobrien 367850397Sobrien attr->dw_attr_next = NULL; 367950397Sobrien attr->dw_attr = attr_kind; 368050397Sobrien attr->dw_attr_val.val_class = dw_val_class_long_long; 368150397Sobrien attr->dw_attr_val.v.val_long_long.hi = val_hi; 368250397Sobrien attr->dw_attr_val.v.val_long_long.low = val_low; 368350397Sobrien add_dwarf_attr (die, attr); 368450397Sobrien} 368550397Sobrien 368650397Sobrien/* Add a floating point attribute value to a DIE and return it. */ 368750397Sobrien 368850397Sobrienstatic inline void 368950397Sobrienadd_AT_float (die, attr_kind, length, array) 369050397Sobrien register dw_die_ref die; 369150397Sobrien register enum dwarf_attribute attr_kind; 369250397Sobrien register unsigned length; 369350397Sobrien register long *array; 369450397Sobrien{ 369550397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 369650397Sobrien 369750397Sobrien attr->dw_attr_next = NULL; 369850397Sobrien attr->dw_attr = attr_kind; 369950397Sobrien attr->dw_attr_val.val_class = dw_val_class_float; 370050397Sobrien attr->dw_attr_val.v.val_float.length = length; 370150397Sobrien attr->dw_attr_val.v.val_float.array = array; 370250397Sobrien add_dwarf_attr (die, attr); 370350397Sobrien} 370450397Sobrien 370550397Sobrien/* Add a string attribute value to a DIE. */ 370650397Sobrien 370750397Sobrienstatic inline void 370850397Sobrienadd_AT_string (die, attr_kind, str) 370950397Sobrien register dw_die_ref die; 371050397Sobrien register enum dwarf_attribute attr_kind; 371150397Sobrien register char *str; 371250397Sobrien{ 371350397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 371450397Sobrien 371550397Sobrien attr->dw_attr_next = NULL; 371650397Sobrien attr->dw_attr = attr_kind; 371750397Sobrien attr->dw_attr_val.val_class = dw_val_class_str; 371850397Sobrien attr->dw_attr_val.v.val_str = xstrdup (str); 371950397Sobrien add_dwarf_attr (die, attr); 372050397Sobrien} 372150397Sobrien 372250397Sobrien/* Add a DIE reference attribute value to a DIE. */ 372350397Sobrien 372450397Sobrienstatic inline void 372550397Sobrienadd_AT_die_ref (die, attr_kind, targ_die) 372650397Sobrien register dw_die_ref die; 372750397Sobrien register enum dwarf_attribute attr_kind; 372850397Sobrien register dw_die_ref targ_die; 372950397Sobrien{ 373050397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 373150397Sobrien 373250397Sobrien attr->dw_attr_next = NULL; 373350397Sobrien attr->dw_attr = attr_kind; 373450397Sobrien attr->dw_attr_val.val_class = dw_val_class_die_ref; 373550397Sobrien attr->dw_attr_val.v.val_die_ref = targ_die; 373650397Sobrien add_dwarf_attr (die, attr); 373750397Sobrien} 373850397Sobrien 373950397Sobrien/* Add an FDE reference attribute value to a DIE. */ 374050397Sobrien 374150397Sobrienstatic inline void 374250397Sobrienadd_AT_fde_ref (die, attr_kind, targ_fde) 374350397Sobrien register dw_die_ref die; 374450397Sobrien register enum dwarf_attribute attr_kind; 374550397Sobrien register unsigned targ_fde; 374650397Sobrien{ 374750397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 374850397Sobrien 374950397Sobrien attr->dw_attr_next = NULL; 375050397Sobrien attr->dw_attr = attr_kind; 375150397Sobrien attr->dw_attr_val.val_class = dw_val_class_fde_ref; 375250397Sobrien attr->dw_attr_val.v.val_fde_index = targ_fde; 375350397Sobrien add_dwarf_attr (die, attr); 375450397Sobrien} 375550397Sobrien 375650397Sobrien/* Add a location description attribute value to a DIE. */ 375750397Sobrien 375850397Sobrienstatic inline void 375950397Sobrienadd_AT_loc (die, attr_kind, loc) 376050397Sobrien register dw_die_ref die; 376150397Sobrien register enum dwarf_attribute attr_kind; 376250397Sobrien register dw_loc_descr_ref loc; 376350397Sobrien{ 376450397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 376550397Sobrien 376650397Sobrien attr->dw_attr_next = NULL; 376750397Sobrien attr->dw_attr = attr_kind; 376850397Sobrien attr->dw_attr_val.val_class = dw_val_class_loc; 376950397Sobrien attr->dw_attr_val.v.val_loc = loc; 377050397Sobrien add_dwarf_attr (die, attr); 377150397Sobrien} 377250397Sobrien 377350397Sobrien/* Add an address constant attribute value to a DIE. */ 377450397Sobrien 377550397Sobrienstatic inline void 377650397Sobrienadd_AT_addr (die, attr_kind, addr) 377750397Sobrien register dw_die_ref die; 377850397Sobrien register enum dwarf_attribute attr_kind; 377950397Sobrien char *addr; 378050397Sobrien{ 378150397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 378250397Sobrien 378350397Sobrien attr->dw_attr_next = NULL; 378450397Sobrien attr->dw_attr = attr_kind; 378550397Sobrien attr->dw_attr_val.val_class = dw_val_class_addr; 378650397Sobrien attr->dw_attr_val.v.val_addr = addr; 378750397Sobrien add_dwarf_attr (die, attr); 378850397Sobrien} 378950397Sobrien 379050397Sobrien/* Add a label identifier attribute value to a DIE. */ 379150397Sobrien 379250397Sobrienstatic inline void 379350397Sobrienadd_AT_lbl_id (die, attr_kind, lbl_id) 379450397Sobrien register dw_die_ref die; 379550397Sobrien register enum dwarf_attribute attr_kind; 379650397Sobrien register char *lbl_id; 379750397Sobrien{ 379850397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 379950397Sobrien 380050397Sobrien attr->dw_attr_next = NULL; 380150397Sobrien attr->dw_attr = attr_kind; 380250397Sobrien attr->dw_attr_val.val_class = dw_val_class_lbl_id; 380350397Sobrien attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); 380450397Sobrien add_dwarf_attr (die, attr); 380550397Sobrien} 380650397Sobrien 380750397Sobrien/* Add a section offset attribute value to a DIE. */ 380850397Sobrien 380950397Sobrienstatic inline void 381050397Sobrienadd_AT_section_offset (die, attr_kind, section) 381150397Sobrien register dw_die_ref die; 381250397Sobrien register enum dwarf_attribute attr_kind; 381350397Sobrien register char *section; 381450397Sobrien{ 381550397Sobrien register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 381650397Sobrien 381750397Sobrien attr->dw_attr_next = NULL; 381850397Sobrien attr->dw_attr = attr_kind; 381950397Sobrien attr->dw_attr_val.val_class = dw_val_class_section_offset; 382050397Sobrien attr->dw_attr_val.v.val_section = section; 382150397Sobrien add_dwarf_attr (die, attr); 382250397Sobrien 382350397Sobrien} 382450397Sobrien 382550397Sobrien/* Test if die refers to an external subroutine. */ 382650397Sobrien 382750397Sobrienstatic inline int 382850397Sobrienis_extern_subr_die (die) 382950397Sobrien register dw_die_ref die; 383050397Sobrien{ 383150397Sobrien register dw_attr_ref a; 383250397Sobrien register int is_subr = FALSE; 383350397Sobrien register int is_extern = FALSE; 383450397Sobrien 383550397Sobrien if (die != NULL && die->die_tag == DW_TAG_subprogram) 383650397Sobrien { 383750397Sobrien is_subr = TRUE; 383850397Sobrien for (a = die->die_attr; a != NULL; a = a->dw_attr_next) 383950397Sobrien { 384050397Sobrien if (a->dw_attr == DW_AT_external 384150397Sobrien && a->dw_attr_val.val_class == dw_val_class_flag 384250397Sobrien && a->dw_attr_val.v.val_flag != 0) 384350397Sobrien { 384450397Sobrien is_extern = TRUE; 384550397Sobrien break; 384650397Sobrien } 384750397Sobrien } 384850397Sobrien } 384950397Sobrien 385050397Sobrien return is_subr && is_extern; 385150397Sobrien} 385250397Sobrien 385350397Sobrien/* Get the attribute of type attr_kind. */ 385450397Sobrien 385550397Sobrienstatic inline dw_attr_ref 385650397Sobrienget_AT (die, attr_kind) 385750397Sobrien register dw_die_ref die; 385850397Sobrien register enum dwarf_attribute attr_kind; 385950397Sobrien{ 386050397Sobrien register dw_attr_ref a; 386150397Sobrien register dw_die_ref spec = NULL; 386250397Sobrien 386350397Sobrien if (die != NULL) 386450397Sobrien { 386550397Sobrien for (a = die->die_attr; a != NULL; a = a->dw_attr_next) 386650397Sobrien { 386750397Sobrien if (a->dw_attr == attr_kind) 386850397Sobrien return a; 386950397Sobrien 387050397Sobrien if (a->dw_attr == DW_AT_specification 387150397Sobrien || a->dw_attr == DW_AT_abstract_origin) 387250397Sobrien spec = a->dw_attr_val.v.val_die_ref; 387350397Sobrien } 387450397Sobrien 387550397Sobrien if (spec) 387650397Sobrien return get_AT (spec, attr_kind); 387750397Sobrien } 387850397Sobrien 387950397Sobrien return NULL; 388050397Sobrien} 388150397Sobrien 388250397Sobrien/* Return the "low pc" attribute value, typically associated with 388350397Sobrien a subprogram DIE. Return null if the "low pc" attribute is 388450397Sobrien either not prsent, or if it cannot be represented as an 388550397Sobrien assembler label identifier. */ 388650397Sobrien 388750397Sobrienstatic inline char * 388850397Sobrienget_AT_low_pc (die) 388950397Sobrien register dw_die_ref die; 389050397Sobrien{ 389150397Sobrien register dw_attr_ref a = get_AT (die, DW_AT_low_pc); 389250397Sobrien 389350397Sobrien if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) 389450397Sobrien return a->dw_attr_val.v.val_lbl_id; 389550397Sobrien 389650397Sobrien return NULL; 389750397Sobrien} 389850397Sobrien 389950397Sobrien/* Return the "high pc" attribute value, typically associated with 390050397Sobrien a subprogram DIE. Return null if the "high pc" attribute is 390150397Sobrien either not prsent, or if it cannot be represented as an 390250397Sobrien assembler label identifier. */ 390350397Sobrien 390450397Sobrienstatic inline char * 390550397Sobrienget_AT_hi_pc (die) 390650397Sobrien register dw_die_ref die; 390750397Sobrien{ 390850397Sobrien register dw_attr_ref a = get_AT (die, DW_AT_high_pc); 390950397Sobrien 391050397Sobrien if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) 391150397Sobrien return a->dw_attr_val.v.val_lbl_id; 391250397Sobrien 391350397Sobrien return NULL; 391450397Sobrien} 391550397Sobrien 391650397Sobrien/* Return the value of the string attribute designated by ATTR_KIND, or 391750397Sobrien NULL if it is not present. */ 391850397Sobrien 391950397Sobrienstatic inline char * 392050397Sobrienget_AT_string (die, attr_kind) 392150397Sobrien register dw_die_ref die; 392250397Sobrien register enum dwarf_attribute attr_kind; 392350397Sobrien{ 392450397Sobrien register dw_attr_ref a = get_AT (die, attr_kind); 392550397Sobrien 392650397Sobrien if (a && a->dw_attr_val.val_class == dw_val_class_str) 392750397Sobrien return a->dw_attr_val.v.val_str; 392850397Sobrien 392950397Sobrien return NULL; 393050397Sobrien} 393150397Sobrien 393250397Sobrien/* Return the value of the flag attribute designated by ATTR_KIND, or -1 393350397Sobrien if it is not present. */ 393450397Sobrien 393550397Sobrienstatic inline int 393650397Sobrienget_AT_flag (die, attr_kind) 393750397Sobrien register dw_die_ref die; 393850397Sobrien register enum dwarf_attribute attr_kind; 393950397Sobrien{ 394050397Sobrien register dw_attr_ref a = get_AT (die, attr_kind); 394150397Sobrien 394250397Sobrien if (a && a->dw_attr_val.val_class == dw_val_class_flag) 394350397Sobrien return a->dw_attr_val.v.val_flag; 394450397Sobrien 394550397Sobrien return -1; 394650397Sobrien} 394750397Sobrien 394850397Sobrien/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0 394950397Sobrien if it is not present. */ 395050397Sobrien 395150397Sobrienstatic inline unsigned 395250397Sobrienget_AT_unsigned (die, attr_kind) 395350397Sobrien register dw_die_ref die; 395450397Sobrien register enum dwarf_attribute attr_kind; 395550397Sobrien{ 395650397Sobrien register dw_attr_ref a = get_AT (die, attr_kind); 395750397Sobrien 395850397Sobrien if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const) 395950397Sobrien return a->dw_attr_val.v.val_unsigned; 396050397Sobrien 396150397Sobrien return 0; 396250397Sobrien} 396350397Sobrien 396450397Sobrienstatic inline int 396550397Sobrienis_c_family () 396650397Sobrien{ 396750397Sobrien register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); 396850397Sobrien 396950397Sobrien return (lang == DW_LANG_C || lang == DW_LANG_C89 397050397Sobrien || lang == DW_LANG_C_plus_plus); 397150397Sobrien} 397250397Sobrien 397350397Sobrienstatic inline int 397450397Sobrienis_fortran () 397550397Sobrien{ 397650397Sobrien register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); 397750397Sobrien 397850397Sobrien return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90); 397950397Sobrien} 398050397Sobrien 398150397Sobrien/* Remove the specified attribute if present. */ 398250397Sobrien 398350397Sobrienstatic inline void 398450397Sobrienremove_AT (die, attr_kind) 398550397Sobrien register dw_die_ref die; 398650397Sobrien register enum dwarf_attribute attr_kind; 398750397Sobrien{ 398850397Sobrien register dw_attr_ref a; 398950397Sobrien register dw_attr_ref removed = NULL;; 399050397Sobrien 399150397Sobrien if (die != NULL) 399250397Sobrien { 399350397Sobrien if (die->die_attr->dw_attr == attr_kind) 399450397Sobrien { 399550397Sobrien removed = die->die_attr; 399650397Sobrien if (die->die_attr_last == die->die_attr) 399750397Sobrien die->die_attr_last = NULL; 399850397Sobrien 399950397Sobrien die->die_attr = die->die_attr->dw_attr_next; 400050397Sobrien } 400150397Sobrien 400250397Sobrien else 400350397Sobrien for (a = die->die_attr; a->dw_attr_next != NULL; 400450397Sobrien a = a->dw_attr_next) 400550397Sobrien if (a->dw_attr_next->dw_attr == attr_kind) 400650397Sobrien { 400750397Sobrien removed = a->dw_attr_next; 400850397Sobrien if (die->die_attr_last == a->dw_attr_next) 400950397Sobrien die->die_attr_last = a; 401050397Sobrien 401150397Sobrien a->dw_attr_next = a->dw_attr_next->dw_attr_next; 401250397Sobrien break; 401350397Sobrien } 401450397Sobrien 401550397Sobrien if (removed != 0) 401650397Sobrien free (removed); 401750397Sobrien } 401850397Sobrien} 401950397Sobrien 402050397Sobrien/* Discard the children of this DIE. */ 402150397Sobrien 402250397Sobrienstatic inline void 402350397Sobrienremove_children (die) 402450397Sobrien register dw_die_ref die; 402550397Sobrien{ 402650397Sobrien register dw_die_ref child_die = die->die_child; 402750397Sobrien 402850397Sobrien die->die_child = NULL; 402950397Sobrien die->die_child_last = NULL; 403050397Sobrien 403150397Sobrien while (child_die != NULL) 403250397Sobrien { 403350397Sobrien register dw_die_ref tmp_die = child_die; 403450397Sobrien register dw_attr_ref a; 403550397Sobrien 403650397Sobrien child_die = child_die->die_sib; 403750397Sobrien 403850397Sobrien for (a = tmp_die->die_attr; a != NULL; ) 403950397Sobrien { 404050397Sobrien register dw_attr_ref tmp_a = a; 404150397Sobrien 404250397Sobrien a = a->dw_attr_next; 404350397Sobrien free (tmp_a); 404450397Sobrien } 404550397Sobrien 404650397Sobrien free (tmp_die); 404750397Sobrien } 404850397Sobrien} 404950397Sobrien 405050397Sobrien/* Add a child DIE below its parent. */ 405150397Sobrien 405250397Sobrienstatic inline void 405350397Sobrienadd_child_die (die, child_die) 405450397Sobrien register dw_die_ref die; 405550397Sobrien register dw_die_ref child_die; 405650397Sobrien{ 405750397Sobrien if (die != NULL && child_die != NULL) 405850397Sobrien { 405950397Sobrien if (die == child_die) 406050397Sobrien abort (); 406150397Sobrien child_die->die_parent = die; 406250397Sobrien child_die->die_sib = NULL; 406350397Sobrien 406450397Sobrien if (die->die_child == NULL) 406550397Sobrien { 406650397Sobrien die->die_child = child_die; 406750397Sobrien die->die_child_last = child_die; 406850397Sobrien } 406950397Sobrien else 407050397Sobrien { 407150397Sobrien die->die_child_last->die_sib = child_die; 407250397Sobrien die->die_child_last = child_die; 407350397Sobrien } 407450397Sobrien } 407550397Sobrien} 407650397Sobrien 407750397Sobrien/* Return a pointer to a newly created DIE node. */ 407850397Sobrien 407950397Sobrienstatic inline dw_die_ref 408050397Sobriennew_die (tag_value, parent_die) 408150397Sobrien register enum dwarf_tag tag_value; 408250397Sobrien register dw_die_ref parent_die; 408350397Sobrien{ 408450397Sobrien register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node)); 408550397Sobrien 408650397Sobrien die->die_tag = tag_value; 408750397Sobrien die->die_abbrev = 0; 408850397Sobrien die->die_offset = 0; 408950397Sobrien die->die_child = NULL; 409050397Sobrien die->die_parent = NULL; 409150397Sobrien die->die_sib = NULL; 409250397Sobrien die->die_child_last = NULL; 409350397Sobrien die->die_attr = NULL; 409450397Sobrien die->die_attr_last = NULL; 409550397Sobrien 409650397Sobrien if (parent_die != NULL) 409750397Sobrien add_child_die (parent_die, die); 409850397Sobrien else 409950397Sobrien { 410050397Sobrien limbo_die_node *limbo_node; 410150397Sobrien 410250397Sobrien limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node)); 410350397Sobrien limbo_node->die = die; 410450397Sobrien limbo_node->next = limbo_die_list; 410550397Sobrien limbo_die_list = limbo_node; 410650397Sobrien } 410750397Sobrien 410850397Sobrien return die; 410950397Sobrien} 411050397Sobrien 411150397Sobrien/* Return the DIE associated with the given type specifier. */ 411250397Sobrien 411350397Sobrienstatic inline dw_die_ref 411450397Sobrienlookup_type_die (type) 411550397Sobrien register tree type; 411650397Sobrien{ 411750397Sobrien return (dw_die_ref) TYPE_SYMTAB_POINTER (type); 411850397Sobrien} 411950397Sobrien 412050397Sobrien/* Equate a DIE to a given type specifier. */ 412150397Sobrien 412250397Sobrienstatic void 412350397Sobrienequate_type_number_to_die (type, type_die) 412450397Sobrien register tree type; 412550397Sobrien register dw_die_ref type_die; 412650397Sobrien{ 412750397Sobrien TYPE_SYMTAB_POINTER (type) = (char *) type_die; 412850397Sobrien} 412950397Sobrien 413050397Sobrien/* Return the DIE associated with a given declaration. */ 413150397Sobrien 413250397Sobrienstatic inline dw_die_ref 413350397Sobrienlookup_decl_die (decl) 413450397Sobrien register tree decl; 413550397Sobrien{ 413650397Sobrien register unsigned decl_id = DECL_UID (decl); 413750397Sobrien 413850397Sobrien return (decl_id < decl_die_table_in_use 413950397Sobrien ? decl_die_table[decl_id] : NULL); 414050397Sobrien} 414150397Sobrien 414250397Sobrien/* Equate a DIE to a particular declaration. */ 414350397Sobrien 414450397Sobrienstatic void 414550397Sobrienequate_decl_number_to_die (decl, decl_die) 414650397Sobrien register tree decl; 414750397Sobrien register dw_die_ref decl_die; 414850397Sobrien{ 414950397Sobrien register unsigned decl_id = DECL_UID (decl); 415050397Sobrien register unsigned num_allocated; 415150397Sobrien 415250397Sobrien if (decl_id >= decl_die_table_allocated) 415350397Sobrien { 415450397Sobrien num_allocated 415550397Sobrien = ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1) 415650397Sobrien / DECL_DIE_TABLE_INCREMENT) 415750397Sobrien * DECL_DIE_TABLE_INCREMENT; 415850397Sobrien 415950397Sobrien decl_die_table 416050397Sobrien = (dw_die_ref *) xrealloc (decl_die_table, 416150397Sobrien sizeof (dw_die_ref) * num_allocated); 416250397Sobrien 416350397Sobrien bzero ((char *) &decl_die_table[decl_die_table_allocated], 416450397Sobrien (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref)); 416550397Sobrien decl_die_table_allocated = num_allocated; 416650397Sobrien } 416750397Sobrien 416850397Sobrien if (decl_id >= decl_die_table_in_use) 416950397Sobrien decl_die_table_in_use = (decl_id + 1); 417050397Sobrien 417150397Sobrien decl_die_table[decl_id] = decl_die; 417250397Sobrien} 417350397Sobrien 417450397Sobrien/* Return a pointer to a newly allocated location description. Location 417550397Sobrien descriptions are simple expression terms that can be strung 417650397Sobrien together to form more complicated location (address) descriptions. */ 417750397Sobrien 417850397Sobrienstatic inline dw_loc_descr_ref 417950397Sobriennew_loc_descr (op, oprnd1, oprnd2) 418050397Sobrien register enum dwarf_location_atom op; 418150397Sobrien register unsigned long oprnd1; 418250397Sobrien register unsigned long oprnd2; 418350397Sobrien{ 418450397Sobrien register dw_loc_descr_ref descr 418550397Sobrien = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node)); 418650397Sobrien 418750397Sobrien descr->dw_loc_next = NULL; 418850397Sobrien descr->dw_loc_opc = op; 418950397Sobrien descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; 419050397Sobrien descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; 419150397Sobrien descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; 419250397Sobrien descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; 419350397Sobrien 419450397Sobrien return descr; 419550397Sobrien} 419650397Sobrien 419750397Sobrien/* Add a location description term to a location description expression. */ 419850397Sobrien 419950397Sobrienstatic inline void 420050397Sobrienadd_loc_descr (list_head, descr) 420150397Sobrien register dw_loc_descr_ref *list_head; 420250397Sobrien register dw_loc_descr_ref descr; 420350397Sobrien{ 420450397Sobrien register dw_loc_descr_ref *d; 420550397Sobrien 420650397Sobrien /* Find the end of the chain. */ 420750397Sobrien for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next) 420850397Sobrien ; 420950397Sobrien 421050397Sobrien *d = descr; 421150397Sobrien} 421250397Sobrien 421350397Sobrien/* Keep track of the number of spaces used to indent the 421450397Sobrien output of the debugging routines that print the structure of 421550397Sobrien the DIE internal representation. */ 421650397Sobrienstatic int print_indent; 421750397Sobrien 421850397Sobrien/* Indent the line the number of spaces given by print_indent. */ 421950397Sobrien 422050397Sobrienstatic inline void 422150397Sobrienprint_spaces (outfile) 422250397Sobrien FILE *outfile; 422350397Sobrien{ 422450397Sobrien fprintf (outfile, "%*s", print_indent, ""); 422550397Sobrien} 422650397Sobrien 422750397Sobrien/* Print the information associated with a given DIE, and its children. 422850397Sobrien This routine is a debugging aid only. */ 422950397Sobrien 423050397Sobrienstatic void 423150397Sobrienprint_die (die, outfile) 423250397Sobrien dw_die_ref die; 423350397Sobrien FILE *outfile; 423450397Sobrien{ 423550397Sobrien register dw_attr_ref a; 423650397Sobrien register dw_die_ref c; 423750397Sobrien 423850397Sobrien print_spaces (outfile); 423950397Sobrien fprintf (outfile, "DIE %4lu: %s\n", 424050397Sobrien die->die_offset, dwarf_tag_name (die->die_tag)); 424150397Sobrien print_spaces (outfile); 424250397Sobrien fprintf (outfile, " abbrev id: %lu", die->die_abbrev); 424350397Sobrien fprintf (outfile, " offset: %lu\n", die->die_offset); 424450397Sobrien 424550397Sobrien for (a = die->die_attr; a != NULL; a = a->dw_attr_next) 424650397Sobrien { 424750397Sobrien print_spaces (outfile); 424850397Sobrien fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr)); 424950397Sobrien 425050397Sobrien switch (a->dw_attr_val.val_class) 425150397Sobrien { 425250397Sobrien case dw_val_class_addr: 425350397Sobrien fprintf (outfile, "address"); 425450397Sobrien break; 425550397Sobrien case dw_val_class_loc: 425650397Sobrien fprintf (outfile, "location descriptor"); 425750397Sobrien break; 425850397Sobrien case dw_val_class_const: 425950397Sobrien fprintf (outfile, "%ld", a->dw_attr_val.v.val_int); 426050397Sobrien break; 426150397Sobrien case dw_val_class_unsigned_const: 426250397Sobrien fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned); 426350397Sobrien break; 426450397Sobrien case dw_val_class_long_long: 426550397Sobrien fprintf (outfile, "constant (%lu,%lu)", 426650397Sobrien a->dw_attr_val.v.val_long_long.hi, 426750397Sobrien a->dw_attr_val.v.val_long_long.low); 426850397Sobrien break; 426950397Sobrien case dw_val_class_float: 427050397Sobrien fprintf (outfile, "floating-point constant"); 427150397Sobrien break; 427250397Sobrien case dw_val_class_flag: 427350397Sobrien fprintf (outfile, "%u", a->dw_attr_val.v.val_flag); 427450397Sobrien break; 427550397Sobrien case dw_val_class_die_ref: 427650397Sobrien if (a->dw_attr_val.v.val_die_ref != NULL) 427750397Sobrien fprintf (outfile, "die -> %lu", 427850397Sobrien a->dw_attr_val.v.val_die_ref->die_offset); 427950397Sobrien else 428050397Sobrien fprintf (outfile, "die -> <null>"); 428150397Sobrien break; 428250397Sobrien case dw_val_class_lbl_id: 428350397Sobrien fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id); 428450397Sobrien break; 428550397Sobrien case dw_val_class_section_offset: 428650397Sobrien fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section); 428750397Sobrien break; 428850397Sobrien case dw_val_class_str: 428950397Sobrien if (a->dw_attr_val.v.val_str != NULL) 429050397Sobrien fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str); 429150397Sobrien else 429250397Sobrien fprintf (outfile, "<null>"); 429350397Sobrien break; 429450397Sobrien default: 429550397Sobrien break; 429650397Sobrien } 429750397Sobrien 429850397Sobrien fprintf (outfile, "\n"); 429950397Sobrien } 430050397Sobrien 430150397Sobrien if (die->die_child != NULL) 430250397Sobrien { 430350397Sobrien print_indent += 4; 430450397Sobrien for (c = die->die_child; c != NULL; c = c->die_sib) 430550397Sobrien print_die (c, outfile); 430650397Sobrien 430750397Sobrien print_indent -= 4; 430850397Sobrien } 430950397Sobrien} 431050397Sobrien 431150397Sobrien/* Print the contents of the source code line number correspondence table. 431250397Sobrien This routine is a debugging aid only. */ 431350397Sobrien 431450397Sobrienstatic void 431550397Sobrienprint_dwarf_line_table (outfile) 431650397Sobrien FILE *outfile; 431750397Sobrien{ 431850397Sobrien register unsigned i; 431950397Sobrien register dw_line_info_ref line_info; 432050397Sobrien 432150397Sobrien fprintf (outfile, "\n\nDWARF source line information\n"); 432250397Sobrien for (i = 1; i < line_info_table_in_use; ++i) 432350397Sobrien { 432450397Sobrien line_info = &line_info_table[i]; 432550397Sobrien fprintf (outfile, "%5d: ", i); 432650397Sobrien fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]); 432750397Sobrien fprintf (outfile, "%6ld", line_info->dw_line_num); 432850397Sobrien fprintf (outfile, "\n"); 432950397Sobrien } 433050397Sobrien 433150397Sobrien fprintf (outfile, "\n\n"); 433250397Sobrien} 433350397Sobrien 433450397Sobrien/* Print the information collected for a given DIE. */ 433550397Sobrien 433650397Sobrienvoid 433750397Sobriendebug_dwarf_die (die) 433850397Sobrien dw_die_ref die; 433950397Sobrien{ 434050397Sobrien print_die (die, stderr); 434150397Sobrien} 434250397Sobrien 434350397Sobrien/* Print all DWARF information collected for the compilation unit. 434450397Sobrien This routine is a debugging aid only. */ 434550397Sobrien 434650397Sobrienvoid 434750397Sobriendebug_dwarf () 434850397Sobrien{ 434950397Sobrien print_indent = 0; 435050397Sobrien print_die (comp_unit_die, stderr); 435150397Sobrien print_dwarf_line_table (stderr); 435250397Sobrien} 435350397Sobrien 435450397Sobrien/* Traverse the DIE, and add a sibling attribute if it may have the 435550397Sobrien effect of speeding up access to siblings. To save some space, 435650397Sobrien avoid generating sibling attributes for DIE's without children. */ 435750397Sobrien 435850397Sobrienstatic void 435950397Sobrienadd_sibling_attributes(die) 436050397Sobrien register dw_die_ref die; 436150397Sobrien{ 436250397Sobrien register dw_die_ref c; 436350397Sobrien register dw_attr_ref attr; 436450397Sobrien if (die != comp_unit_die && die->die_child != NULL) 436550397Sobrien { 436650397Sobrien attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); 436750397Sobrien attr->dw_attr_next = NULL; 436850397Sobrien attr->dw_attr = DW_AT_sibling; 436950397Sobrien attr->dw_attr_val.val_class = dw_val_class_die_ref; 437050397Sobrien attr->dw_attr_val.v.val_die_ref = die->die_sib; 437150397Sobrien 437250397Sobrien /* Add the sibling link to the front of the attribute list. */ 437350397Sobrien attr->dw_attr_next = die->die_attr; 437450397Sobrien if (die->die_attr == NULL) 437550397Sobrien die->die_attr_last = attr; 437650397Sobrien 437750397Sobrien die->die_attr = attr; 437850397Sobrien } 437950397Sobrien 438050397Sobrien for (c = die->die_child; c != NULL; c = c->die_sib) 438150397Sobrien add_sibling_attributes (c); 438250397Sobrien} 438350397Sobrien 438450397Sobrien/* The format of each DIE (and its attribute value pairs) 438550397Sobrien is encoded in an abbreviation table. This routine builds the 438650397Sobrien abbreviation table and assigns a unique abbreviation id for 438750397Sobrien each abbreviation entry. The children of each die are visited 438850397Sobrien recursively. */ 438950397Sobrien 439050397Sobrienstatic void 439150397Sobrienbuild_abbrev_table (die) 439250397Sobrien register dw_die_ref die; 439350397Sobrien{ 439450397Sobrien register unsigned long abbrev_id; 439550397Sobrien register unsigned long n_alloc; 439650397Sobrien register dw_die_ref c; 439750397Sobrien register dw_attr_ref d_attr, a_attr; 439850397Sobrien for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) 439950397Sobrien { 440050397Sobrien register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; 440150397Sobrien 440250397Sobrien if (abbrev->die_tag == die->die_tag) 440350397Sobrien { 440450397Sobrien if ((abbrev->die_child != NULL) == (die->die_child != NULL)) 440550397Sobrien { 440650397Sobrien a_attr = abbrev->die_attr; 440750397Sobrien d_attr = die->die_attr; 440850397Sobrien 440950397Sobrien while (a_attr != NULL && d_attr != NULL) 441050397Sobrien { 441150397Sobrien if ((a_attr->dw_attr != d_attr->dw_attr) 441250397Sobrien || (value_format (&a_attr->dw_attr_val) 441350397Sobrien != value_format (&d_attr->dw_attr_val))) 441450397Sobrien break; 441550397Sobrien 441650397Sobrien a_attr = a_attr->dw_attr_next; 441750397Sobrien d_attr = d_attr->dw_attr_next; 441850397Sobrien } 441950397Sobrien 442050397Sobrien if (a_attr == NULL && d_attr == NULL) 442150397Sobrien break; 442250397Sobrien } 442350397Sobrien } 442450397Sobrien } 442550397Sobrien 442650397Sobrien if (abbrev_id >= abbrev_die_table_in_use) 442750397Sobrien { 442850397Sobrien if (abbrev_die_table_in_use >= abbrev_die_table_allocated) 442950397Sobrien { 443050397Sobrien n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT; 443150397Sobrien abbrev_die_table 443250397Sobrien = (dw_die_ref *) xrealloc (abbrev_die_table, 443350397Sobrien sizeof (dw_die_ref) * n_alloc); 443450397Sobrien 443550397Sobrien bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated], 443650397Sobrien (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref)); 443750397Sobrien abbrev_die_table_allocated = n_alloc; 443850397Sobrien } 443950397Sobrien 444050397Sobrien ++abbrev_die_table_in_use; 444150397Sobrien abbrev_die_table[abbrev_id] = die; 444250397Sobrien } 444350397Sobrien 444450397Sobrien die->die_abbrev = abbrev_id; 444550397Sobrien for (c = die->die_child; c != NULL; c = c->die_sib) 444650397Sobrien build_abbrev_table (c); 444750397Sobrien} 444850397Sobrien 444950397Sobrien/* Return the size of a string, including the null byte. 445050397Sobrien 445150397Sobrien This used to treat backslashes as escapes, and hence they were not included 445250397Sobrien in the count. However, that conflicts with what ASM_OUTPUT_ASCII does, 445350397Sobrien which treats a backslash as a backslash, escaping it if necessary, and hence 445450397Sobrien we must include them in the count. */ 445550397Sobrien 445650397Sobrienstatic unsigned long 445750397Sobriensize_of_string (str) 445850397Sobrien register char *str; 445950397Sobrien{ 446050397Sobrien return strlen (str) + 1; 446150397Sobrien} 446250397Sobrien 446350397Sobrien/* Return the size of a location descriptor. */ 446450397Sobrien 446550397Sobrienstatic unsigned long 446650397Sobriensize_of_loc_descr (loc) 446750397Sobrien register dw_loc_descr_ref loc; 446850397Sobrien{ 446950397Sobrien register unsigned long size = 1; 447050397Sobrien 447150397Sobrien switch (loc->dw_loc_opc) 447250397Sobrien { 447350397Sobrien case DW_OP_addr: 447450397Sobrien size += PTR_SIZE; 447550397Sobrien break; 447650397Sobrien case DW_OP_const1u: 447750397Sobrien case DW_OP_const1s: 447850397Sobrien size += 1; 447950397Sobrien break; 448050397Sobrien case DW_OP_const2u: 448150397Sobrien case DW_OP_const2s: 448250397Sobrien size += 2; 448350397Sobrien break; 448450397Sobrien case DW_OP_const4u: 448550397Sobrien case DW_OP_const4s: 448650397Sobrien size += 4; 448750397Sobrien break; 448850397Sobrien case DW_OP_const8u: 448950397Sobrien case DW_OP_const8s: 449050397Sobrien size += 8; 449150397Sobrien break; 449250397Sobrien case DW_OP_constu: 449350397Sobrien size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); 449450397Sobrien break; 449550397Sobrien case DW_OP_consts: 449650397Sobrien size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); 449750397Sobrien break; 449850397Sobrien case DW_OP_pick: 449950397Sobrien size += 1; 450050397Sobrien break; 450150397Sobrien case DW_OP_plus_uconst: 450250397Sobrien size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); 450350397Sobrien break; 450450397Sobrien case DW_OP_skip: 450550397Sobrien case DW_OP_bra: 450650397Sobrien size += 2; 450750397Sobrien break; 450850397Sobrien case DW_OP_breg0: 450950397Sobrien case DW_OP_breg1: 451050397Sobrien case DW_OP_breg2: 451150397Sobrien case DW_OP_breg3: 451250397Sobrien case DW_OP_breg4: 451350397Sobrien case DW_OP_breg5: 451450397Sobrien case DW_OP_breg6: 451550397Sobrien case DW_OP_breg7: 451650397Sobrien case DW_OP_breg8: 451750397Sobrien case DW_OP_breg9: 451850397Sobrien case DW_OP_breg10: 451950397Sobrien case DW_OP_breg11: 452050397Sobrien case DW_OP_breg12: 452150397Sobrien case DW_OP_breg13: 452250397Sobrien case DW_OP_breg14: 452350397Sobrien case DW_OP_breg15: 452450397Sobrien case DW_OP_breg16: 452550397Sobrien case DW_OP_breg17: 452650397Sobrien case DW_OP_breg18: 452750397Sobrien case DW_OP_breg19: 452850397Sobrien case DW_OP_breg20: 452950397Sobrien case DW_OP_breg21: 453050397Sobrien case DW_OP_breg22: 453150397Sobrien case DW_OP_breg23: 453250397Sobrien case DW_OP_breg24: 453350397Sobrien case DW_OP_breg25: 453450397Sobrien case DW_OP_breg26: 453550397Sobrien case DW_OP_breg27: 453650397Sobrien case DW_OP_breg28: 453750397Sobrien case DW_OP_breg29: 453850397Sobrien case DW_OP_breg30: 453950397Sobrien case DW_OP_breg31: 454050397Sobrien size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); 454150397Sobrien break; 454250397Sobrien case DW_OP_regx: 454350397Sobrien size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); 454450397Sobrien break; 454550397Sobrien case DW_OP_fbreg: 454650397Sobrien size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); 454750397Sobrien break; 454850397Sobrien case DW_OP_bregx: 454950397Sobrien size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); 455050397Sobrien size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int); 455150397Sobrien break; 455250397Sobrien case DW_OP_piece: 455350397Sobrien size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); 455450397Sobrien break; 455550397Sobrien case DW_OP_deref_size: 455650397Sobrien case DW_OP_xderef_size: 455750397Sobrien size += 1; 455850397Sobrien break; 455950397Sobrien default: 456050397Sobrien break; 456150397Sobrien } 456250397Sobrien 456350397Sobrien return size; 456450397Sobrien} 456550397Sobrien 456650397Sobrien/* Return the size of a series of location descriptors. */ 456750397Sobrien 456850397Sobrienstatic unsigned long 456950397Sobriensize_of_locs (loc) 457050397Sobrien register dw_loc_descr_ref loc; 457150397Sobrien{ 457250397Sobrien register unsigned long size = 0; 457350397Sobrien 457450397Sobrien for (; loc != NULL; loc = loc->dw_loc_next) 457550397Sobrien size += size_of_loc_descr (loc); 457650397Sobrien 457750397Sobrien return size; 457850397Sobrien} 457950397Sobrien 458050397Sobrien/* Return the power-of-two number of bytes necessary to represent VALUE. */ 458150397Sobrien 458250397Sobrienstatic int 458350397Sobrienconstant_size (value) 458450397Sobrien long unsigned value; 458550397Sobrien{ 458650397Sobrien int log; 458750397Sobrien 458850397Sobrien if (value == 0) 458950397Sobrien log = 0; 459050397Sobrien else 459150397Sobrien log = floor_log2 (value); 459250397Sobrien 459350397Sobrien log = log / 8; 459450397Sobrien log = 1 << (floor_log2 (log) + 1); 459550397Sobrien 459650397Sobrien return log; 459750397Sobrien} 459850397Sobrien 459950397Sobrien/* Return the size of a DIE, as it is represented in the 460050397Sobrien .debug_info section. */ 460150397Sobrien 460250397Sobrienstatic unsigned long 460350397Sobriensize_of_die (die) 460450397Sobrien register dw_die_ref die; 460550397Sobrien{ 460650397Sobrien register unsigned long size = 0; 460750397Sobrien register dw_attr_ref a; 460850397Sobrien 460950397Sobrien size += size_of_uleb128 (die->die_abbrev); 461050397Sobrien for (a = die->die_attr; a != NULL; a = a->dw_attr_next) 461150397Sobrien { 461250397Sobrien switch (a->dw_attr_val.val_class) 461350397Sobrien { 461450397Sobrien case dw_val_class_addr: 461550397Sobrien size += PTR_SIZE; 461650397Sobrien break; 461750397Sobrien case dw_val_class_loc: 461850397Sobrien { 461950397Sobrien register unsigned long lsize 462050397Sobrien = size_of_locs (a->dw_attr_val.v.val_loc); 462150397Sobrien 462250397Sobrien /* Block length. */ 462350397Sobrien size += constant_size (lsize); 462450397Sobrien size += lsize; 462550397Sobrien } 462650397Sobrien break; 462750397Sobrien case dw_val_class_const: 462850397Sobrien size += 4; 462950397Sobrien break; 463050397Sobrien case dw_val_class_unsigned_const: 463150397Sobrien size += constant_size (a->dw_attr_val.v.val_unsigned); 463250397Sobrien break; 463350397Sobrien case dw_val_class_long_long: 463450397Sobrien size += 1 + 8; /* block */ 463550397Sobrien break; 463650397Sobrien case dw_val_class_float: 463750397Sobrien size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */ 463850397Sobrien break; 463950397Sobrien case dw_val_class_flag: 464050397Sobrien size += 1; 464150397Sobrien break; 464250397Sobrien case dw_val_class_die_ref: 464350397Sobrien size += DWARF_OFFSET_SIZE; 464450397Sobrien break; 464550397Sobrien case dw_val_class_fde_ref: 464650397Sobrien size += DWARF_OFFSET_SIZE; 464750397Sobrien break; 464850397Sobrien case dw_val_class_lbl_id: 464950397Sobrien size += PTR_SIZE; 465050397Sobrien break; 465150397Sobrien case dw_val_class_section_offset: 465250397Sobrien size += DWARF_OFFSET_SIZE; 465350397Sobrien break; 465450397Sobrien case dw_val_class_str: 465550397Sobrien size += size_of_string (a->dw_attr_val.v.val_str); 465650397Sobrien break; 465750397Sobrien default: 465850397Sobrien abort (); 465950397Sobrien } 466050397Sobrien } 466150397Sobrien 466250397Sobrien return size; 466350397Sobrien} 466450397Sobrien 466550397Sobrien/* Size the debugging information associated with a given DIE. 466650397Sobrien Visits the DIE's children recursively. Updates the global 466750397Sobrien variable next_die_offset, on each time through. Uses the 466850397Sobrien current value of next_die_offset to update the die_offset 466950397Sobrien field in each DIE. */ 467050397Sobrien 467150397Sobrienstatic void 467250397Sobriencalc_die_sizes (die) 467350397Sobrien dw_die_ref die; 467450397Sobrien{ 467550397Sobrien register dw_die_ref c; 467650397Sobrien die->die_offset = next_die_offset; 467750397Sobrien next_die_offset += size_of_die (die); 467850397Sobrien 467950397Sobrien for (c = die->die_child; c != NULL; c = c->die_sib) 468050397Sobrien calc_die_sizes (c); 468150397Sobrien 468250397Sobrien if (die->die_child != NULL) 468350397Sobrien /* Count the null byte used to terminate sibling lists. */ 468450397Sobrien next_die_offset += 1; 468550397Sobrien} 468650397Sobrien 468750397Sobrien/* Return the size of the line information prolog generated for the 468850397Sobrien compilation unit. */ 468950397Sobrien 469050397Sobrienstatic unsigned long 469150397Sobriensize_of_line_prolog () 469250397Sobrien{ 469350397Sobrien register unsigned long size; 469450397Sobrien register unsigned long ft_index; 469550397Sobrien 469650397Sobrien size = DWARF_LINE_PROLOG_HEADER_SIZE; 469750397Sobrien 469850397Sobrien /* Count the size of the table giving number of args for each 469950397Sobrien standard opcode. */ 470050397Sobrien size += DWARF_LINE_OPCODE_BASE - 1; 470150397Sobrien 470250397Sobrien /* Include directory table is empty (at present). Count only the 470350397Sobrien null byte used to terminate the table. */ 470450397Sobrien size += 1; 470550397Sobrien 470650397Sobrien for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) 470750397Sobrien { 470850397Sobrien /* File name entry. */ 470950397Sobrien size += size_of_string (file_table[ft_index]); 471050397Sobrien 471150397Sobrien /* Include directory index. */ 471250397Sobrien size += size_of_uleb128 (0); 471350397Sobrien 471450397Sobrien /* Modification time. */ 471550397Sobrien size += size_of_uleb128 (0); 471650397Sobrien 471750397Sobrien /* File length in bytes. */ 471850397Sobrien size += size_of_uleb128 (0); 471950397Sobrien } 472050397Sobrien 472150397Sobrien /* Count the file table terminator. */ 472250397Sobrien size += 1; 472350397Sobrien return size; 472450397Sobrien} 472550397Sobrien 472650397Sobrien/* Return the size of the line information generated for this 472750397Sobrien compilation unit. */ 472850397Sobrien 472950397Sobrienstatic unsigned long 473050397Sobriensize_of_line_info () 473150397Sobrien{ 473250397Sobrien register unsigned long size; 473350397Sobrien register unsigned long lt_index; 473450397Sobrien register unsigned long current_line; 473550397Sobrien register long line_offset; 473650397Sobrien register long line_delta; 473750397Sobrien register unsigned long current_file; 473850397Sobrien register unsigned long function; 473950397Sobrien unsigned long size_of_set_address; 474050397Sobrien 474150397Sobrien /* Size of a DW_LNE_set_address instruction. */ 474250397Sobrien size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE; 474350397Sobrien 474450397Sobrien /* Version number. */ 474550397Sobrien size = 2; 474650397Sobrien 474750397Sobrien /* Prolog length specifier. */ 474850397Sobrien size += DWARF_OFFSET_SIZE; 474950397Sobrien 475050397Sobrien /* Prolog. */ 475150397Sobrien size += size_of_line_prolog (); 475250397Sobrien 475350397Sobrien /* Set address register instruction. */ 475450397Sobrien size += size_of_set_address; 475550397Sobrien 475650397Sobrien current_file = 1; 475750397Sobrien current_line = 1; 475850397Sobrien for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) 475950397Sobrien { 476050397Sobrien register dw_line_info_ref line_info; 476150397Sobrien 476250397Sobrien /* Advance pc instruction. */ 476350397Sobrien /* ??? See the DW_LNS_advance_pc comment in output_line_info. */ 476450397Sobrien if (0) 476550397Sobrien size += 1 + 2; 476650397Sobrien else 476750397Sobrien size += size_of_set_address; 476850397Sobrien 476950397Sobrien line_info = &line_info_table[lt_index]; 477050397Sobrien if (line_info->dw_file_num != current_file) 477150397Sobrien { 477250397Sobrien /* Set file number instruction. */ 477350397Sobrien size += 1; 477450397Sobrien current_file = line_info->dw_file_num; 477550397Sobrien size += size_of_uleb128 (current_file); 477650397Sobrien } 477750397Sobrien 477850397Sobrien if (line_info->dw_line_num != current_line) 477950397Sobrien { 478050397Sobrien line_offset = line_info->dw_line_num - current_line; 478150397Sobrien line_delta = line_offset - DWARF_LINE_BASE; 478250397Sobrien current_line = line_info->dw_line_num; 478350397Sobrien if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) 478450397Sobrien /* 1-byte special line number instruction. */ 478550397Sobrien size += 1; 478650397Sobrien else 478750397Sobrien { 478850397Sobrien /* Advance line instruction. */ 478950397Sobrien size += 1; 479050397Sobrien size += size_of_sleb128 (line_offset); 479150397Sobrien /* Generate line entry instruction. */ 479250397Sobrien size += 1; 479350397Sobrien } 479450397Sobrien } 479550397Sobrien } 479650397Sobrien 479750397Sobrien /* Advance pc instruction. */ 479850397Sobrien if (0) 479950397Sobrien size += 1 + 2; 480050397Sobrien else 480150397Sobrien size += size_of_set_address; 480250397Sobrien 480350397Sobrien /* End of line number info. marker. */ 480450397Sobrien size += 1 + size_of_uleb128 (1) + 1; 480550397Sobrien 480650397Sobrien function = 0; 480750397Sobrien current_file = 1; 480850397Sobrien current_line = 1; 480950397Sobrien for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) 481050397Sobrien { 481150397Sobrien register dw_separate_line_info_ref line_info 481250397Sobrien = &separate_line_info_table[lt_index]; 481350397Sobrien if (function != line_info->function) 481450397Sobrien { 481550397Sobrien function = line_info->function; 481650397Sobrien /* Set address register instruction. */ 481750397Sobrien size += size_of_set_address; 481850397Sobrien } 481950397Sobrien else 482050397Sobrien { 482150397Sobrien /* Advance pc instruction. */ 482250397Sobrien if (0) 482350397Sobrien size += 1 + 2; 482450397Sobrien else 482550397Sobrien size += size_of_set_address; 482650397Sobrien } 482750397Sobrien 482850397Sobrien if (line_info->dw_file_num != current_file) 482950397Sobrien { 483050397Sobrien /* Set file number instruction. */ 483150397Sobrien size += 1; 483250397Sobrien current_file = line_info->dw_file_num; 483350397Sobrien size += size_of_uleb128 (current_file); 483450397Sobrien } 483550397Sobrien 483650397Sobrien if (line_info->dw_line_num != current_line) 483750397Sobrien { 483850397Sobrien line_offset = line_info->dw_line_num - current_line; 483950397Sobrien line_delta = line_offset - DWARF_LINE_BASE; 484050397Sobrien current_line = line_info->dw_line_num; 484150397Sobrien if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) 484250397Sobrien /* 1-byte special line number instruction. */ 484350397Sobrien size += 1; 484450397Sobrien else 484550397Sobrien { 484650397Sobrien /* Advance line instruction. */ 484750397Sobrien size += 1; 484850397Sobrien size += size_of_sleb128 (line_offset); 484950397Sobrien 485050397Sobrien /* Generate line entry instruction. */ 485150397Sobrien size += 1; 485250397Sobrien } 485350397Sobrien } 485450397Sobrien 485550397Sobrien ++lt_index; 485650397Sobrien 485750397Sobrien /* If we're done with a function, end its sequence. */ 485850397Sobrien if (lt_index == separate_line_info_table_in_use 485950397Sobrien || separate_line_info_table[lt_index].function != function) 486050397Sobrien { 486150397Sobrien current_file = 1; 486250397Sobrien current_line = 1; 486350397Sobrien 486450397Sobrien /* Advance pc instruction. */ 486550397Sobrien if (0) 486650397Sobrien size += 1 + 2; 486750397Sobrien else 486850397Sobrien size += size_of_set_address; 486950397Sobrien 487050397Sobrien /* End of line number info. marker. */ 487150397Sobrien size += 1 + size_of_uleb128 (1) + 1; 487250397Sobrien } 487350397Sobrien } 487450397Sobrien 487550397Sobrien return size; 487650397Sobrien} 487750397Sobrien 487850397Sobrien/* Return the size of the .debug_pubnames table generated for the 487950397Sobrien compilation unit. */ 488050397Sobrien 488150397Sobrienstatic unsigned long 488250397Sobriensize_of_pubnames () 488350397Sobrien{ 488450397Sobrien register unsigned long size; 488550397Sobrien register unsigned i; 488650397Sobrien 488750397Sobrien size = DWARF_PUBNAMES_HEADER_SIZE; 488850397Sobrien for (i = 0; i < pubname_table_in_use; ++i) 488950397Sobrien { 489050397Sobrien register pubname_ref p = &pubname_table[i]; 489150397Sobrien size += DWARF_OFFSET_SIZE + size_of_string (p->name); 489250397Sobrien } 489350397Sobrien 489450397Sobrien size += DWARF_OFFSET_SIZE; 489550397Sobrien return size; 489650397Sobrien} 489750397Sobrien 489850397Sobrien/* Return the size of the information in the .debug_aranges section. */ 489950397Sobrien 490050397Sobrienstatic unsigned long 490150397Sobriensize_of_aranges () 490250397Sobrien{ 490350397Sobrien register unsigned long size; 490450397Sobrien 490550397Sobrien size = DWARF_ARANGES_HEADER_SIZE; 490650397Sobrien 490750397Sobrien /* Count the address/length pair for this compilation unit. */ 490850397Sobrien size += 2 * PTR_SIZE; 490950397Sobrien size += 2 * PTR_SIZE * arange_table_in_use; 491050397Sobrien 491150397Sobrien /* Count the two zero words used to terminated the address range table. */ 491250397Sobrien size += 2 * PTR_SIZE; 491350397Sobrien return size; 491450397Sobrien} 491550397Sobrien 491650397Sobrien/* Select the encoding of an attribute value. */ 491750397Sobrien 491850397Sobrienstatic enum dwarf_form 491950397Sobrienvalue_format (v) 492050397Sobrien dw_val_ref v; 492150397Sobrien{ 492250397Sobrien switch (v->val_class) 492350397Sobrien { 492450397Sobrien case dw_val_class_addr: 492550397Sobrien return DW_FORM_addr; 492650397Sobrien case dw_val_class_loc: 492750397Sobrien switch (constant_size (size_of_locs (v->v.val_loc))) 492850397Sobrien { 492950397Sobrien case 1: 493050397Sobrien return DW_FORM_block1; 493150397Sobrien case 2: 493250397Sobrien return DW_FORM_block2; 493350397Sobrien default: 493450397Sobrien abort (); 493550397Sobrien } 493650397Sobrien case dw_val_class_const: 493750397Sobrien return DW_FORM_data4; 493850397Sobrien case dw_val_class_unsigned_const: 493950397Sobrien switch (constant_size (v->v.val_unsigned)) 494050397Sobrien { 494150397Sobrien case 1: 494250397Sobrien return DW_FORM_data1; 494350397Sobrien case 2: 494450397Sobrien return DW_FORM_data2; 494550397Sobrien case 4: 494650397Sobrien return DW_FORM_data4; 494750397Sobrien case 8: 494850397Sobrien return DW_FORM_data8; 494950397Sobrien default: 495050397Sobrien abort (); 495150397Sobrien } 495250397Sobrien case dw_val_class_long_long: 495350397Sobrien return DW_FORM_block1; 495450397Sobrien case dw_val_class_float: 495550397Sobrien return DW_FORM_block1; 495650397Sobrien case dw_val_class_flag: 495750397Sobrien return DW_FORM_flag; 495850397Sobrien case dw_val_class_die_ref: 495950397Sobrien return DW_FORM_ref; 496050397Sobrien case dw_val_class_fde_ref: 496150397Sobrien return DW_FORM_data; 496250397Sobrien case dw_val_class_lbl_id: 496350397Sobrien return DW_FORM_addr; 496450397Sobrien case dw_val_class_section_offset: 496550397Sobrien return DW_FORM_data; 496650397Sobrien case dw_val_class_str: 496750397Sobrien return DW_FORM_string; 496850397Sobrien default: 496950397Sobrien abort (); 497050397Sobrien } 497150397Sobrien} 497250397Sobrien 497350397Sobrien/* Output the encoding of an attribute value. */ 497450397Sobrien 497550397Sobrienstatic void 497650397Sobrienoutput_value_format (v) 497750397Sobrien dw_val_ref v; 497850397Sobrien{ 497950397Sobrien enum dwarf_form form = value_format (v); 498050397Sobrien 498150397Sobrien output_uleb128 (form); 498250397Sobrien if (flag_debug_asm) 498350397Sobrien fprintf (asm_out_file, " (%s)", dwarf_form_name (form)); 498450397Sobrien 498550397Sobrien fputc ('\n', asm_out_file); 498650397Sobrien} 498750397Sobrien 498850397Sobrien/* Output the .debug_abbrev section which defines the DIE abbreviation 498950397Sobrien table. */ 499050397Sobrien 499150397Sobrienstatic void 499250397Sobrienoutput_abbrev_section () 499350397Sobrien{ 499450397Sobrien unsigned long abbrev_id; 499550397Sobrien 499650397Sobrien dw_attr_ref a_attr; 499750397Sobrien for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) 499850397Sobrien { 499950397Sobrien register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; 500050397Sobrien 500150397Sobrien output_uleb128 (abbrev_id); 500250397Sobrien if (flag_debug_asm) 500350397Sobrien fprintf (asm_out_file, " (abbrev code)"); 500450397Sobrien 500550397Sobrien fputc ('\n', asm_out_file); 500650397Sobrien output_uleb128 (abbrev->die_tag); 500750397Sobrien if (flag_debug_asm) 500850397Sobrien fprintf (asm_out_file, " (TAG: %s)", 500950397Sobrien dwarf_tag_name (abbrev->die_tag)); 501050397Sobrien 501150397Sobrien fputc ('\n', asm_out_file); 501250397Sobrien fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, 501350397Sobrien abbrev->die_child != NULL ? DW_children_yes : DW_children_no); 501450397Sobrien 501550397Sobrien if (flag_debug_asm) 501650397Sobrien fprintf (asm_out_file, "\t%s %s", 501750397Sobrien ASM_COMMENT_START, 501850397Sobrien (abbrev->die_child != NULL 501950397Sobrien ? "DW_children_yes" : "DW_children_no")); 502050397Sobrien 502150397Sobrien fputc ('\n', asm_out_file); 502250397Sobrien 502350397Sobrien for (a_attr = abbrev->die_attr; a_attr != NULL; 502450397Sobrien a_attr = a_attr->dw_attr_next) 502550397Sobrien { 502650397Sobrien output_uleb128 (a_attr->dw_attr); 502750397Sobrien if (flag_debug_asm) 502850397Sobrien fprintf (asm_out_file, " (%s)", 502950397Sobrien dwarf_attr_name (a_attr->dw_attr)); 503050397Sobrien 503150397Sobrien fputc ('\n', asm_out_file); 503250397Sobrien output_value_format (&a_attr->dw_attr_val); 503350397Sobrien } 503450397Sobrien 503550397Sobrien fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP); 503650397Sobrien } 503750397Sobrien} 503850397Sobrien 503950397Sobrien/* Output location description stack opcode's operands (if any). */ 504050397Sobrien 504150397Sobrienstatic void 504250397Sobrienoutput_loc_operands (loc) 504350397Sobrien register dw_loc_descr_ref loc; 504450397Sobrien{ 504550397Sobrien register dw_val_ref val1 = &loc->dw_loc_oprnd1; 504650397Sobrien register dw_val_ref val2 = &loc->dw_loc_oprnd2; 504750397Sobrien 504850397Sobrien switch (loc->dw_loc_opc) 504950397Sobrien { 505050397Sobrien case DW_OP_addr: 505150397Sobrien ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr); 505250397Sobrien fputc ('\n', asm_out_file); 505350397Sobrien break; 505450397Sobrien case DW_OP_const1u: 505550397Sobrien case DW_OP_const1s: 505650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); 505750397Sobrien fputc ('\n', asm_out_file); 505850397Sobrien break; 505950397Sobrien case DW_OP_const2u: 506050397Sobrien case DW_OP_const2s: 506150397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); 506250397Sobrien fputc ('\n', asm_out_file); 506350397Sobrien break; 506450397Sobrien case DW_OP_const4u: 506550397Sobrien case DW_OP_const4s: 506650397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int); 506750397Sobrien fputc ('\n', asm_out_file); 506850397Sobrien break; 506950397Sobrien case DW_OP_const8u: 507050397Sobrien case DW_OP_const8s: 507150397Sobrien abort (); 507250397Sobrien fputc ('\n', asm_out_file); 507350397Sobrien break; 507450397Sobrien case DW_OP_constu: 507550397Sobrien output_uleb128 (val1->v.val_unsigned); 507650397Sobrien fputc ('\n', asm_out_file); 507750397Sobrien break; 507850397Sobrien case DW_OP_consts: 507950397Sobrien output_sleb128 (val1->v.val_int); 508050397Sobrien fputc ('\n', asm_out_file); 508150397Sobrien break; 508250397Sobrien case DW_OP_pick: 508350397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int); 508450397Sobrien fputc ('\n', asm_out_file); 508550397Sobrien break; 508650397Sobrien case DW_OP_plus_uconst: 508750397Sobrien output_uleb128 (val1->v.val_unsigned); 508850397Sobrien fputc ('\n', asm_out_file); 508950397Sobrien break; 509050397Sobrien case DW_OP_skip: 509150397Sobrien case DW_OP_bra: 509250397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); 509350397Sobrien fputc ('\n', asm_out_file); 509450397Sobrien break; 509550397Sobrien case DW_OP_breg0: 509650397Sobrien case DW_OP_breg1: 509750397Sobrien case DW_OP_breg2: 509850397Sobrien case DW_OP_breg3: 509950397Sobrien case DW_OP_breg4: 510050397Sobrien case DW_OP_breg5: 510150397Sobrien case DW_OP_breg6: 510250397Sobrien case DW_OP_breg7: 510350397Sobrien case DW_OP_breg8: 510450397Sobrien case DW_OP_breg9: 510550397Sobrien case DW_OP_breg10: 510650397Sobrien case DW_OP_breg11: 510750397Sobrien case DW_OP_breg12: 510850397Sobrien case DW_OP_breg13: 510950397Sobrien case DW_OP_breg14: 511050397Sobrien case DW_OP_breg15: 511150397Sobrien case DW_OP_breg16: 511250397Sobrien case DW_OP_breg17: 511350397Sobrien case DW_OP_breg18: 511450397Sobrien case DW_OP_breg19: 511550397Sobrien case DW_OP_breg20: 511650397Sobrien case DW_OP_breg21: 511750397Sobrien case DW_OP_breg22: 511850397Sobrien case DW_OP_breg23: 511950397Sobrien case DW_OP_breg24: 512050397Sobrien case DW_OP_breg25: 512150397Sobrien case DW_OP_breg26: 512250397Sobrien case DW_OP_breg27: 512350397Sobrien case DW_OP_breg28: 512450397Sobrien case DW_OP_breg29: 512550397Sobrien case DW_OP_breg30: 512650397Sobrien case DW_OP_breg31: 512750397Sobrien output_sleb128 (val1->v.val_int); 512850397Sobrien fputc ('\n', asm_out_file); 512950397Sobrien break; 513050397Sobrien case DW_OP_regx: 513150397Sobrien output_uleb128 (val1->v.val_unsigned); 513250397Sobrien fputc ('\n', asm_out_file); 513350397Sobrien break; 513450397Sobrien case DW_OP_fbreg: 513550397Sobrien output_sleb128 (val1->v.val_int); 513650397Sobrien fputc ('\n', asm_out_file); 513750397Sobrien break; 513850397Sobrien case DW_OP_bregx: 513950397Sobrien output_uleb128 (val1->v.val_unsigned); 514050397Sobrien fputc ('\n', asm_out_file); 514150397Sobrien output_sleb128 (val2->v.val_int); 514250397Sobrien fputc ('\n', asm_out_file); 514350397Sobrien break; 514450397Sobrien case DW_OP_piece: 514550397Sobrien output_uleb128 (val1->v.val_unsigned); 514650397Sobrien fputc ('\n', asm_out_file); 514750397Sobrien break; 514850397Sobrien case DW_OP_deref_size: 514950397Sobrien case DW_OP_xderef_size: 515050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); 515150397Sobrien fputc ('\n', asm_out_file); 515250397Sobrien break; 515350397Sobrien default: 515450397Sobrien break; 515550397Sobrien } 515650397Sobrien} 515750397Sobrien 515850397Sobrien/* Compute the offset of a sibling. */ 515950397Sobrien 516050397Sobrienstatic unsigned long 516150397Sobriensibling_offset (die) 516250397Sobrien dw_die_ref die; 516350397Sobrien{ 516450397Sobrien unsigned long offset; 516550397Sobrien 516650397Sobrien if (die->die_child_last == NULL) 516750397Sobrien offset = die->die_offset + size_of_die (die); 516850397Sobrien else 516950397Sobrien offset = sibling_offset (die->die_child_last) + 1; 517050397Sobrien 517150397Sobrien return offset; 517250397Sobrien} 517350397Sobrien 517450397Sobrien/* Output the DIE and its attributes. Called recursively to generate 517550397Sobrien the definitions of each child DIE. */ 517650397Sobrien 517750397Sobrienstatic void 517850397Sobrienoutput_die (die) 517950397Sobrien register dw_die_ref die; 518050397Sobrien{ 518150397Sobrien register dw_attr_ref a; 518250397Sobrien register dw_die_ref c; 518350397Sobrien register unsigned long ref_offset; 518450397Sobrien register unsigned long size; 518550397Sobrien register dw_loc_descr_ref loc; 518650397Sobrien register int i; 518750397Sobrien 518850397Sobrien output_uleb128 (die->die_abbrev); 518950397Sobrien if (flag_debug_asm) 519050397Sobrien fprintf (asm_out_file, " (DIE (0x%lx) %s)", 519150397Sobrien die->die_offset, dwarf_tag_name (die->die_tag)); 519250397Sobrien 519350397Sobrien fputc ('\n', asm_out_file); 519450397Sobrien 519550397Sobrien for (a = die->die_attr; a != NULL; a = a->dw_attr_next) 519650397Sobrien { 519750397Sobrien switch (a->dw_attr_val.val_class) 519850397Sobrien { 519950397Sobrien case dw_val_class_addr: 520050397Sobrien ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, 520150397Sobrien a->dw_attr_val.v.val_addr); 520250397Sobrien break; 520350397Sobrien 520450397Sobrien case dw_val_class_loc: 520550397Sobrien size = size_of_locs (a->dw_attr_val.v.val_loc); 520650397Sobrien 520750397Sobrien /* Output the block length for this list of location operations. */ 520850397Sobrien switch (constant_size (size)) 520950397Sobrien { 521050397Sobrien case 1: 521150397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size); 521250397Sobrien break; 521350397Sobrien case 2: 521450397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size); 521550397Sobrien break; 521650397Sobrien default: 521750397Sobrien abort (); 521850397Sobrien } 521950397Sobrien 522050397Sobrien if (flag_debug_asm) 522150397Sobrien fprintf (asm_out_file, "\t%s %s", 522250397Sobrien ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); 522350397Sobrien 522450397Sobrien fputc ('\n', asm_out_file); 522550397Sobrien for (loc = a->dw_attr_val.v.val_loc; loc != NULL; 522650397Sobrien loc = loc->dw_loc_next) 522750397Sobrien { 522850397Sobrien /* Output the opcode. */ 522950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc); 523050397Sobrien if (flag_debug_asm) 523150397Sobrien fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, 523250397Sobrien dwarf_stack_op_name (loc->dw_loc_opc)); 523350397Sobrien 523450397Sobrien fputc ('\n', asm_out_file); 523550397Sobrien 523650397Sobrien /* Output the operand(s) (if any). */ 523750397Sobrien output_loc_operands (loc); 523850397Sobrien } 523950397Sobrien break; 524050397Sobrien 524150397Sobrien case dw_val_class_const: 524250397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int); 524350397Sobrien break; 524450397Sobrien 524550397Sobrien case dw_val_class_unsigned_const: 524650397Sobrien switch (constant_size (a->dw_attr_val.v.val_unsigned)) 524750397Sobrien { 524850397Sobrien case 1: 524950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 525050397Sobrien a->dw_attr_val.v.val_unsigned); 525150397Sobrien break; 525250397Sobrien case 2: 525350397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 525450397Sobrien a->dw_attr_val.v.val_unsigned); 525550397Sobrien break; 525650397Sobrien case 4: 525750397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 525850397Sobrien a->dw_attr_val.v.val_unsigned); 525950397Sobrien break; 526050397Sobrien case 8: 526150397Sobrien ASM_OUTPUT_DWARF_DATA8 (asm_out_file, 526250397Sobrien a->dw_attr_val.v.val_long_long.hi, 526350397Sobrien a->dw_attr_val.v.val_long_long.low); 526450397Sobrien break; 526550397Sobrien default: 526650397Sobrien abort (); 526750397Sobrien } 526850397Sobrien break; 526950397Sobrien 527050397Sobrien case dw_val_class_long_long: 527150397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8); 527250397Sobrien if (flag_debug_asm) 527350397Sobrien fprintf (asm_out_file, "\t%s %s", 527450397Sobrien ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); 527550397Sobrien 527650397Sobrien fputc ('\n', asm_out_file); 527750397Sobrien ASM_OUTPUT_DWARF_DATA8 (asm_out_file, 527850397Sobrien a->dw_attr_val.v.val_long_long.hi, 527950397Sobrien a->dw_attr_val.v.val_long_long.low); 528050397Sobrien 528150397Sobrien if (flag_debug_asm) 528250397Sobrien fprintf (asm_out_file, 528350397Sobrien "\t%s long long constant", ASM_COMMENT_START); 528450397Sobrien 528550397Sobrien fputc ('\n', asm_out_file); 528650397Sobrien break; 528750397Sobrien 528850397Sobrien case dw_val_class_float: 528950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 529050397Sobrien a->dw_attr_val.v.val_float.length * 4); 529150397Sobrien if (flag_debug_asm) 529250397Sobrien fprintf (asm_out_file, "\t%s %s", 529350397Sobrien ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); 529450397Sobrien 529550397Sobrien fputc ('\n', asm_out_file); 529650397Sobrien for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i) 529750397Sobrien { 529850397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 529950397Sobrien a->dw_attr_val.v.val_float.array[i]); 530050397Sobrien if (flag_debug_asm) 530150397Sobrien fprintf (asm_out_file, "\t%s fp constant word %d", 530250397Sobrien ASM_COMMENT_START, i); 530350397Sobrien 530450397Sobrien fputc ('\n', asm_out_file); 530550397Sobrien } 530650397Sobrien break; 530750397Sobrien 530850397Sobrien case dw_val_class_flag: 530950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag); 531050397Sobrien break; 531150397Sobrien 531250397Sobrien case dw_val_class_die_ref: 531350397Sobrien if (a->dw_attr_val.v.val_die_ref != NULL) 531450397Sobrien ref_offset = a->dw_attr_val.v.val_die_ref->die_offset; 531550397Sobrien else if (a->dw_attr == DW_AT_sibling) 531650397Sobrien ref_offset = sibling_offset(die); 531750397Sobrien else 531850397Sobrien abort (); 531950397Sobrien 532050397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset); 532150397Sobrien break; 532250397Sobrien 532350397Sobrien case dw_val_class_fde_ref: 532450397Sobrien { 532550397Sobrien char l1[20]; 532650397Sobrien ASM_GENERATE_INTERNAL_LABEL 532750397Sobrien (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2); 532850397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1); 532950397Sobrien fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE); 533050397Sobrien } 533150397Sobrien break; 533250397Sobrien 533350397Sobrien case dw_val_class_lbl_id: 533450397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id); 533550397Sobrien break; 533650397Sobrien 533750397Sobrien case dw_val_class_section_offset: 533850397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, 533950397Sobrien stripattributes 534050397Sobrien (a->dw_attr_val.v.val_section)); 534150397Sobrien break; 534250397Sobrien 534350397Sobrien case dw_val_class_str: 534450397Sobrien if (flag_debug_asm) 534550397Sobrien ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str); 534650397Sobrien else 534750397Sobrien ASM_OUTPUT_ASCII (asm_out_file, 534850397Sobrien a->dw_attr_val.v.val_str, 534950397Sobrien strlen (a->dw_attr_val.v.val_str) + 1); 535050397Sobrien break; 535150397Sobrien 535250397Sobrien default: 535350397Sobrien abort (); 535450397Sobrien } 535550397Sobrien 535650397Sobrien if (a->dw_attr_val.val_class != dw_val_class_loc 535750397Sobrien && a->dw_attr_val.val_class != dw_val_class_long_long 535850397Sobrien && a->dw_attr_val.val_class != dw_val_class_float) 535950397Sobrien { 536050397Sobrien if (flag_debug_asm) 536150397Sobrien fprintf (asm_out_file, "\t%s %s", 536250397Sobrien ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); 536350397Sobrien 536450397Sobrien fputc ('\n', asm_out_file); 536550397Sobrien } 536650397Sobrien } 536750397Sobrien 536850397Sobrien for (c = die->die_child; c != NULL; c = c->die_sib) 536950397Sobrien output_die (c); 537050397Sobrien 537150397Sobrien if (die->die_child != NULL) 537250397Sobrien { 537350397Sobrien /* Add null byte to terminate sibling list. */ 537450397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 537550397Sobrien if (flag_debug_asm) 537650397Sobrien fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx", 537750397Sobrien ASM_COMMENT_START, die->die_offset); 537850397Sobrien 537950397Sobrien fputc ('\n', asm_out_file); 538050397Sobrien } 538150397Sobrien} 538250397Sobrien 538350397Sobrien/* Output the compilation unit that appears at the beginning of the 538450397Sobrien .debug_info section, and precedes the DIE descriptions. */ 538550397Sobrien 538650397Sobrienstatic void 538750397Sobrienoutput_compilation_unit_header () 538850397Sobrien{ 538950397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE); 539050397Sobrien if (flag_debug_asm) 539150397Sobrien fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.", 539250397Sobrien ASM_COMMENT_START); 539350397Sobrien 539450397Sobrien fputc ('\n', asm_out_file); 539550397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); 539650397Sobrien if (flag_debug_asm) 539750397Sobrien fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START); 539850397Sobrien 539950397Sobrien fputc ('\n', asm_out_file); 540050397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION)); 540150397Sobrien if (flag_debug_asm) 540250397Sobrien fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section", 540350397Sobrien ASM_COMMENT_START); 540450397Sobrien 540550397Sobrien fputc ('\n', asm_out_file); 540650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); 540750397Sobrien if (flag_debug_asm) 540850397Sobrien fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START); 540950397Sobrien 541050397Sobrien fputc ('\n', asm_out_file); 541150397Sobrien} 541250397Sobrien 541350397Sobrien/* The DWARF2 pubname for a nested thingy looks like "A::f". The output 541450397Sobrien of decl_printable_name for C++ looks like "A::f(int)". Let's drop the 541550397Sobrien argument list, and maybe the scope. */ 541650397Sobrien 541750397Sobrienstatic char * 541850397Sobriendwarf2_name (decl, scope) 541950397Sobrien tree decl; 542050397Sobrien int scope; 542150397Sobrien{ 542250397Sobrien return (*decl_printable_name) (decl, scope ? 1 : 0); 542350397Sobrien} 542450397Sobrien 542550397Sobrien/* Add a new entry to .debug_pubnames if appropriate. */ 542650397Sobrien 542750397Sobrienstatic void 542850397Sobrienadd_pubname (decl, die) 542950397Sobrien tree decl; 543050397Sobrien dw_die_ref die; 543150397Sobrien{ 543250397Sobrien pubname_ref p; 543350397Sobrien 543450397Sobrien if (! TREE_PUBLIC (decl)) 543550397Sobrien return; 543650397Sobrien 543750397Sobrien if (pubname_table_in_use == pubname_table_allocated) 543850397Sobrien { 543950397Sobrien pubname_table_allocated += PUBNAME_TABLE_INCREMENT; 544050397Sobrien pubname_table = (pubname_ref) xrealloc 544150397Sobrien (pubname_table, pubname_table_allocated * sizeof (pubname_entry)); 544250397Sobrien } 544350397Sobrien 544450397Sobrien p = &pubname_table[pubname_table_in_use++]; 544550397Sobrien p->die = die; 544650397Sobrien 544750397Sobrien p->name = xstrdup (dwarf2_name (decl, 1)); 544850397Sobrien} 544950397Sobrien 545050397Sobrien/* Output the public names table used to speed up access to externally 545150397Sobrien visible names. For now, only generate entries for externally 545250397Sobrien visible procedures. */ 545350397Sobrien 545450397Sobrienstatic void 545550397Sobrienoutput_pubnames () 545650397Sobrien{ 545750397Sobrien register unsigned i; 545850397Sobrien register unsigned long pubnames_length = size_of_pubnames (); 545950397Sobrien 546050397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length); 546150397Sobrien 546250397Sobrien if (flag_debug_asm) 546350397Sobrien fprintf (asm_out_file, "\t%s Length of Public Names Info.", 546450397Sobrien ASM_COMMENT_START); 546550397Sobrien 546650397Sobrien fputc ('\n', asm_out_file); 546750397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); 546850397Sobrien 546950397Sobrien if (flag_debug_asm) 547050397Sobrien fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); 547150397Sobrien 547250397Sobrien fputc ('\n', asm_out_file); 547350397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION)); 547450397Sobrien if (flag_debug_asm) 547550397Sobrien fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", 547650397Sobrien ASM_COMMENT_START); 547750397Sobrien 547850397Sobrien fputc ('\n', asm_out_file); 547950397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset); 548050397Sobrien if (flag_debug_asm) 548150397Sobrien fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START); 548250397Sobrien 548350397Sobrien fputc ('\n', asm_out_file); 548450397Sobrien for (i = 0; i < pubname_table_in_use; ++i) 548550397Sobrien { 548650397Sobrien register pubname_ref pub = &pubname_table[i]; 548750397Sobrien 548850397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset); 548950397Sobrien if (flag_debug_asm) 549050397Sobrien fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START); 549150397Sobrien 549250397Sobrien fputc ('\n', asm_out_file); 549350397Sobrien 549450397Sobrien if (flag_debug_asm) 549550397Sobrien { 549650397Sobrien ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name); 549750397Sobrien fprintf (asm_out_file, "%s external name", ASM_COMMENT_START); 549850397Sobrien } 549950397Sobrien else 550050397Sobrien { 550150397Sobrien ASM_OUTPUT_ASCII (asm_out_file, pub->name, strlen (pub->name) + 1); 550250397Sobrien } 550350397Sobrien 550450397Sobrien fputc ('\n', asm_out_file); 550550397Sobrien } 550650397Sobrien 550750397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, 0); 550850397Sobrien fputc ('\n', asm_out_file); 550950397Sobrien} 551050397Sobrien 551150397Sobrien/* Add a new entry to .debug_aranges if appropriate. */ 551250397Sobrien 551350397Sobrienstatic void 551450397Sobrienadd_arange (decl, die) 551550397Sobrien tree decl; 551650397Sobrien dw_die_ref die; 551750397Sobrien{ 551850397Sobrien if (! DECL_SECTION_NAME (decl)) 551950397Sobrien return; 552050397Sobrien 552150397Sobrien if (arange_table_in_use == arange_table_allocated) 552250397Sobrien { 552350397Sobrien arange_table_allocated += ARANGE_TABLE_INCREMENT; 552450397Sobrien arange_table 552550397Sobrien = (arange_ref) xrealloc (arange_table, 552650397Sobrien arange_table_allocated * sizeof (dw_die_ref)); 552750397Sobrien } 552850397Sobrien 552950397Sobrien arange_table[arange_table_in_use++] = die; 553050397Sobrien} 553150397Sobrien 553250397Sobrien/* Output the information that goes into the .debug_aranges table. 553350397Sobrien Namely, define the beginning and ending address range of the 553450397Sobrien text section generated for this compilation unit. */ 553550397Sobrien 553650397Sobrienstatic void 553750397Sobrienoutput_aranges () 553850397Sobrien{ 553950397Sobrien register unsigned i; 554050397Sobrien register unsigned long aranges_length = size_of_aranges (); 554150397Sobrien 554250397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length); 554350397Sobrien if (flag_debug_asm) 554450397Sobrien fprintf (asm_out_file, "\t%s Length of Address Ranges Info.", 554550397Sobrien ASM_COMMENT_START); 554650397Sobrien 554750397Sobrien fputc ('\n', asm_out_file); 554850397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); 554950397Sobrien if (flag_debug_asm) 555050397Sobrien fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); 555150397Sobrien 555250397Sobrien fputc ('\n', asm_out_file); 555350397Sobrien ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION)); 555450397Sobrien if (flag_debug_asm) 555550397Sobrien fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", 555650397Sobrien ASM_COMMENT_START); 555750397Sobrien 555850397Sobrien fputc ('\n', asm_out_file); 555950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); 556050397Sobrien if (flag_debug_asm) 556150397Sobrien fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START); 556250397Sobrien 556350397Sobrien fputc ('\n', asm_out_file); 556450397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 556550397Sobrien if (flag_debug_asm) 556650397Sobrien fprintf (asm_out_file, "\t%s Size of Segment Descriptor", 556750397Sobrien ASM_COMMENT_START); 556850397Sobrien 556950397Sobrien fputc ('\n', asm_out_file); 557050397Sobrien ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4); 557150397Sobrien if (PTR_SIZE == 8) 557250397Sobrien fprintf (asm_out_file, ",0,0"); 557350397Sobrien 557450397Sobrien if (flag_debug_asm) 557550397Sobrien fprintf (asm_out_file, "\t%s Pad to %d byte boundary", 557650397Sobrien ASM_COMMENT_START, 2 * PTR_SIZE); 557750397Sobrien 557850397Sobrien fputc ('\n', asm_out_file); 557950397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION); 558050397Sobrien if (flag_debug_asm) 558150397Sobrien fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); 558250397Sobrien 558350397Sobrien fputc ('\n', asm_out_file); 558450397Sobrien ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, TEXT_SECTION); 558550397Sobrien if (flag_debug_asm) 558650397Sobrien fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); 558750397Sobrien 558850397Sobrien fputc ('\n', asm_out_file); 558950397Sobrien for (i = 0; i < arange_table_in_use; ++i) 559050397Sobrien { 559150397Sobrien dw_die_ref a = arange_table[i]; 559250397Sobrien 559350397Sobrien if (a->die_tag == DW_TAG_subprogram) 559450397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a)); 559550397Sobrien else 559650397Sobrien { 559750397Sobrien char *name = get_AT_string (a, DW_AT_MIPS_linkage_name); 559850397Sobrien if (! name) 559950397Sobrien name = get_AT_string (a, DW_AT_name); 560050397Sobrien 560150397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, name); 560250397Sobrien } 560350397Sobrien 560450397Sobrien if (flag_debug_asm) 560550397Sobrien fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); 560650397Sobrien 560750397Sobrien fputc ('\n', asm_out_file); 560850397Sobrien if (a->die_tag == DW_TAG_subprogram) 560950397Sobrien ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a), 561050397Sobrien get_AT_low_pc (a)); 561150397Sobrien else 561250397Sobrien ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 561350397Sobrien get_AT_unsigned (a, DW_AT_byte_size)); 561450397Sobrien 561550397Sobrien if (flag_debug_asm) 561650397Sobrien fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); 561750397Sobrien 561850397Sobrien fputc ('\n', asm_out_file); 561950397Sobrien } 562050397Sobrien 562150397Sobrien /* Output the terminator words. */ 562250397Sobrien ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); 562350397Sobrien fputc ('\n', asm_out_file); 562450397Sobrien ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); 562550397Sobrien fputc ('\n', asm_out_file); 562650397Sobrien} 562750397Sobrien 562850397Sobrien/* Output the source line number correspondence information. This 562950397Sobrien information goes into the .debug_line section. 563050397Sobrien 563150397Sobrien If the format of this data changes, then the function size_of_line_info 563250397Sobrien must also be adjusted the same way. */ 563350397Sobrien 563450397Sobrienstatic void 563550397Sobrienoutput_line_info () 563650397Sobrien{ 563750397Sobrien char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; 563850397Sobrien char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES]; 563950397Sobrien register unsigned opc; 564050397Sobrien register unsigned n_op_args; 564150397Sobrien register unsigned long ft_index; 564250397Sobrien register unsigned long lt_index; 564350397Sobrien register unsigned long current_line; 564450397Sobrien register long line_offset; 564550397Sobrien register long line_delta; 564650397Sobrien register unsigned long current_file; 564750397Sobrien register unsigned long function; 564850397Sobrien 564950397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ()); 565050397Sobrien if (flag_debug_asm) 565150397Sobrien fprintf (asm_out_file, "\t%s Length of Source Line Info.", 565250397Sobrien ASM_COMMENT_START); 565350397Sobrien 565450397Sobrien fputc ('\n', asm_out_file); 565550397Sobrien ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); 565650397Sobrien if (flag_debug_asm) 565750397Sobrien fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); 565850397Sobrien 565950397Sobrien fputc ('\n', asm_out_file); 566050397Sobrien ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ()); 566150397Sobrien if (flag_debug_asm) 566250397Sobrien fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START); 566350397Sobrien 566450397Sobrien fputc ('\n', asm_out_file); 566550397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH); 566650397Sobrien if (flag_debug_asm) 566750397Sobrien fprintf (asm_out_file, "\t%s Minimum Instruction Length", 566850397Sobrien ASM_COMMENT_START); 566950397Sobrien 567050397Sobrien fputc ('\n', asm_out_file); 567150397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START); 567250397Sobrien if (flag_debug_asm) 567350397Sobrien fprintf (asm_out_file, "\t%s Default is_stmt_start flag", 567450397Sobrien ASM_COMMENT_START); 567550397Sobrien 567650397Sobrien fputc ('\n', asm_out_file); 567750397Sobrien fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE); 567850397Sobrien if (flag_debug_asm) 567950397Sobrien fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)", 568050397Sobrien ASM_COMMENT_START); 568150397Sobrien 568250397Sobrien fputc ('\n', asm_out_file); 568350397Sobrien fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE); 568450397Sobrien if (flag_debug_asm) 568550397Sobrien fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)", 568650397Sobrien ASM_COMMENT_START); 568750397Sobrien 568850397Sobrien fputc ('\n', asm_out_file); 568950397Sobrien fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE); 569050397Sobrien if (flag_debug_asm) 569150397Sobrien fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START); 569250397Sobrien 569350397Sobrien fputc ('\n', asm_out_file); 569450397Sobrien for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc) 569550397Sobrien { 569650397Sobrien switch (opc) 569750397Sobrien { 569850397Sobrien case DW_LNS_advance_pc: 569950397Sobrien case DW_LNS_advance_line: 570050397Sobrien case DW_LNS_set_file: 570150397Sobrien case DW_LNS_set_column: 570250397Sobrien case DW_LNS_fixed_advance_pc: 570350397Sobrien n_op_args = 1; 570450397Sobrien break; 570550397Sobrien default: 570650397Sobrien n_op_args = 0; 570750397Sobrien break; 570850397Sobrien } 570950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args); 571050397Sobrien if (flag_debug_asm) 571150397Sobrien fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args", 571250397Sobrien ASM_COMMENT_START, opc, n_op_args); 571350397Sobrien fputc ('\n', asm_out_file); 571450397Sobrien } 571550397Sobrien 571650397Sobrien if (flag_debug_asm) 571750397Sobrien fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START); 571850397Sobrien 571950397Sobrien /* Include directory table is empty, at present */ 572050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 572150397Sobrien fputc ('\n', asm_out_file); 572250397Sobrien if (flag_debug_asm) 572350397Sobrien fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START); 572450397Sobrien 572550397Sobrien for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) 572650397Sobrien { 572750397Sobrien if (flag_debug_asm) 572850397Sobrien { 572950397Sobrien ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]); 573050397Sobrien fprintf (asm_out_file, "%s File Entry: 0x%lx", 573150397Sobrien ASM_COMMENT_START, ft_index); 573250397Sobrien } 573350397Sobrien else 573450397Sobrien { 573550397Sobrien ASM_OUTPUT_ASCII (asm_out_file, 573650397Sobrien file_table[ft_index], 573750397Sobrien strlen (file_table[ft_index]) + 1); 573850397Sobrien } 573950397Sobrien 574050397Sobrien fputc ('\n', asm_out_file); 574150397Sobrien 574250397Sobrien /* Include directory index */ 574350397Sobrien output_uleb128 (0); 574450397Sobrien fputc ('\n', asm_out_file); 574550397Sobrien 574650397Sobrien /* Modification time */ 574750397Sobrien output_uleb128 (0); 574850397Sobrien fputc ('\n', asm_out_file); 574950397Sobrien 575050397Sobrien /* File length in bytes */ 575150397Sobrien output_uleb128 (0); 575250397Sobrien fputc ('\n', asm_out_file); 575350397Sobrien } 575450397Sobrien 575550397Sobrien /* Terminate the file name table */ 575650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 575750397Sobrien fputc ('\n', asm_out_file); 575850397Sobrien 575950397Sobrien /* Set the address register to the first location in the text section */ 576050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 576150397Sobrien if (flag_debug_asm) 576250397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); 576350397Sobrien 576450397Sobrien fputc ('\n', asm_out_file); 576550397Sobrien output_uleb128 (1 + PTR_SIZE); 576650397Sobrien fputc ('\n', asm_out_file); 576750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); 576850397Sobrien fputc ('\n', asm_out_file); 576950397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION); 577050397Sobrien fputc ('\n', asm_out_file); 577150397Sobrien 577250397Sobrien /* Generate the line number to PC correspondence table, encoded as 577350397Sobrien a series of state machine operations. */ 577450397Sobrien current_file = 1; 577550397Sobrien current_line = 1; 577650397Sobrien strcpy (prev_line_label, TEXT_SECTION); 577750397Sobrien for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) 577850397Sobrien { 577950397Sobrien register dw_line_info_ref line_info; 578050397Sobrien 578150397Sobrien /* Emit debug info for the address of the current line, choosing 578250397Sobrien the encoding that uses the least amount of space. */ 578350397Sobrien /* ??? Unfortunately, we have little choice here currently, and must 578450397Sobrien always use the most general form. Gcc does not know the address 578550397Sobrien delta itself, so we can't use DW_LNS_advance_pc. There are no known 578650397Sobrien dwarf2 aware assemblers at this time, so we can't use any special 578750397Sobrien pseudo ops that would allow the assembler to optimally encode this for 578850397Sobrien us. Many ports do have length attributes which will give an upper 578950397Sobrien bound on the address range. We could perhaps use length attributes 579050397Sobrien to determine when it is safe to use DW_LNS_fixed_advance_pc. */ 579150397Sobrien ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index); 579250397Sobrien if (0) 579350397Sobrien { 579450397Sobrien /* This can handle deltas up to 0xffff. This takes 3 bytes. */ 579550397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); 579650397Sobrien if (flag_debug_asm) 579750397Sobrien fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", 579850397Sobrien ASM_COMMENT_START); 579950397Sobrien 580050397Sobrien fputc ('\n', asm_out_file); 580150397Sobrien ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label); 580250397Sobrien fputc ('\n', asm_out_file); 580350397Sobrien } 580450397Sobrien else 580550397Sobrien { 580650397Sobrien /* This can handle any delta. This takes 4+PTR_SIZE bytes. */ 580750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 580850397Sobrien if (flag_debug_asm) 580950397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_set_address", 581050397Sobrien ASM_COMMENT_START); 581150397Sobrien fputc ('\n', asm_out_file); 581250397Sobrien output_uleb128 (1 + PTR_SIZE); 581350397Sobrien fputc ('\n', asm_out_file); 581450397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); 581550397Sobrien fputc ('\n', asm_out_file); 581650397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); 581750397Sobrien fputc ('\n', asm_out_file); 581850397Sobrien } 581950397Sobrien strcpy (prev_line_label, line_label); 582050397Sobrien 582150397Sobrien /* Emit debug info for the source file of the current line, if 582250397Sobrien different from the previous line. */ 582350397Sobrien line_info = &line_info_table[lt_index]; 582450397Sobrien if (line_info->dw_file_num != current_file) 582550397Sobrien { 582650397Sobrien current_file = line_info->dw_file_num; 582750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); 582850397Sobrien if (flag_debug_asm) 582950397Sobrien fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); 583050397Sobrien 583150397Sobrien fputc ('\n', asm_out_file); 583250397Sobrien output_uleb128 (current_file); 583350397Sobrien if (flag_debug_asm) 583450397Sobrien fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); 583550397Sobrien 583650397Sobrien fputc ('\n', asm_out_file); 583750397Sobrien } 583850397Sobrien 583950397Sobrien /* Emit debug info for the current line number, choosing the encoding 584050397Sobrien that uses the least amount of space. */ 584150397Sobrien line_offset = line_info->dw_line_num - current_line; 584250397Sobrien line_delta = line_offset - DWARF_LINE_BASE; 584350397Sobrien current_line = line_info->dw_line_num; 584450397Sobrien if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) 584550397Sobrien { 584650397Sobrien /* This can handle deltas from -10 to 234, using the current 584750397Sobrien definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This 584850397Sobrien takes 1 byte. */ 584950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 585050397Sobrien DWARF_LINE_OPCODE_BASE + line_delta); 585150397Sobrien if (flag_debug_asm) 585250397Sobrien fprintf (asm_out_file, 585350397Sobrien "\t%s line %ld", ASM_COMMENT_START, current_line); 585450397Sobrien 585550397Sobrien fputc ('\n', asm_out_file); 585650397Sobrien } 585750397Sobrien else 585850397Sobrien { 585950397Sobrien /* This can handle any delta. This takes at least 4 bytes, depending 586050397Sobrien on the value being encoded. */ 586150397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); 586250397Sobrien if (flag_debug_asm) 586350397Sobrien fprintf (asm_out_file, "\t%s advance to line %ld", 586450397Sobrien ASM_COMMENT_START, current_line); 586550397Sobrien 586650397Sobrien fputc ('\n', asm_out_file); 586750397Sobrien output_sleb128 (line_offset); 586850397Sobrien fputc ('\n', asm_out_file); 586950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); 587050397Sobrien fputc ('\n', asm_out_file); 587150397Sobrien } 587250397Sobrien } 587350397Sobrien 587450397Sobrien /* Emit debug info for the address of the end of the function. */ 587550397Sobrien if (0) 587650397Sobrien { 587750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); 587850397Sobrien if (flag_debug_asm) 587950397Sobrien fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", 588050397Sobrien ASM_COMMENT_START); 588150397Sobrien 588250397Sobrien fputc ('\n', asm_out_file); 588350397Sobrien ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label); 588450397Sobrien fputc ('\n', asm_out_file); 588550397Sobrien } 588650397Sobrien else 588750397Sobrien { 588850397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 588950397Sobrien if (flag_debug_asm) 589050397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); 589150397Sobrien fputc ('\n', asm_out_file); 589250397Sobrien output_uleb128 (1 + PTR_SIZE); 589350397Sobrien fputc ('\n', asm_out_file); 589450397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); 589550397Sobrien fputc ('\n', asm_out_file); 589650397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label); 589750397Sobrien fputc ('\n', asm_out_file); 589850397Sobrien } 589950397Sobrien 590050397Sobrien /* Output the marker for the end of the line number info. */ 590150397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 590250397Sobrien if (flag_debug_asm) 590350397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START); 590450397Sobrien 590550397Sobrien fputc ('\n', asm_out_file); 590650397Sobrien output_uleb128 (1); 590750397Sobrien fputc ('\n', asm_out_file); 590850397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); 590950397Sobrien fputc ('\n', asm_out_file); 591050397Sobrien 591150397Sobrien function = 0; 591250397Sobrien current_file = 1; 591350397Sobrien current_line = 1; 591450397Sobrien for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) 591550397Sobrien { 591650397Sobrien register dw_separate_line_info_ref line_info 591750397Sobrien = &separate_line_info_table[lt_index]; 591850397Sobrien 591950397Sobrien /* Emit debug info for the address of the current line. If this is 592050397Sobrien a new function, or the first line of a function, then we need 592150397Sobrien to handle it differently. */ 592250397Sobrien ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL, 592350397Sobrien lt_index); 592450397Sobrien if (function != line_info->function) 592550397Sobrien { 592650397Sobrien function = line_info->function; 592750397Sobrien 592850397Sobrien /* Set the address register to the first line in the function */ 592950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 593050397Sobrien if (flag_debug_asm) 593150397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_set_address", 593250397Sobrien ASM_COMMENT_START); 593350397Sobrien 593450397Sobrien fputc ('\n', asm_out_file); 593550397Sobrien output_uleb128 (1 + PTR_SIZE); 593650397Sobrien fputc ('\n', asm_out_file); 593750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); 593850397Sobrien fputc ('\n', asm_out_file); 593950397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); 594050397Sobrien fputc ('\n', asm_out_file); 594150397Sobrien } 594250397Sobrien else 594350397Sobrien { 594450397Sobrien /* ??? See the DW_LNS_advance_pc comment above. */ 594550397Sobrien if (0) 594650397Sobrien { 594750397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); 594850397Sobrien if (flag_debug_asm) 594950397Sobrien fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", 595050397Sobrien ASM_COMMENT_START); 595150397Sobrien 595250397Sobrien fputc ('\n', asm_out_file); 595350397Sobrien ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, 595450397Sobrien prev_line_label); 595550397Sobrien fputc ('\n', asm_out_file); 595650397Sobrien } 595750397Sobrien else 595850397Sobrien { 595950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 596050397Sobrien if (flag_debug_asm) 596150397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_set_address", 596250397Sobrien ASM_COMMENT_START); 596350397Sobrien fputc ('\n', asm_out_file); 596450397Sobrien output_uleb128 (1 + PTR_SIZE); 596550397Sobrien fputc ('\n', asm_out_file); 596650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); 596750397Sobrien fputc ('\n', asm_out_file); 596850397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); 596950397Sobrien fputc ('\n', asm_out_file); 597050397Sobrien } 597150397Sobrien } 597250397Sobrien strcpy (prev_line_label, line_label); 597350397Sobrien 597450397Sobrien /* Emit debug info for the source file of the current line, if 597550397Sobrien different from the previous line. */ 597650397Sobrien if (line_info->dw_file_num != current_file) 597750397Sobrien { 597850397Sobrien current_file = line_info->dw_file_num; 597950397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); 598050397Sobrien if (flag_debug_asm) 598150397Sobrien fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); 598250397Sobrien 598350397Sobrien fputc ('\n', asm_out_file); 598450397Sobrien output_uleb128 (current_file); 598550397Sobrien if (flag_debug_asm) 598650397Sobrien fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); 598750397Sobrien 598850397Sobrien fputc ('\n', asm_out_file); 598950397Sobrien } 599050397Sobrien 599150397Sobrien /* Emit debug info for the current line number, choosing the encoding 599250397Sobrien that uses the least amount of space. */ 599350397Sobrien if (line_info->dw_line_num != current_line) 599450397Sobrien { 599550397Sobrien line_offset = line_info->dw_line_num - current_line; 599650397Sobrien line_delta = line_offset - DWARF_LINE_BASE; 599750397Sobrien current_line = line_info->dw_line_num; 599850397Sobrien if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) 599950397Sobrien { 600050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 600150397Sobrien DWARF_LINE_OPCODE_BASE + line_delta); 600250397Sobrien if (flag_debug_asm) 600350397Sobrien fprintf (asm_out_file, 600450397Sobrien "\t%s line %ld", ASM_COMMENT_START, current_line); 600550397Sobrien 600650397Sobrien fputc ('\n', asm_out_file); 600750397Sobrien } 600850397Sobrien else 600950397Sobrien { 601050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); 601150397Sobrien if (flag_debug_asm) 601250397Sobrien fprintf (asm_out_file, "\t%s advance to line %ld", 601350397Sobrien ASM_COMMENT_START, current_line); 601450397Sobrien 601550397Sobrien fputc ('\n', asm_out_file); 601650397Sobrien output_sleb128 (line_offset); 601750397Sobrien fputc ('\n', asm_out_file); 601850397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); 601950397Sobrien fputc ('\n', asm_out_file); 602050397Sobrien } 602150397Sobrien } 602250397Sobrien 602350397Sobrien ++lt_index; 602450397Sobrien 602550397Sobrien /* If we're done with a function, end its sequence. */ 602650397Sobrien if (lt_index == separate_line_info_table_in_use 602750397Sobrien || separate_line_info_table[lt_index].function != function) 602850397Sobrien { 602950397Sobrien current_file = 1; 603050397Sobrien current_line = 1; 603150397Sobrien 603250397Sobrien /* Emit debug info for the address of the end of the function. */ 603350397Sobrien ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function); 603450397Sobrien if (0) 603550397Sobrien { 603650397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); 603750397Sobrien if (flag_debug_asm) 603850397Sobrien fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", 603950397Sobrien ASM_COMMENT_START); 604050397Sobrien 604150397Sobrien fputc ('\n', asm_out_file); 604250397Sobrien ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, 604350397Sobrien prev_line_label); 604450397Sobrien fputc ('\n', asm_out_file); 604550397Sobrien } 604650397Sobrien else 604750397Sobrien { 604850397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 604950397Sobrien if (flag_debug_asm) 605050397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_set_address", 605150397Sobrien ASM_COMMENT_START); 605250397Sobrien fputc ('\n', asm_out_file); 605350397Sobrien output_uleb128 (1 + PTR_SIZE); 605450397Sobrien fputc ('\n', asm_out_file); 605550397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); 605650397Sobrien fputc ('\n', asm_out_file); 605750397Sobrien ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); 605850397Sobrien fputc ('\n', asm_out_file); 605950397Sobrien } 606050397Sobrien 606150397Sobrien /* Output the marker for the end of this sequence. */ 606250397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); 606350397Sobrien if (flag_debug_asm) 606450397Sobrien fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", 606550397Sobrien ASM_COMMENT_START); 606650397Sobrien 606750397Sobrien fputc ('\n', asm_out_file); 606850397Sobrien output_uleb128 (1); 606950397Sobrien fputc ('\n', asm_out_file); 607050397Sobrien ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); 607150397Sobrien fputc ('\n', asm_out_file); 607250397Sobrien } 607350397Sobrien } 607450397Sobrien} 607550397Sobrien 607650397Sobrien/* Given a pointer to a BLOCK node return non-zero if (and only if) the node 607750397Sobrien in question represents the outermost pair of curly braces (i.e. the "body 607850397Sobrien block") of a function or method. 607950397Sobrien 608050397Sobrien For any BLOCK node representing a "body block" of a function or method, the 608150397Sobrien BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which 608250397Sobrien represents the outermost (function) scope for the function or method (i.e. 608350397Sobrien the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of 608450397Sobrien *that* node in turn will point to the relevant FUNCTION_DECL node. */ 608550397Sobrien 608650397Sobrienstatic inline int 608750397Sobrienis_body_block (stmt) 608850397Sobrien register tree stmt; 608950397Sobrien{ 609050397Sobrien if (TREE_CODE (stmt) == BLOCK) 609150397Sobrien { 609250397Sobrien register tree parent = BLOCK_SUPERCONTEXT (stmt); 609350397Sobrien 609450397Sobrien if (TREE_CODE (parent) == BLOCK) 609550397Sobrien { 609650397Sobrien register tree grandparent = BLOCK_SUPERCONTEXT (parent); 609750397Sobrien 609850397Sobrien if (TREE_CODE (grandparent) == FUNCTION_DECL) 609950397Sobrien return 1; 610050397Sobrien } 610150397Sobrien } 610250397Sobrien 610350397Sobrien return 0; 610450397Sobrien} 610550397Sobrien 610650397Sobrien/* Given a pointer to a tree node for some base type, return a pointer to 610750397Sobrien a DIE that describes the given type. 610850397Sobrien 610950397Sobrien This routine must only be called for GCC type nodes that correspond to 611050397Sobrien Dwarf base (fundamental) types. */ 611150397Sobrien 611250397Sobrienstatic dw_die_ref 611350397Sobrienbase_type_die (type) 611450397Sobrien register tree type; 611550397Sobrien{ 611650397Sobrien register dw_die_ref base_type_result; 611750397Sobrien register char *type_name; 611850397Sobrien register enum dwarf_type encoding; 611950397Sobrien register tree name = TYPE_NAME (type); 612050397Sobrien 612150397Sobrien if (TREE_CODE (type) == ERROR_MARK 612250397Sobrien || TREE_CODE (type) == VOID_TYPE) 612350397Sobrien return 0; 612450397Sobrien 612550397Sobrien if (TREE_CODE (name) == TYPE_DECL) 612650397Sobrien name = DECL_NAME (name); 612750397Sobrien type_name = IDENTIFIER_POINTER (name); 612850397Sobrien 612950397Sobrien switch (TREE_CODE (type)) 613050397Sobrien { 613150397Sobrien case INTEGER_TYPE: 613250397Sobrien /* Carefully distinguish the C character types, without messing 613350397Sobrien up if the language is not C. Note that we check only for the names 613450397Sobrien that contain spaces; other names might occur by coincidence in other 613550397Sobrien languages. */ 613650397Sobrien if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE 613750397Sobrien && (type == char_type_node 613850397Sobrien || ! strcmp (type_name, "signed char") 613950397Sobrien || ! strcmp (type_name, "unsigned char")))) 614050397Sobrien { 614150397Sobrien if (TREE_UNSIGNED (type)) 614250397Sobrien encoding = DW_ATE_unsigned; 614350397Sobrien else 614450397Sobrien encoding = DW_ATE_signed; 614550397Sobrien break; 614650397Sobrien } 614750397Sobrien /* else fall through */ 614850397Sobrien 614950397Sobrien case CHAR_TYPE: 615050397Sobrien /* GNU Pascal/Ada CHAR type. Not used in C. */ 615150397Sobrien if (TREE_UNSIGNED (type)) 615250397Sobrien encoding = DW_ATE_unsigned_char; 615350397Sobrien else 615450397Sobrien encoding = DW_ATE_signed_char; 615550397Sobrien break; 615650397Sobrien 615750397Sobrien case REAL_TYPE: 615850397Sobrien encoding = DW_ATE_float; 615950397Sobrien break; 616050397Sobrien 616150397Sobrien case COMPLEX_TYPE: 616250397Sobrien encoding = DW_ATE_complex_float; 616350397Sobrien break; 616450397Sobrien 616550397Sobrien case BOOLEAN_TYPE: 616650397Sobrien /* GNU FORTRAN/Ada/C++ BOOLEAN type. */ 616750397Sobrien encoding = DW_ATE_boolean; 616850397Sobrien break; 616950397Sobrien 617050397Sobrien default: 617150397Sobrien abort (); /* No other TREE_CODEs are Dwarf fundamental types. */ 617250397Sobrien } 617350397Sobrien 617450397Sobrien base_type_result = new_die (DW_TAG_base_type, comp_unit_die); 617550397Sobrien add_AT_string (base_type_result, DW_AT_name, type_name); 617650397Sobrien add_AT_unsigned (base_type_result, DW_AT_byte_size, 617750397Sobrien int_size_in_bytes (type)); 617850397Sobrien add_AT_unsigned (base_type_result, DW_AT_encoding, encoding); 617950397Sobrien 618050397Sobrien return base_type_result; 618150397Sobrien} 618250397Sobrien 618350397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to 618450397Sobrien the Dwarf "root" type for the given input type. The Dwarf "root" type of 618550397Sobrien a given type is generally the same as the given type, except that if the 618650397Sobrien given type is a pointer or reference type, then the root type of the given 618750397Sobrien type is the root type of the "basis" type for the pointer or reference 618850397Sobrien type. (This definition of the "root" type is recursive.) Also, the root 618950397Sobrien type of a `const' qualified type or a `volatile' qualified type is the 619050397Sobrien root type of the given type without the qualifiers. */ 619150397Sobrien 619250397Sobrienstatic tree 619350397Sobrienroot_type (type) 619450397Sobrien register tree type; 619550397Sobrien{ 619650397Sobrien if (TREE_CODE (type) == ERROR_MARK) 619750397Sobrien return error_mark_node; 619850397Sobrien 619950397Sobrien switch (TREE_CODE (type)) 620050397Sobrien { 620150397Sobrien case ERROR_MARK: 620250397Sobrien return error_mark_node; 620350397Sobrien 620450397Sobrien case POINTER_TYPE: 620550397Sobrien case REFERENCE_TYPE: 620650397Sobrien return type_main_variant (root_type (TREE_TYPE (type))); 620750397Sobrien 620850397Sobrien default: 620950397Sobrien return type_main_variant (type); 621050397Sobrien } 621150397Sobrien} 621250397Sobrien 621350397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the 621450397Sobrien given input type is a Dwarf "fundamental" type. Otherwise return null. */ 621550397Sobrien 621650397Sobrienstatic inline int 621750397Sobrienis_base_type (type) 621850397Sobrien register tree type; 621950397Sobrien{ 622050397Sobrien switch (TREE_CODE (type)) 622150397Sobrien { 622250397Sobrien case ERROR_MARK: 622350397Sobrien case VOID_TYPE: 622450397Sobrien case INTEGER_TYPE: 622550397Sobrien case REAL_TYPE: 622650397Sobrien case COMPLEX_TYPE: 622750397Sobrien case BOOLEAN_TYPE: 622850397Sobrien case CHAR_TYPE: 622950397Sobrien return 1; 623050397Sobrien 623150397Sobrien case SET_TYPE: 623250397Sobrien case ARRAY_TYPE: 623350397Sobrien case RECORD_TYPE: 623450397Sobrien case UNION_TYPE: 623550397Sobrien case QUAL_UNION_TYPE: 623650397Sobrien case ENUMERAL_TYPE: 623750397Sobrien case FUNCTION_TYPE: 623850397Sobrien case METHOD_TYPE: 623950397Sobrien case POINTER_TYPE: 624050397Sobrien case REFERENCE_TYPE: 624150397Sobrien case FILE_TYPE: 624250397Sobrien case OFFSET_TYPE: 624350397Sobrien case LANG_TYPE: 624450397Sobrien return 0; 624550397Sobrien 624650397Sobrien default: 624750397Sobrien abort (); 624850397Sobrien } 624950397Sobrien 625050397Sobrien return 0; 625150397Sobrien} 625250397Sobrien 625350397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging 625450397Sobrien entry that chains various modifiers in front of the given type. */ 625550397Sobrien 625650397Sobrienstatic dw_die_ref 625750397Sobrienmodified_type_die (type, is_const_type, is_volatile_type, context_die) 625850397Sobrien register tree type; 625950397Sobrien register int is_const_type; 626050397Sobrien register int is_volatile_type; 626150397Sobrien register dw_die_ref context_die; 626250397Sobrien{ 626350397Sobrien register enum tree_code code = TREE_CODE (type); 626450397Sobrien register dw_die_ref mod_type_die = NULL; 626550397Sobrien register dw_die_ref sub_die = NULL; 626650397Sobrien register tree item_type = NULL; 626750397Sobrien 626850397Sobrien if (code != ERROR_MARK) 626950397Sobrien { 627050397Sobrien type = build_type_variant (type, is_const_type, is_volatile_type); 627150397Sobrien 627250397Sobrien mod_type_die = lookup_type_die (type); 627350397Sobrien if (mod_type_die) 627450397Sobrien return mod_type_die; 627550397Sobrien 627650397Sobrien /* Handle C typedef types. */ 627750397Sobrien if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL 627850397Sobrien && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) 627950397Sobrien { 628050397Sobrien tree dtype = TREE_TYPE (TYPE_NAME (type)); 628150397Sobrien if (type == dtype) 628250397Sobrien { 628350397Sobrien /* For a named type, use the typedef. */ 628450397Sobrien gen_type_die (type, context_die); 628550397Sobrien mod_type_die = lookup_type_die (type); 628650397Sobrien } 628750397Sobrien 628850397Sobrien else if (is_const_type < TYPE_READONLY (dtype) 628950397Sobrien || is_volatile_type < TYPE_VOLATILE (dtype)) 629050397Sobrien /* cv-unqualified version of named type. Just use the unnamed 629150397Sobrien type to which it refers. */ 629250397Sobrien mod_type_die 629350397Sobrien = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), 629450397Sobrien is_const_type, is_volatile_type, 629550397Sobrien context_die); 629650397Sobrien /* Else cv-qualified version of named type; fall through. */ 629750397Sobrien } 629850397Sobrien 629950397Sobrien if (mod_type_die) 630050397Sobrien /* OK */; 630150397Sobrien else if (is_const_type) 630250397Sobrien { 630350397Sobrien mod_type_die = new_die (DW_TAG_const_type, comp_unit_die); 630450397Sobrien sub_die = modified_type_die (type, 0, is_volatile_type, context_die); 630550397Sobrien } 630650397Sobrien else if (is_volatile_type) 630750397Sobrien { 630850397Sobrien mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die); 630950397Sobrien sub_die = modified_type_die (type, 0, 0, context_die); 631050397Sobrien } 631150397Sobrien else if (code == POINTER_TYPE) 631250397Sobrien { 631350397Sobrien mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die); 631450397Sobrien add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); 631550397Sobrien#if 0 631650397Sobrien add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); 631750397Sobrien#endif 631850397Sobrien item_type = TREE_TYPE (type); 631950397Sobrien } 632050397Sobrien else if (code == REFERENCE_TYPE) 632150397Sobrien { 632250397Sobrien mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die); 632350397Sobrien add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); 632450397Sobrien#if 0 632550397Sobrien add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); 632650397Sobrien#endif 632750397Sobrien item_type = TREE_TYPE (type); 632850397Sobrien } 632950397Sobrien else if (is_base_type (type)) 633050397Sobrien mod_type_die = base_type_die (type); 633150397Sobrien else 633250397Sobrien { 633350397Sobrien gen_type_die (type, context_die); 633450397Sobrien 633550397Sobrien /* We have to get the type_main_variant here (and pass that to the 633650397Sobrien `lookup_type_die' routine) because the ..._TYPE node we have 633750397Sobrien might simply be a *copy* of some original type node (where the 633850397Sobrien copy was created to help us keep track of typedef names) and 633950397Sobrien that copy might have a different TYPE_UID from the original 634050397Sobrien ..._TYPE node. */ 634150397Sobrien mod_type_die = lookup_type_die (type_main_variant (type)); 634250397Sobrien if (mod_type_die == NULL) 634350397Sobrien abort (); 634450397Sobrien } 634550397Sobrien } 634650397Sobrien 634750397Sobrien equate_type_number_to_die (type, mod_type_die); 634850397Sobrien if (item_type) 634950397Sobrien /* We must do this after the equate_type_number_to_die call, in case 635050397Sobrien this is a recursive type. This ensures that the modified_type_die 635150397Sobrien recursion will terminate even if the type is recursive. Recursive 635250397Sobrien types are possible in Ada. */ 635350397Sobrien sub_die = modified_type_die (item_type, 635450397Sobrien TYPE_READONLY (item_type), 635550397Sobrien TYPE_VOLATILE (item_type), 635650397Sobrien context_die); 635750397Sobrien 635850397Sobrien if (sub_die != NULL) 635950397Sobrien add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); 636050397Sobrien 636150397Sobrien return mod_type_die; 636250397Sobrien} 636350397Sobrien 636450397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is 636550397Sobrien an enumerated type. */ 636650397Sobrien 636750397Sobrienstatic inline int 636850397Sobrientype_is_enum (type) 636950397Sobrien register tree type; 637050397Sobrien{ 637150397Sobrien return TREE_CODE (type) == ENUMERAL_TYPE; 637250397Sobrien} 637350397Sobrien 637450397Sobrien/* Return a location descriptor that designates a machine register. */ 637550397Sobrien 637650397Sobrienstatic dw_loc_descr_ref 637750397Sobrienreg_loc_descriptor (rtl) 637850397Sobrien register rtx rtl; 637950397Sobrien{ 638050397Sobrien register dw_loc_descr_ref loc_result = NULL; 638150397Sobrien register unsigned reg = reg_number (rtl); 638250397Sobrien 638350397Sobrien if (reg <= 31) 638450397Sobrien loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0); 638550397Sobrien else 638650397Sobrien loc_result = new_loc_descr (DW_OP_regx, reg, 0); 638750397Sobrien 638850397Sobrien return loc_result; 638950397Sobrien} 639050397Sobrien 639150397Sobrien/* Return a location descriptor that designates a base+offset location. */ 639250397Sobrien 639350397Sobrienstatic dw_loc_descr_ref 639450397Sobrienbased_loc_descr (reg, offset) 639550397Sobrien unsigned reg; 639650397Sobrien long int offset; 639750397Sobrien{ 639850397Sobrien register dw_loc_descr_ref loc_result; 639950397Sobrien /* For the "frame base", we use the frame pointer or stack pointer 640050397Sobrien registers, since the RTL for local variables is relative to one of 640150397Sobrien them. */ 640250397Sobrien register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed 640350397Sobrien ? HARD_FRAME_POINTER_REGNUM 640450397Sobrien : STACK_POINTER_REGNUM); 640550397Sobrien 640650397Sobrien if (reg == fp_reg) 640750397Sobrien loc_result = new_loc_descr (DW_OP_fbreg, offset, 0); 640850397Sobrien else if (reg <= 31) 640950397Sobrien loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0); 641050397Sobrien else 641150397Sobrien loc_result = new_loc_descr (DW_OP_bregx, reg, offset); 641250397Sobrien 641350397Sobrien return loc_result; 641450397Sobrien} 641550397Sobrien 641650397Sobrien/* Return true if this RTL expression describes a base+offset calculation. */ 641750397Sobrien 641850397Sobrienstatic inline int 641950397Sobrienis_based_loc (rtl) 642050397Sobrien register rtx rtl; 642150397Sobrien{ 642250397Sobrien return (GET_CODE (rtl) == PLUS 642350397Sobrien && ((GET_CODE (XEXP (rtl, 0)) == REG 642450397Sobrien && GET_CODE (XEXP (rtl, 1)) == CONST_INT))); 642550397Sobrien} 642650397Sobrien 642750397Sobrien/* The following routine converts the RTL for a variable or parameter 642850397Sobrien (resident in memory) into an equivalent Dwarf representation of a 642950397Sobrien mechanism for getting the address of that same variable onto the top of a 643050397Sobrien hypothetical "address evaluation" stack. 643150397Sobrien 643250397Sobrien When creating memory location descriptors, we are effectively transforming 643350397Sobrien the RTL for a memory-resident object into its Dwarf postfix expression 643450397Sobrien equivalent. This routine recursively descends an RTL tree, turning 643550397Sobrien it into Dwarf postfix code as it goes. */ 643650397Sobrien 643750397Sobrienstatic dw_loc_descr_ref 643850397Sobrienmem_loc_descriptor (rtl) 643950397Sobrien register rtx rtl; 644050397Sobrien{ 644150397Sobrien dw_loc_descr_ref mem_loc_result = NULL; 644250397Sobrien /* Note that for a dynamically sized array, the location we will generate a 644350397Sobrien description of here will be the lowest numbered location which is 644450397Sobrien actually within the array. That's *not* necessarily the same as the 644550397Sobrien zeroth element of the array. */ 644650397Sobrien 644750397Sobrien switch (GET_CODE (rtl)) 644850397Sobrien { 644950397Sobrien case SUBREG: 645050397Sobrien /* The case of a subreg may arise when we have a local (register) 645150397Sobrien variable or a formal (register) parameter which doesn't quite fill 645250397Sobrien up an entire register. For now, just assume that it is 645350397Sobrien legitimate to make the Dwarf info refer to the whole register which 645450397Sobrien contains the given subreg. */ 645550397Sobrien rtl = XEXP (rtl, 0); 645650397Sobrien 645750397Sobrien /* ... fall through ... */ 645850397Sobrien 645950397Sobrien case REG: 646050397Sobrien /* Whenever a register number forms a part of the description of the 646150397Sobrien method for calculating the (dynamic) address of a memory resident 646250397Sobrien object, DWARF rules require the register number be referred to as 646350397Sobrien a "base register". This distinction is not based in any way upon 646450397Sobrien what category of register the hardware believes the given register 646550397Sobrien belongs to. This is strictly DWARF terminology we're dealing with 646650397Sobrien here. Note that in cases where the location of a memory-resident 646750397Sobrien data object could be expressed as: OP_ADD (OP_BASEREG (basereg), 646850397Sobrien OP_CONST (0)) the actual DWARF location descriptor that we generate 646950397Sobrien may just be OP_BASEREG (basereg). This may look deceptively like 647050397Sobrien the object in question was allocated to a register (rather than in 647150397Sobrien memory) so DWARF consumers need to be aware of the subtle 647250397Sobrien distinction between OP_REG and OP_BASEREG. */ 647350397Sobrien mem_loc_result = based_loc_descr (reg_number (rtl), 0); 647450397Sobrien break; 647550397Sobrien 647650397Sobrien case MEM: 647750397Sobrien mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0)); 647850397Sobrien add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); 647950397Sobrien break; 648050397Sobrien 648150397Sobrien case CONST: 648250397Sobrien case SYMBOL_REF: 648350397Sobrien mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); 648450397Sobrien mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; 648550397Sobrien mem_loc_result->dw_loc_oprnd1.v.val_addr = addr_to_string (rtl); 648650397Sobrien break; 648750397Sobrien 648850397Sobrien case PLUS: 648950397Sobrien if (is_based_loc (rtl)) 649050397Sobrien mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)), 649150397Sobrien INTVAL (XEXP (rtl, 1))); 649250397Sobrien else 649350397Sobrien { 649450397Sobrien add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); 649550397Sobrien add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); 649650397Sobrien add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); 649750397Sobrien } 649850397Sobrien break; 649950397Sobrien 650050397Sobrien case MULT: 650150397Sobrien /* If a pseudo-reg is optimized away, it is possible for it to 650250397Sobrien be replaced with a MEM containing a multiply. */ 650350397Sobrien add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); 650450397Sobrien add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); 650550397Sobrien add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0)); 650650397Sobrien break; 650750397Sobrien 650850397Sobrien case CONST_INT: 650950397Sobrien mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0); 651050397Sobrien break; 651150397Sobrien 651250397Sobrien default: 651350397Sobrien abort (); 651450397Sobrien } 651550397Sobrien 651650397Sobrien return mem_loc_result; 651750397Sobrien} 651850397Sobrien 651950397Sobrien/* Return a descriptor that describes the concatenation of two locations. 652050397Sobrien This is typically a complex variable. */ 652150397Sobrien 652250397Sobrienstatic dw_loc_descr_ref 652350397Sobrienconcat_loc_descriptor (x0, x1) 652450397Sobrien register rtx x0, x1; 652550397Sobrien{ 652650397Sobrien dw_loc_descr_ref cc_loc_result = NULL; 652750397Sobrien 652850397Sobrien if (!is_pseudo_reg (x0) 652950397Sobrien && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0)))) 653050397Sobrien add_loc_descr (&cc_loc_result, loc_descriptor (x0)); 653150397Sobrien add_loc_descr (&cc_loc_result, 653250397Sobrien new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0)); 653350397Sobrien 653450397Sobrien if (!is_pseudo_reg (x1) 653550397Sobrien && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0)))) 653650397Sobrien add_loc_descr (&cc_loc_result, loc_descriptor (x1)); 653750397Sobrien add_loc_descr (&cc_loc_result, 653850397Sobrien new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0)); 653950397Sobrien 654050397Sobrien return cc_loc_result; 654150397Sobrien} 654250397Sobrien 654350397Sobrien/* Output a proper Dwarf location descriptor for a variable or parameter 654450397Sobrien which is either allocated in a register or in a memory location. For a 654550397Sobrien register, we just generate an OP_REG and the register number. For a 654650397Sobrien memory location we provide a Dwarf postfix expression describing how to 654750397Sobrien generate the (dynamic) address of the object onto the address stack. */ 654850397Sobrien 654950397Sobrienstatic dw_loc_descr_ref 655050397Sobrienloc_descriptor (rtl) 655150397Sobrien register rtx rtl; 655250397Sobrien{ 655350397Sobrien dw_loc_descr_ref loc_result = NULL; 655450397Sobrien switch (GET_CODE (rtl)) 655550397Sobrien { 655650397Sobrien case SUBREG: 655750397Sobrien /* The case of a subreg may arise when we have a local (register) 655850397Sobrien variable or a formal (register) parameter which doesn't quite fill 655950397Sobrien up an entire register. For now, just assume that it is 656050397Sobrien legitimate to make the Dwarf info refer to the whole register which 656150397Sobrien contains the given subreg. */ 656250397Sobrien rtl = XEXP (rtl, 0); 656350397Sobrien 656450397Sobrien /* ... fall through ... */ 656550397Sobrien 656650397Sobrien case REG: 656750397Sobrien loc_result = reg_loc_descriptor (rtl); 656850397Sobrien break; 656950397Sobrien 657050397Sobrien case MEM: 657150397Sobrien loc_result = mem_loc_descriptor (XEXP (rtl, 0)); 657250397Sobrien break; 657350397Sobrien 657450397Sobrien case CONCAT: 657550397Sobrien loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1)); 657650397Sobrien break; 657750397Sobrien 657850397Sobrien default: 657950397Sobrien abort (); 658050397Sobrien } 658150397Sobrien 658250397Sobrien return loc_result; 658350397Sobrien} 658450397Sobrien 658550397Sobrien/* Given an unsigned value, round it up to the lowest multiple of `boundary' 658650397Sobrien which is not less than the value itself. */ 658750397Sobrien 658850397Sobrienstatic inline unsigned 658950397Sobrienceiling (value, boundary) 659050397Sobrien register unsigned value; 659150397Sobrien register unsigned boundary; 659250397Sobrien{ 659350397Sobrien return (((value + boundary - 1) / boundary) * boundary); 659450397Sobrien} 659550397Sobrien 659650397Sobrien/* Given a pointer to what is assumed to be a FIELD_DECL node, return a 659750397Sobrien pointer to the declared type for the relevant field variable, or return 659850397Sobrien `integer_type_node' if the given node turns out to be an 659950397Sobrien ERROR_MARK node. */ 660050397Sobrien 660150397Sobrienstatic inline tree 660250397Sobrienfield_type (decl) 660350397Sobrien register tree decl; 660450397Sobrien{ 660550397Sobrien register tree type; 660650397Sobrien 660750397Sobrien if (TREE_CODE (decl) == ERROR_MARK) 660850397Sobrien return integer_type_node; 660950397Sobrien 661050397Sobrien type = DECL_BIT_FIELD_TYPE (decl); 661150397Sobrien if (type == NULL_TREE) 661250397Sobrien type = TREE_TYPE (decl); 661350397Sobrien 661450397Sobrien return type; 661550397Sobrien} 661650397Sobrien 661750397Sobrien/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE 661850397Sobrien node, return the alignment in bits for the type, or else return 661950397Sobrien BITS_PER_WORD if the node actually turns out to be an 662050397Sobrien ERROR_MARK node. */ 662150397Sobrien 662250397Sobrienstatic inline unsigned 662350397Sobriensimple_type_align_in_bits (type) 662450397Sobrien register tree type; 662550397Sobrien{ 662650397Sobrien return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD; 662750397Sobrien} 662850397Sobrien 662950397Sobrien/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE 663050397Sobrien node, return the size in bits for the type if it is a constant, or else 663150397Sobrien return the alignment for the type if the type's size is not constant, or 663250397Sobrien else return BITS_PER_WORD if the type actually turns out to be an 663350397Sobrien ERROR_MARK node. */ 663450397Sobrien 663550397Sobrienstatic inline unsigned 663650397Sobriensimple_type_size_in_bits (type) 663750397Sobrien register tree type; 663850397Sobrien{ 663950397Sobrien if (TREE_CODE (type) == ERROR_MARK) 664050397Sobrien return BITS_PER_WORD; 664150397Sobrien else 664250397Sobrien { 664350397Sobrien register tree type_size_tree = TYPE_SIZE (type); 664450397Sobrien 664550397Sobrien if (TREE_CODE (type_size_tree) != INTEGER_CST) 664650397Sobrien return TYPE_ALIGN (type); 664750397Sobrien 664850397Sobrien return (unsigned) TREE_INT_CST_LOW (type_size_tree); 664950397Sobrien } 665050397Sobrien} 665150397Sobrien 665250397Sobrien/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and 665350397Sobrien return the byte offset of the lowest addressed byte of the "containing 665450397Sobrien object" for the given FIELD_DECL, or return 0 if we are unable to 665550397Sobrien determine what that offset is, either because the argument turns out to 665650397Sobrien be a pointer to an ERROR_MARK node, or because the offset is actually 665750397Sobrien variable. (We can't handle the latter case just yet). */ 665850397Sobrien 665950397Sobrienstatic unsigned 666050397Sobrienfield_byte_offset (decl) 666150397Sobrien register tree decl; 666250397Sobrien{ 666350397Sobrien register unsigned type_align_in_bytes; 666450397Sobrien register unsigned type_align_in_bits; 666550397Sobrien register unsigned type_size_in_bits; 666650397Sobrien register unsigned object_offset_in_align_units; 666750397Sobrien register unsigned object_offset_in_bits; 666850397Sobrien register unsigned object_offset_in_bytes; 666950397Sobrien register tree type; 667050397Sobrien register tree bitpos_tree; 667150397Sobrien register tree field_size_tree; 667250397Sobrien register unsigned bitpos_int; 667350397Sobrien register unsigned deepest_bitpos; 667450397Sobrien register unsigned field_size_in_bits; 667550397Sobrien 667650397Sobrien if (TREE_CODE (decl) == ERROR_MARK) 667750397Sobrien return 0; 667850397Sobrien 667950397Sobrien if (TREE_CODE (decl) != FIELD_DECL) 668050397Sobrien abort (); 668150397Sobrien 668250397Sobrien type = field_type (decl); 668350397Sobrien 668450397Sobrien bitpos_tree = DECL_FIELD_BITPOS (decl); 668550397Sobrien field_size_tree = DECL_SIZE (decl); 668650397Sobrien 668750397Sobrien /* We cannot yet cope with fields whose positions or sizes are variable, so 668850397Sobrien for now, when we see such things, we simply return 0. Someday, we may 668950397Sobrien be able to handle such cases, but it will be damn difficult. */ 669050397Sobrien if (TREE_CODE (bitpos_tree) != INTEGER_CST) 669150397Sobrien return 0; 669250397Sobrien bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); 669350397Sobrien 669450397Sobrien if (TREE_CODE (field_size_tree) != INTEGER_CST) 669550397Sobrien return 0; 669650397Sobrien 669750397Sobrien field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree); 669850397Sobrien type_size_in_bits = simple_type_size_in_bits (type); 669950397Sobrien type_align_in_bits = simple_type_align_in_bits (type); 670050397Sobrien type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT; 670150397Sobrien 670250397Sobrien /* Note that the GCC front-end doesn't make any attempt to keep track of 670350397Sobrien the starting bit offset (relative to the start of the containing 670450397Sobrien structure type) of the hypothetical "containing object" for a bit- 670550397Sobrien field. Thus, when computing the byte offset value for the start of the 670650397Sobrien "containing object" of a bit-field, we must deduce this information on 670750397Sobrien our own. This can be rather tricky to do in some cases. For example, 670850397Sobrien handling the following structure type definition when compiling for an 670950397Sobrien i386/i486 target (which only aligns long long's to 32-bit boundaries) 671050397Sobrien can be very tricky: 671150397Sobrien 671250397Sobrien struct S { int field1; long long field2:31; }; 671350397Sobrien 671450397Sobrien Fortunately, there is a simple rule-of-thumb which can be 671550397Sobrien used in such cases. When compiling for an i386/i486, GCC will allocate 671650397Sobrien 8 bytes for the structure shown above. It decides to do this based upon 671750397Sobrien one simple rule for bit-field allocation. Quite simply, GCC allocates 671850397Sobrien each "containing object" for each bit-field at the first (i.e. lowest 671950397Sobrien addressed) legitimate alignment boundary (based upon the required 672050397Sobrien minimum alignment for the declared type of the field) which it can 672150397Sobrien possibly use, subject to the condition that there is still enough 672250397Sobrien available space remaining in the containing object (when allocated at 672350397Sobrien the selected point) to fully accommodate all of the bits of the 672450397Sobrien bit-field itself. This simple rule makes it obvious why GCC allocates 672550397Sobrien 8 bytes for each object of the structure type shown above. When looking 672650397Sobrien for a place to allocate the "containing object" for `field2', the 672750397Sobrien compiler simply tries to allocate a 64-bit "containing object" at each 672850397Sobrien successive 32-bit boundary (starting at zero) until it finds a place to 672950397Sobrien allocate that 64- bit field such that at least 31 contiguous (and 673050397Sobrien previously unallocated) bits remain within that selected 64 bit field. 673150397Sobrien (As it turns out, for the example above, the compiler finds that it is 673250397Sobrien OK to allocate the "containing object" 64-bit field at bit-offset zero 673350397Sobrien within the structure type.) Here we attempt to work backwards from the 673450397Sobrien limited set of facts we're given, and we try to deduce from those facts, 673550397Sobrien where GCC must have believed that the containing object started (within 673650397Sobrien the structure type). The value we deduce is then used (by the callers of 673750397Sobrien this routine) to generate DW_AT_location and DW_AT_bit_offset attributes 673850397Sobrien for fields (both bit-fields and, in the case of DW_AT_location, regular 673950397Sobrien fields as well). */ 674050397Sobrien 674150397Sobrien /* Figure out the bit-distance from the start of the structure to the 674250397Sobrien "deepest" bit of the bit-field. */ 674350397Sobrien deepest_bitpos = bitpos_int + field_size_in_bits; 674450397Sobrien 674550397Sobrien /* This is the tricky part. Use some fancy footwork to deduce where the 674650397Sobrien lowest addressed bit of the containing object must be. */ 674750397Sobrien object_offset_in_bits 674850397Sobrien = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits; 674950397Sobrien 675050397Sobrien /* Compute the offset of the containing object in "alignment units". */ 675150397Sobrien object_offset_in_align_units = object_offset_in_bits / type_align_in_bits; 675250397Sobrien 675350397Sobrien /* Compute the offset of the containing object in bytes. */ 675450397Sobrien object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes; 675550397Sobrien 675650397Sobrien return object_offset_in_bytes; 675750397Sobrien} 675850397Sobrien 675950397Sobrien/* The following routines define various Dwarf attributes and any data 676050397Sobrien associated with them. */ 676150397Sobrien 676250397Sobrien/* Add a location description attribute value to a DIE. 676350397Sobrien 676450397Sobrien This emits location attributes suitable for whole variables and 676550397Sobrien whole parameters. Note that the location attributes for struct fields are 676650397Sobrien generated by the routine `data_member_location_attribute' below. */ 676750397Sobrien 676850397Sobrienstatic void 676950397Sobrienadd_AT_location_description (die, attr_kind, rtl) 677050397Sobrien dw_die_ref die; 677150397Sobrien enum dwarf_attribute attr_kind; 677250397Sobrien register rtx rtl; 677350397Sobrien{ 677450397Sobrien /* Handle a special case. If we are about to output a location descriptor 677550397Sobrien for a variable or parameter which has been optimized out of existence, 677650397Sobrien don't do that. A variable which has been optimized out 677750397Sobrien of existence will have a DECL_RTL value which denotes a pseudo-reg. 677850397Sobrien Currently, in some rare cases, variables can have DECL_RTL values which 677950397Sobrien look like (MEM (REG pseudo-reg#)). These cases are due to bugs 678050397Sobrien elsewhere in the compiler. We treat such cases as if the variable(s) in 678150397Sobrien question had been optimized out of existence. */ 678250397Sobrien 678350397Sobrien if (is_pseudo_reg (rtl) 678450397Sobrien || (GET_CODE (rtl) == MEM 678550397Sobrien && is_pseudo_reg (XEXP (rtl, 0))) 678650397Sobrien || (GET_CODE (rtl) == CONCAT 678750397Sobrien && is_pseudo_reg (XEXP (rtl, 0)) 678850397Sobrien && is_pseudo_reg (XEXP (rtl, 1)))) 678950397Sobrien return; 679050397Sobrien 679150397Sobrien add_AT_loc (die, attr_kind, loc_descriptor (rtl)); 679250397Sobrien} 679350397Sobrien 679450397Sobrien/* Attach the specialized form of location attribute used for data 679550397Sobrien members of struct and union types. In the special case of a 679650397Sobrien FIELD_DECL node which represents a bit-field, the "offset" part 679750397Sobrien of this special location descriptor must indicate the distance 679850397Sobrien in bytes from the lowest-addressed byte of the containing struct 679950397Sobrien or union type to the lowest-addressed byte of the "containing 680050397Sobrien object" for the bit-field. (See the `field_byte_offset' function 680150397Sobrien above).. For any given bit-field, the "containing object" is a 680250397Sobrien hypothetical object (of some integral or enum type) within which 680350397Sobrien the given bit-field lives. The type of this hypothetical 680450397Sobrien "containing object" is always the same as the declared type of 680550397Sobrien the individual bit-field itself (for GCC anyway... the DWARF 680650397Sobrien spec doesn't actually mandate this). Note that it is the size 680750397Sobrien (in bytes) of the hypothetical "containing object" which will 680850397Sobrien be given in the DW_AT_byte_size attribute for this bit-field. 680950397Sobrien (See the `byte_size_attribute' function below.) It is also used 681050397Sobrien when calculating the value of the DW_AT_bit_offset attribute. 681150397Sobrien (See the `bit_offset_attribute' function below). */ 681250397Sobrien 681350397Sobrienstatic void 681450397Sobrienadd_data_member_location_attribute (die, decl) 681550397Sobrien register dw_die_ref die; 681650397Sobrien register tree decl; 681750397Sobrien{ 681850397Sobrien register unsigned long offset; 681950397Sobrien register dw_loc_descr_ref loc_descr; 682050397Sobrien register enum dwarf_location_atom op; 682150397Sobrien 682250397Sobrien if (TREE_CODE (decl) == TREE_VEC) 682350397Sobrien offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl)); 682450397Sobrien else 682550397Sobrien offset = field_byte_offset (decl); 682650397Sobrien 682750397Sobrien /* The DWARF2 standard says that we should assume that the structure address 682850397Sobrien is already on the stack, so we can specify a structure field address 682950397Sobrien by using DW_OP_plus_uconst. */ 683050397Sobrien 683150397Sobrien#ifdef MIPS_DEBUGGING_INFO 683250397Sobrien /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator 683350397Sobrien correctly. It works only if we leave the offset on the stack. */ 683450397Sobrien op = DW_OP_constu; 683550397Sobrien#else 683650397Sobrien op = DW_OP_plus_uconst; 683750397Sobrien#endif 683850397Sobrien 683950397Sobrien loc_descr = new_loc_descr (op, offset, 0); 684050397Sobrien add_AT_loc (die, DW_AT_data_member_location, loc_descr); 684150397Sobrien} 684250397Sobrien 684350397Sobrien/* Attach an DW_AT_const_value attribute for a variable or a parameter which 684450397Sobrien does not have a "location" either in memory or in a register. These 684550397Sobrien things can arise in GNU C when a constant is passed as an actual parameter 684650397Sobrien to an inlined function. They can also arise in C++ where declared 684750397Sobrien constants do not necessarily get memory "homes". */ 684850397Sobrien 684950397Sobrienstatic void 685050397Sobrienadd_const_value_attribute (die, rtl) 685150397Sobrien register dw_die_ref die; 685250397Sobrien register rtx rtl; 685350397Sobrien{ 685450397Sobrien switch (GET_CODE (rtl)) 685550397Sobrien { 685650397Sobrien case CONST_INT: 685750397Sobrien /* Note that a CONST_INT rtx could represent either an integer or a 685850397Sobrien floating-point constant. A CONST_INT is used whenever the constant 685950397Sobrien will fit into a single word. In all such cases, the original mode 686050397Sobrien of the constant value is wiped out, and the CONST_INT rtx is 686150397Sobrien assigned VOIDmode. */ 686250397Sobrien add_AT_unsigned (die, DW_AT_const_value, (unsigned) INTVAL (rtl)); 686350397Sobrien break; 686450397Sobrien 686550397Sobrien case CONST_DOUBLE: 686650397Sobrien /* Note that a CONST_DOUBLE rtx could represent either an integer or a 686750397Sobrien floating-point constant. A CONST_DOUBLE is used whenever the 686850397Sobrien constant requires more than one word in order to be adequately 686950397Sobrien represented. We output CONST_DOUBLEs as blocks. */ 687050397Sobrien { 687150397Sobrien register enum machine_mode mode = GET_MODE (rtl); 687250397Sobrien 687350397Sobrien if (GET_MODE_CLASS (mode) == MODE_FLOAT) 687450397Sobrien { 687550397Sobrien register unsigned length = GET_MODE_SIZE (mode) / sizeof (long); 687650397Sobrien long array[4]; 687750397Sobrien REAL_VALUE_TYPE rv; 687850397Sobrien 687950397Sobrien REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl); 688050397Sobrien switch (mode) 688150397Sobrien { 688250397Sobrien case SFmode: 688350397Sobrien REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]); 688450397Sobrien break; 688550397Sobrien 688650397Sobrien case DFmode: 688750397Sobrien REAL_VALUE_TO_TARGET_DOUBLE (rv, array); 688850397Sobrien break; 688950397Sobrien 689050397Sobrien case XFmode: 689150397Sobrien case TFmode: 689250397Sobrien REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array); 689350397Sobrien break; 689450397Sobrien 689550397Sobrien default: 689650397Sobrien abort (); 689750397Sobrien } 689850397Sobrien 689950397Sobrien add_AT_float (die, DW_AT_const_value, length, array); 690050397Sobrien } 690150397Sobrien else 690250397Sobrien add_AT_long_long (die, DW_AT_const_value, 690350397Sobrien CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); 690450397Sobrien } 690550397Sobrien break; 690650397Sobrien 690750397Sobrien case CONST_STRING: 690850397Sobrien add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0)); 690950397Sobrien break; 691050397Sobrien 691150397Sobrien case SYMBOL_REF: 691250397Sobrien case LABEL_REF: 691350397Sobrien case CONST: 691450397Sobrien add_AT_addr (die, DW_AT_const_value, addr_to_string (rtl)); 691550397Sobrien break; 691650397Sobrien 691750397Sobrien case PLUS: 691850397Sobrien /* In cases where an inlined instance of an inline function is passed 691950397Sobrien the address of an `auto' variable (which is local to the caller) we 692050397Sobrien can get a situation where the DECL_RTL of the artificial local 692150397Sobrien variable (for the inlining) which acts as a stand-in for the 692250397Sobrien corresponding formal parameter (of the inline function) will look 692350397Sobrien like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not 692450397Sobrien exactly a compile-time constant expression, but it isn't the address 692550397Sobrien of the (artificial) local variable either. Rather, it represents the 692650397Sobrien *value* which the artificial local variable always has during its 692750397Sobrien lifetime. We currently have no way to represent such quasi-constant 692850397Sobrien values in Dwarf, so for now we just punt and generate nothing. */ 692950397Sobrien break; 693050397Sobrien 693150397Sobrien default: 693250397Sobrien /* No other kinds of rtx should be possible here. */ 693350397Sobrien abort (); 693450397Sobrien } 693550397Sobrien 693650397Sobrien} 693750397Sobrien 693850397Sobrien/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value 693950397Sobrien data attribute for a variable or a parameter. We generate the 694050397Sobrien DW_AT_const_value attribute only in those cases where the given variable 694150397Sobrien or parameter does not have a true "location" either in memory or in a 694250397Sobrien register. This can happen (for example) when a constant is passed as an 694350397Sobrien actual argument in a call to an inline function. (It's possible that 694450397Sobrien these things can crop up in other ways also.) Note that one type of 694550397Sobrien constant value which can be passed into an inlined function is a constant 694650397Sobrien pointer. This can happen for example if an actual argument in an inlined 694750397Sobrien function call evaluates to a compile-time constant address. */ 694850397Sobrien 694950397Sobrienstatic void 695050397Sobrienadd_location_or_const_value_attribute (die, decl) 695150397Sobrien register dw_die_ref die; 695250397Sobrien register tree decl; 695350397Sobrien{ 695450397Sobrien register rtx rtl; 695550397Sobrien register tree declared_type; 695650397Sobrien register tree passed_type; 695750397Sobrien 695850397Sobrien if (TREE_CODE (decl) == ERROR_MARK) 695950397Sobrien return; 696050397Sobrien 696150397Sobrien if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL) 696250397Sobrien abort (); 696350397Sobrien 696450397Sobrien /* Here we have to decide where we are going to say the parameter "lives" 696550397Sobrien (as far as the debugger is concerned). We only have a couple of 696650397Sobrien choices. GCC provides us with DECL_RTL and with DECL_INCOMING_RTL. 696750397Sobrien 696850397Sobrien DECL_RTL normally indicates where the parameter lives during most of the 696950397Sobrien activation of the function. If optimization is enabled however, this 697050397Sobrien could be either NULL or else a pseudo-reg. Both of those cases indicate 697150397Sobrien that the parameter doesn't really live anywhere (as far as the code 697250397Sobrien generation parts of GCC are concerned) during most of the function's 697350397Sobrien activation. That will happen (for example) if the parameter is never 697450397Sobrien referenced within the function. 697550397Sobrien 697650397Sobrien We could just generate a location descriptor here for all non-NULL 697750397Sobrien non-pseudo values of DECL_RTL and ignore all of the rest, but we can be 697850397Sobrien a little nicer than that if we also consider DECL_INCOMING_RTL in cases 697950397Sobrien where DECL_RTL is NULL or is a pseudo-reg. 698050397Sobrien 698150397Sobrien Note however that we can only get away with using DECL_INCOMING_RTL as 698250397Sobrien a backup substitute for DECL_RTL in certain limited cases. In cases 698350397Sobrien where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl), 698450397Sobrien we can be sure that the parameter was passed using the same type as it is 698550397Sobrien declared to have within the function, and that its DECL_INCOMING_RTL 698650397Sobrien points us to a place where a value of that type is passed. 698750397Sobrien 698850397Sobrien In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different, 698950397Sobrien we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL 699050397Sobrien because in these cases DECL_INCOMING_RTL points us to a value of some 699150397Sobrien type which is *different* from the type of the parameter itself. Thus, 699250397Sobrien if we tried to use DECL_INCOMING_RTL to generate a location attribute in 699350397Sobrien such cases, the debugger would end up (for example) trying to fetch a 699450397Sobrien `float' from a place which actually contains the first part of a 699550397Sobrien `double'. That would lead to really incorrect and confusing 699650397Sobrien output at debug-time. 699750397Sobrien 699850397Sobrien So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL 699950397Sobrien in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl). There 700050397Sobrien are a couple of exceptions however. On little-endian machines we can 700150397Sobrien get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is 700250397Sobrien not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is 700350397Sobrien an integral type that is smaller than TREE_TYPE (decl). These cases arise 700450397Sobrien when (on a little-endian machine) a non-prototyped function has a 700550397Sobrien parameter declared to be of type `short' or `char'. In such cases, 700650397Sobrien TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will 700750397Sobrien be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the 700850397Sobrien passed `int' value. If the debugger then uses that address to fetch 700950397Sobrien a `short' or a `char' (on a little-endian machine) the result will be 701050397Sobrien the correct data, so we allow for such exceptional cases below. 701150397Sobrien 701250397Sobrien Note that our goal here is to describe the place where the given formal 701350397Sobrien parameter lives during most of the function's activation (i.e. between 701450397Sobrien the end of the prologue and the start of the epilogue). We'll do that 701550397Sobrien as best as we can. Note however that if the given formal parameter is 701650397Sobrien modified sometime during the execution of the function, then a stack 701750397Sobrien backtrace (at debug-time) will show the function as having been 701850397Sobrien called with the *new* value rather than the value which was 701950397Sobrien originally passed in. This happens rarely enough that it is not 702050397Sobrien a major problem, but it *is* a problem, and I'd like to fix it. 702150397Sobrien 702250397Sobrien A future version of dwarf2out.c may generate two additional 702350397Sobrien attributes for any given DW_TAG_formal_parameter DIE which will 702450397Sobrien describe the "passed type" and the "passed location" for the 702550397Sobrien given formal parameter in addition to the attributes we now 702650397Sobrien generate to indicate the "declared type" and the "active 702750397Sobrien location" for each parameter. This additional set of attributes 702850397Sobrien could be used by debuggers for stack backtraces. Separately, note 702950397Sobrien that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be 703050397Sobrien NULL also. This happens (for example) for inlined-instances of 703150397Sobrien inline function formal parameters which are never referenced. 703250397Sobrien This really shouldn't be happening. All PARM_DECL nodes should 703350397Sobrien get valid non-NULL DECL_INCOMING_RTL values, but integrate.c 703450397Sobrien doesn't currently generate these values for inlined instances of 703550397Sobrien inline function parameters, so when we see such cases, we are 703650397Sobrien just out-of-luck for the time being (until integrate.c 703750397Sobrien gets fixed). */ 703850397Sobrien 703950397Sobrien /* Use DECL_RTL as the "location" unless we find something better. */ 704050397Sobrien rtl = DECL_RTL (decl); 704150397Sobrien 704250397Sobrien if (TREE_CODE (decl) == PARM_DECL) 704350397Sobrien { 704450397Sobrien if (rtl == NULL_RTX || is_pseudo_reg (rtl)) 704550397Sobrien { 704650397Sobrien declared_type = type_main_variant (TREE_TYPE (decl)); 704750397Sobrien passed_type = type_main_variant (DECL_ARG_TYPE (decl)); 704850397Sobrien 704950397Sobrien /* This decl represents a formal parameter which was optimized out. 705050397Sobrien Note that DECL_INCOMING_RTL may be NULL in here, but we handle 705150397Sobrien all* cases where (rtl == NULL_RTX) just below. */ 705250397Sobrien if (declared_type == passed_type) 705350397Sobrien rtl = DECL_INCOMING_RTL (decl); 705450397Sobrien else if (! BYTES_BIG_ENDIAN 705550397Sobrien && TREE_CODE (declared_type) == INTEGER_TYPE 705650397Sobrien && TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type)) 705750397Sobrien rtl = DECL_INCOMING_RTL (decl); 705850397Sobrien } 705950397Sobrien } 706050397Sobrien 706150397Sobrien if (rtl == NULL_RTX) 706250397Sobrien return; 706350397Sobrien 706450397Sobrien rtl = eliminate_regs (rtl, 0, NULL_RTX); 706550397Sobrien#ifdef LEAF_REG_REMAP 706650397Sobrien if (leaf_function) 706750397Sobrien leaf_renumber_regs_insn (rtl); 706850397Sobrien#endif 706950397Sobrien 707050397Sobrien switch (GET_CODE (rtl)) 707150397Sobrien { 707250397Sobrien case ADDRESSOF: 707350397Sobrien /* The address of a variable that was optimized away; don't emit 707450397Sobrien anything. */ 707550397Sobrien break; 707650397Sobrien 707750397Sobrien case CONST_INT: 707850397Sobrien case CONST_DOUBLE: 707950397Sobrien case CONST_STRING: 708050397Sobrien case SYMBOL_REF: 708150397Sobrien case LABEL_REF: 708250397Sobrien case CONST: 708350397Sobrien case PLUS: 708450397Sobrien /* DECL_RTL could be (plus (reg ...) (const_int ...)) */ 708550397Sobrien add_const_value_attribute (die, rtl); 708650397Sobrien break; 708750397Sobrien 708850397Sobrien case MEM: 708950397Sobrien case REG: 709050397Sobrien case SUBREG: 709150397Sobrien case CONCAT: 709250397Sobrien add_AT_location_description (die, DW_AT_location, rtl); 709350397Sobrien break; 709450397Sobrien 709550397Sobrien default: 709650397Sobrien abort (); 709750397Sobrien } 709850397Sobrien} 709950397Sobrien 710050397Sobrien/* Generate an DW_AT_name attribute given some string value to be included as 710150397Sobrien the value of the attribute. */ 710250397Sobrien 710350397Sobrienstatic inline void 710450397Sobrienadd_name_attribute (die, name_string) 710550397Sobrien register dw_die_ref die; 710650397Sobrien register char *name_string; 710750397Sobrien{ 710850397Sobrien if (name_string != NULL && *name_string != 0) 710950397Sobrien add_AT_string (die, DW_AT_name, name_string); 711050397Sobrien} 711150397Sobrien 711250397Sobrien/* Given a tree node describing an array bound (either lower or upper) output 711350397Sobrien a representation for that bound. */ 711450397Sobrien 711550397Sobrienstatic void 711650397Sobrienadd_bound_info (subrange_die, bound_attr, bound) 711750397Sobrien register dw_die_ref subrange_die; 711850397Sobrien register enum dwarf_attribute bound_attr; 711950397Sobrien register tree bound; 712050397Sobrien{ 712150397Sobrien register unsigned bound_value = 0; 712250397Sobrien 712350397Sobrien /* If this is an Ada unconstrained array type, then don't emit any debug 712450397Sobrien info because the array bounds are unknown. They are parameterized when 712550397Sobrien the type is instantiated. */ 712650397Sobrien if (contains_placeholder_p (bound)) 712750397Sobrien return; 712850397Sobrien 712950397Sobrien switch (TREE_CODE (bound)) 713050397Sobrien { 713150397Sobrien case ERROR_MARK: 713250397Sobrien return; 713350397Sobrien 713450397Sobrien /* All fixed-bounds are represented by INTEGER_CST nodes. */ 713550397Sobrien case INTEGER_CST: 713650397Sobrien bound_value = TREE_INT_CST_LOW (bound); 713750397Sobrien if (bound_attr == DW_AT_lower_bound 713850397Sobrien && ((is_c_family () && bound_value == 0) 713950397Sobrien || (is_fortran () && bound_value == 1))) 714050397Sobrien /* use the default */; 714150397Sobrien else 714250397Sobrien add_AT_unsigned (subrange_die, bound_attr, bound_value); 714350397Sobrien break; 714450397Sobrien 714550397Sobrien case CONVERT_EXPR: 714650397Sobrien case NOP_EXPR: 714750397Sobrien case NON_LVALUE_EXPR: 714850397Sobrien add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0)); 714950397Sobrien break; 715050397Sobrien 715150397Sobrien case SAVE_EXPR: 715250397Sobrien /* If optimization is turned on, the SAVE_EXPRs that describe how to 715350397Sobrien access the upper bound values may be bogus. If they refer to a 715450397Sobrien register, they may only describe how to get at these values at the 715550397Sobrien points in the generated code right after they have just been 715650397Sobrien computed. Worse yet, in the typical case, the upper bound values 715750397Sobrien will not even *be* computed in the optimized code (though the 715850397Sobrien number of elements will), so these SAVE_EXPRs are entirely 715950397Sobrien bogus. In order to compensate for this fact, we check here to see 716050397Sobrien if optimization is enabled, and if so, we don't add an attribute 716150397Sobrien for the (unknown and unknowable) upper bound. This should not 716250397Sobrien cause too much trouble for existing (stupid?) debuggers because 716350397Sobrien they have to deal with empty upper bounds location descriptions 716450397Sobrien anyway in order to be able to deal with incomplete array types. 716550397Sobrien Of course an intelligent debugger (GDB?) should be able to 716650397Sobrien comprehend that a missing upper bound specification in a array 716750397Sobrien type used for a storage class `auto' local array variable 716850397Sobrien indicates that the upper bound is both unknown (at compile- time) 716950397Sobrien and unknowable (at run-time) due to optimization. 717050397Sobrien 717150397Sobrien We assume that a MEM rtx is safe because gcc wouldn't put the 717250397Sobrien value there unless it was going to be used repeatedly in the 717350397Sobrien function, i.e. for cleanups. */ 717450397Sobrien if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM) 717550397Sobrien { 717650397Sobrien register dw_die_ref ctx = lookup_decl_die (current_function_decl); 717750397Sobrien register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx); 717850397Sobrien register rtx loc = SAVE_EXPR_RTL (bound); 717950397Sobrien 718050397Sobrien /* If the RTL for the SAVE_EXPR is memory, handle the case where 718150397Sobrien it references an outer function's frame. */ 718250397Sobrien 718350397Sobrien if (GET_CODE (loc) == MEM) 718450397Sobrien { 718550397Sobrien rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound); 718650397Sobrien 718750397Sobrien if (XEXP (loc, 0) != new_addr) 718850397Sobrien loc = gen_rtx (MEM, GET_MODE (loc), new_addr); 718950397Sobrien } 719050397Sobrien 719150397Sobrien add_AT_flag (decl_die, DW_AT_artificial, 1); 719250397Sobrien add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); 719350397Sobrien add_AT_location_description (decl_die, DW_AT_location, loc); 719450397Sobrien add_AT_die_ref (subrange_die, bound_attr, decl_die); 719550397Sobrien } 719650397Sobrien 719750397Sobrien /* Else leave out the attribute. */ 719850397Sobrien break; 719950397Sobrien 720050397Sobrien case MAX_EXPR: 720150397Sobrien case VAR_DECL: 720250397Sobrien case COMPONENT_REF: 720350397Sobrien /* ??? These types of bounds can be created by the Ada front end, 720450397Sobrien and it isn't clear how to emit debug info for them. */ 720550397Sobrien break; 720650397Sobrien 720750397Sobrien default: 720850397Sobrien abort (); 720950397Sobrien } 721050397Sobrien} 721150397Sobrien 721250397Sobrien/* Note that the block of subscript information for an array type also 721350397Sobrien includes information about the element type of type given array type. */ 721450397Sobrien 721550397Sobrienstatic void 721650397Sobrienadd_subscript_info (type_die, type) 721750397Sobrien register dw_die_ref type_die; 721850397Sobrien register tree type; 721950397Sobrien{ 722050397Sobrien#ifndef MIPS_DEBUGGING_INFO 722150397Sobrien register unsigned dimension_number; 722250397Sobrien#endif 722350397Sobrien register tree lower, upper; 722450397Sobrien register dw_die_ref subrange_die; 722550397Sobrien 722650397Sobrien /* The GNU compilers represent multidimensional array types as sequences of 722750397Sobrien one dimensional array types whose element types are themselves array 722850397Sobrien types. Here we squish that down, so that each multidimensional array 722950397Sobrien type gets only one array_type DIE in the Dwarf debugging info. The draft 723050397Sobrien Dwarf specification say that we are allowed to do this kind of 723150397Sobrien compression in C (because there is no difference between an array or 723250397Sobrien arrays and a multidimensional array in C) but for other source languages 723350397Sobrien (e.g. Ada) we probably shouldn't do this. */ 723450397Sobrien 723550397Sobrien /* ??? The SGI dwarf reader fails for multidimensional arrays with a 723650397Sobrien const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. 723750397Sobrien We work around this by disabling this feature. See also 723850397Sobrien gen_array_type_die. */ 723950397Sobrien#ifndef MIPS_DEBUGGING_INFO 724050397Sobrien for (dimension_number = 0; 724150397Sobrien TREE_CODE (type) == ARRAY_TYPE; 724250397Sobrien type = TREE_TYPE (type), dimension_number++) 724350397Sobrien { 724450397Sobrien#endif 724550397Sobrien register tree domain = TYPE_DOMAIN (type); 724650397Sobrien 724750397Sobrien /* Arrays come in three flavors: Unspecified bounds, fixed bounds, 724850397Sobrien and (in GNU C only) variable bounds. Handle all three forms 724950397Sobrien here. */ 725050397Sobrien subrange_die = new_die (DW_TAG_subrange_type, type_die); 725150397Sobrien if (domain) 725250397Sobrien { 725350397Sobrien /* We have an array type with specified bounds. */ 725450397Sobrien lower = TYPE_MIN_VALUE (domain); 725550397Sobrien upper = TYPE_MAX_VALUE (domain); 725650397Sobrien 725750397Sobrien /* define the index type. */ 725850397Sobrien if (TREE_TYPE (domain)) 725950397Sobrien { 726050397Sobrien /* ??? This is probably an Ada unnamed subrange type. Ignore the 726150397Sobrien TREE_TYPE field. We can't emit debug info for this 726250397Sobrien because it is an unnamed integral type. */ 726350397Sobrien if (TREE_CODE (domain) == INTEGER_TYPE 726450397Sobrien && TYPE_NAME (domain) == NULL_TREE 726550397Sobrien && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE 726650397Sobrien && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE) 726750397Sobrien ; 726850397Sobrien else 726950397Sobrien add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0, 727050397Sobrien type_die); 727150397Sobrien } 727250397Sobrien 727350397Sobrien /* ??? If upper is NULL, the array has unspecified length, 727450397Sobrien but it does have a lower bound. This happens with Fortran 727550397Sobrien dimension arr(N:*) 727650397Sobrien Since the debugger is definitely going to need to know N 727750397Sobrien to produce useful results, go ahead and output the lower 727850397Sobrien bound solo, and hope the debugger can cope. */ 727950397Sobrien 728050397Sobrien add_bound_info (subrange_die, DW_AT_lower_bound, lower); 728150397Sobrien if (upper) 728250397Sobrien add_bound_info (subrange_die, DW_AT_upper_bound, upper); 728350397Sobrien } 728450397Sobrien else 728550397Sobrien /* We have an array type with an unspecified length. The DWARF-2 728650397Sobrien spec does not say how to handle this; let's just leave out the 728750397Sobrien bounds. */ 728850397Sobrien {;} 728950397Sobrien 729050397Sobrien 729150397Sobrien#ifndef MIPS_DEBUGGING_INFO 729250397Sobrien } 729350397Sobrien#endif 729450397Sobrien} 729550397Sobrien 729650397Sobrienstatic void 729750397Sobrienadd_byte_size_attribute (die, tree_node) 729850397Sobrien dw_die_ref die; 729950397Sobrien register tree tree_node; 730050397Sobrien{ 730150397Sobrien register unsigned size; 730250397Sobrien 730350397Sobrien switch (TREE_CODE (tree_node)) 730450397Sobrien { 730550397Sobrien case ERROR_MARK: 730650397Sobrien size = 0; 730750397Sobrien break; 730850397Sobrien case ENUMERAL_TYPE: 730950397Sobrien case RECORD_TYPE: 731050397Sobrien case UNION_TYPE: 731150397Sobrien case QUAL_UNION_TYPE: 731250397Sobrien size = int_size_in_bytes (tree_node); 731350397Sobrien break; 731450397Sobrien case FIELD_DECL: 731550397Sobrien /* For a data member of a struct or union, the DW_AT_byte_size is 731650397Sobrien generally given as the number of bytes normally allocated for an 731750397Sobrien object of the *declared* type of the member itself. This is true 731850397Sobrien even for bit-fields. */ 731950397Sobrien size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT; 732050397Sobrien break; 732150397Sobrien default: 732250397Sobrien abort (); 732350397Sobrien } 732450397Sobrien 732550397Sobrien /* Note that `size' might be -1 when we get to this point. If it is, that 732650397Sobrien indicates that the byte size of the entity in question is variable. We 732750397Sobrien have no good way of expressing this fact in Dwarf at the present time, 732850397Sobrien so just let the -1 pass on through. */ 732950397Sobrien 733050397Sobrien add_AT_unsigned (die, DW_AT_byte_size, size); 733150397Sobrien} 733250397Sobrien 733350397Sobrien/* For a FIELD_DECL node which represents a bit-field, output an attribute 733450397Sobrien which specifies the distance in bits from the highest order bit of the 733550397Sobrien "containing object" for the bit-field to the highest order bit of the 733650397Sobrien bit-field itself. 733750397Sobrien 733850397Sobrien For any given bit-field, the "containing object" is a hypothetical 733950397Sobrien object (of some integral or enum type) within which the given bit-field 734050397Sobrien lives. The type of this hypothetical "containing object" is always the 734150397Sobrien same as the declared type of the individual bit-field itself. The 734250397Sobrien determination of the exact location of the "containing object" for a 734350397Sobrien bit-field is rather complicated. It's handled by the 734450397Sobrien `field_byte_offset' function (above). 734550397Sobrien 734650397Sobrien Note that it is the size (in bytes) of the hypothetical "containing object" 734750397Sobrien which will be given in the DW_AT_byte_size attribute for this bit-field. 734850397Sobrien (See `byte_size_attribute' above). */ 734950397Sobrien 735050397Sobrienstatic inline void 735150397Sobrienadd_bit_offset_attribute (die, decl) 735250397Sobrien register dw_die_ref die; 735350397Sobrien register tree decl; 735450397Sobrien{ 735550397Sobrien register unsigned object_offset_in_bytes = field_byte_offset (decl); 735650397Sobrien register tree type = DECL_BIT_FIELD_TYPE (decl); 735750397Sobrien register tree bitpos_tree = DECL_FIELD_BITPOS (decl); 735850397Sobrien register unsigned bitpos_int; 735950397Sobrien register unsigned highest_order_object_bit_offset; 736050397Sobrien register unsigned highest_order_field_bit_offset; 736150397Sobrien register unsigned bit_offset; 736250397Sobrien 736350397Sobrien /* Must be a field and a bit field. */ 736450397Sobrien if (!type 736550397Sobrien || TREE_CODE (decl) != FIELD_DECL) 736650397Sobrien abort (); 736750397Sobrien 736850397Sobrien /* We can't yet handle bit-fields whose offsets are variable, so if we 736950397Sobrien encounter such things, just return without generating any attribute 737050397Sobrien whatsoever. */ 737150397Sobrien if (TREE_CODE (bitpos_tree) != INTEGER_CST) 737250397Sobrien return; 737350397Sobrien 737450397Sobrien bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); 737550397Sobrien 737650397Sobrien /* Note that the bit offset is always the distance (in bits) from the 737750397Sobrien highest-order bit of the "containing object" to the highest-order bit of 737850397Sobrien the bit-field itself. Since the "high-order end" of any object or field 737950397Sobrien is different on big-endian and little-endian machines, the computation 738050397Sobrien below must take account of these differences. */ 738150397Sobrien highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT; 738250397Sobrien highest_order_field_bit_offset = bitpos_int; 738350397Sobrien 738450397Sobrien if (! BYTES_BIG_ENDIAN) 738550397Sobrien { 738650397Sobrien highest_order_field_bit_offset 738750397Sobrien += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)); 738850397Sobrien 738950397Sobrien highest_order_object_bit_offset += simple_type_size_in_bits (type); 739050397Sobrien } 739150397Sobrien 739250397Sobrien bit_offset 739350397Sobrien = (! BYTES_BIG_ENDIAN 739450397Sobrien ? highest_order_object_bit_offset - highest_order_field_bit_offset 739550397Sobrien : highest_order_field_bit_offset - highest_order_object_bit_offset); 739650397Sobrien 739750397Sobrien add_AT_unsigned (die, DW_AT_bit_offset, bit_offset); 739850397Sobrien} 739950397Sobrien 740050397Sobrien/* For a FIELD_DECL node which represents a bit field, output an attribute 740150397Sobrien which specifies the length in bits of the given field. */ 740250397Sobrien 740350397Sobrienstatic inline void 740450397Sobrienadd_bit_size_attribute (die, decl) 740550397Sobrien register dw_die_ref die; 740650397Sobrien register tree decl; 740750397Sobrien{ 740850397Sobrien /* Must be a field and a bit field. */ 740950397Sobrien if (TREE_CODE (decl) != FIELD_DECL 741050397Sobrien || ! DECL_BIT_FIELD_TYPE (decl)) 741150397Sobrien abort (); 741250397Sobrien add_AT_unsigned (die, DW_AT_bit_size, 741350397Sobrien (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl))); 741450397Sobrien} 741550397Sobrien 741650397Sobrien/* If the compiled language is ANSI C, then add a 'prototyped' 741750397Sobrien attribute, if arg types are given for the parameters of a function. */ 741850397Sobrien 741950397Sobrienstatic inline void 742050397Sobrienadd_prototyped_attribute (die, func_type) 742150397Sobrien register dw_die_ref die; 742250397Sobrien register tree func_type; 742350397Sobrien{ 742450397Sobrien if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89 742550397Sobrien && TYPE_ARG_TYPES (func_type) != NULL) 742650397Sobrien add_AT_flag (die, DW_AT_prototyped, 1); 742750397Sobrien} 742850397Sobrien 742950397Sobrien 743050397Sobrien/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found 743150397Sobrien by looking in either the type declaration or object declaration 743250397Sobrien equate table. */ 743350397Sobrien 743450397Sobrienstatic inline void 743550397Sobrienadd_abstract_origin_attribute (die, origin) 743650397Sobrien register dw_die_ref die; 743750397Sobrien register tree origin; 743850397Sobrien{ 743950397Sobrien dw_die_ref origin_die = NULL; 744050397Sobrien if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd') 744150397Sobrien origin_die = lookup_decl_die (origin); 744250397Sobrien else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't') 744350397Sobrien origin_die = lookup_type_die (origin); 744450397Sobrien 744550397Sobrien add_AT_die_ref (die, DW_AT_abstract_origin, origin_die); 744650397Sobrien} 744750397Sobrien 744850397Sobrien/* We do not currently support the pure_virtual attribute. */ 744950397Sobrien 745050397Sobrienstatic inline void 745150397Sobrienadd_pure_or_virtual_attribute (die, func_decl) 745250397Sobrien register dw_die_ref die; 745350397Sobrien register tree func_decl; 745450397Sobrien{ 745550397Sobrien if (DECL_VINDEX (func_decl)) 745650397Sobrien { 745750397Sobrien add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); 745850397Sobrien add_AT_loc (die, DW_AT_vtable_elem_location, 745950397Sobrien new_loc_descr (DW_OP_constu, 746050397Sobrien TREE_INT_CST_LOW (DECL_VINDEX (func_decl)), 746150397Sobrien 0)); 746250397Sobrien 746350397Sobrien /* GNU extension: Record what type this method came from originally. */ 746450397Sobrien if (debug_info_level > DINFO_LEVEL_TERSE) 746550397Sobrien add_AT_die_ref (die, DW_AT_containing_type, 746650397Sobrien lookup_type_die (DECL_CONTEXT (func_decl))); 746750397Sobrien } 746850397Sobrien} 746950397Sobrien 747050397Sobrien/* Add source coordinate attributes for the given decl. */ 747150397Sobrien 747250397Sobrienstatic void 747350397Sobrienadd_src_coords_attributes (die, decl) 747450397Sobrien register dw_die_ref die; 747550397Sobrien register tree decl; 747650397Sobrien{ 747750397Sobrien register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl)); 747850397Sobrien 747950397Sobrien add_AT_unsigned (die, DW_AT_decl_file, file_index); 748050397Sobrien add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); 748150397Sobrien} 748250397Sobrien 748350397Sobrien/* Add an DW_AT_name attribute and source coordinate attribute for the 748450397Sobrien given decl, but only if it actually has a name. */ 748550397Sobrien 748650397Sobrienstatic void 748750397Sobrienadd_name_and_src_coords_attributes (die, decl) 748850397Sobrien register dw_die_ref die; 748950397Sobrien register tree decl; 749050397Sobrien{ 749150397Sobrien register tree decl_name; 749250397Sobrien 749350397Sobrien decl_name = DECL_NAME (decl); 749450397Sobrien if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) 749550397Sobrien { 749650397Sobrien add_name_attribute (die, dwarf2_name (decl, 0)); 749750397Sobrien add_src_coords_attributes (die, decl); 749850397Sobrien if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) 749950397Sobrien && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) 750050397Sobrien add_AT_string (die, DW_AT_MIPS_linkage_name, 750150397Sobrien IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); 750250397Sobrien } 750350397Sobrien} 750450397Sobrien 750550397Sobrien/* Push a new declaration scope. */ 750650397Sobrien 750750397Sobrienstatic void 750850397Sobrienpush_decl_scope (scope) 750950397Sobrien tree scope; 751050397Sobrien{ 751150397Sobrien tree containing_scope; 751250397Sobrien int i; 751350397Sobrien 751450397Sobrien /* Make room in the decl_scope_table, if necessary. */ 751550397Sobrien if (decl_scope_table_allocated == decl_scope_depth) 751650397Sobrien { 751750397Sobrien decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT; 751850397Sobrien decl_scope_table 751950397Sobrien = (decl_scope_node *) xrealloc (decl_scope_table, 752050397Sobrien (decl_scope_table_allocated 752150397Sobrien * sizeof (decl_scope_node))); 752250397Sobrien } 752350397Sobrien 752450397Sobrien decl_scope_table[decl_scope_depth].scope = scope; 752550397Sobrien 752650397Sobrien /* Sometimes, while recursively emitting subtypes within a class type, 752750397Sobrien we end up recuring on a subtype at a higher level then the current 752850397Sobrien subtype. In such a case, we need to search the decl_scope_table to 752950397Sobrien find the parent of this subtype. */ 753050397Sobrien 753150397Sobrien if (TREE_CODE_CLASS (TREE_CODE (scope)) == 't') 753250397Sobrien containing_scope = TYPE_CONTEXT (scope); 753350397Sobrien else 753450397Sobrien containing_scope = NULL_TREE; 753550397Sobrien 753650397Sobrien /* The normal case. */ 753750397Sobrien if (decl_scope_depth == 0 753850397Sobrien || containing_scope == NULL_TREE 753950397Sobrien /* Ignore namespaces for the moment. */ 754050397Sobrien || TREE_CODE (containing_scope) == NAMESPACE_DECL 754150397Sobrien || containing_scope == decl_scope_table[decl_scope_depth - 1].scope) 754250397Sobrien decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1; 754350397Sobrien else 754450397Sobrien { 754550397Sobrien /* We need to search for the containing_scope. */ 754650397Sobrien for (i = 0; i < decl_scope_depth; i++) 754750397Sobrien if (decl_scope_table[i].scope == containing_scope) 754850397Sobrien break; 754950397Sobrien 755050397Sobrien if (i == decl_scope_depth) 755150397Sobrien abort (); 755250397Sobrien else 755350397Sobrien decl_scope_table[decl_scope_depth].previous = i; 755450397Sobrien } 755550397Sobrien 755650397Sobrien decl_scope_depth++; 755750397Sobrien} 755850397Sobrien 755950397Sobrien/* Return the DIE for the scope that immediately contains this declaration. */ 756050397Sobrien 756150397Sobrienstatic dw_die_ref 756250397Sobrienscope_die_for (t, context_die) 756350397Sobrien register tree t; 756450397Sobrien register dw_die_ref context_die; 756550397Sobrien{ 756650397Sobrien register dw_die_ref scope_die = NULL; 756750397Sobrien register tree containing_scope; 756850397Sobrien register int i; 756950397Sobrien 757050397Sobrien /* Walk back up the declaration tree looking for a place to define 757150397Sobrien this type. */ 757250397Sobrien if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') 757350397Sobrien containing_scope = TYPE_CONTEXT (t); 757450397Sobrien else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t)) 757550397Sobrien containing_scope = decl_class_context (t); 757650397Sobrien else 757750397Sobrien containing_scope = DECL_CONTEXT (t); 757850397Sobrien 757950397Sobrien /* Ignore namespaces for the moment. */ 758050397Sobrien if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL) 758150397Sobrien containing_scope = NULL_TREE; 758250397Sobrien 758350397Sobrien /* Function-local tags and functions get stuck in limbo until they are 758450397Sobrien fixed up by decls_for_scope. */ 758550397Sobrien if (context_die == NULL && containing_scope != NULL_TREE 758650397Sobrien && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t))) 758750397Sobrien return NULL; 758850397Sobrien 758950397Sobrien if (containing_scope == NULL_TREE) 759050397Sobrien scope_die = comp_unit_die; 759150397Sobrien else 759250397Sobrien { 759350397Sobrien for (i = decl_scope_depth - 1, scope_die = context_die; 759450397Sobrien i >= 0 && decl_scope_table[i].scope != containing_scope; 759550397Sobrien (scope_die = scope_die->die_parent, 759650397Sobrien i = decl_scope_table[i].previous)) 759750397Sobrien ; 759850397Sobrien 759950397Sobrien /* ??? Integrate_decl_tree does not handle BLOCK_TYPE_TAGS, nor 760050397Sobrien does it try to handle types defined by TYPE_DECLs. Such types 760150397Sobrien thus have an incorrect TYPE_CONTEXT, which points to the block 760250397Sobrien they were originally defined in, instead of the current block 760350397Sobrien created by function inlining. We try to detect that here and 760450397Sobrien work around it. */ 760550397Sobrien 760650397Sobrien if (i < 0 && scope_die == comp_unit_die 760750397Sobrien && TREE_CODE (containing_scope) == BLOCK 760850397Sobrien && is_tagged_type (t) 760950397Sobrien && (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope) 761050397Sobrien == containing_scope)) 761150397Sobrien { 761250397Sobrien scope_die = context_die; 761350397Sobrien /* Since the checks below are no longer applicable. */ 761450397Sobrien i = 0; 761550397Sobrien } 761650397Sobrien 761750397Sobrien if (i < 0) 761850397Sobrien { 761950397Sobrien if (scope_die != comp_unit_die 762050397Sobrien || TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't') 762150397Sobrien abort (); 762250397Sobrien if (debug_info_level > DINFO_LEVEL_TERSE 762350397Sobrien && !TREE_ASM_WRITTEN (containing_scope)) 762450397Sobrien abort (); 762550397Sobrien } 762650397Sobrien } 762750397Sobrien 762850397Sobrien return scope_die; 762950397Sobrien} 763050397Sobrien 763150397Sobrien/* Pop a declaration scope. */ 763250397Sobrienstatic inline void 763350397Sobrienpop_decl_scope () 763450397Sobrien{ 763550397Sobrien if (decl_scope_depth <= 0) 763650397Sobrien abort (); 763750397Sobrien --decl_scope_depth; 763850397Sobrien} 763950397Sobrien 764050397Sobrien/* Many forms of DIEs require a "type description" attribute. This 764150397Sobrien routine locates the proper "type descriptor" die for the type given 764250397Sobrien by 'type', and adds an DW_AT_type attribute below the given die. */ 764350397Sobrien 764450397Sobrienstatic void 764550397Sobrienadd_type_attribute (object_die, type, decl_const, decl_volatile, context_die) 764650397Sobrien register dw_die_ref object_die; 764750397Sobrien register tree type; 764850397Sobrien register int decl_const; 764950397Sobrien register int decl_volatile; 765050397Sobrien register dw_die_ref context_die; 765150397Sobrien{ 765250397Sobrien register enum tree_code code = TREE_CODE (type); 765350397Sobrien register dw_die_ref type_die = NULL; 765450397Sobrien 765550397Sobrien /* ??? If this type is an unnamed subrange type of an integral or 765650397Sobrien floating-point type, use the inner type. This is because we have no 765750397Sobrien support for unnamed types in base_type_die. This can happen if this is 765850397Sobrien an Ada subrange type. Correct solution is emit a subrange type die. */ 765950397Sobrien if ((code == INTEGER_TYPE || code == REAL_TYPE) 766050397Sobrien && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0) 766150397Sobrien type = TREE_TYPE (type), code = TREE_CODE (type); 766250397Sobrien 766350397Sobrien if (code == ERROR_MARK) 766450397Sobrien return; 766550397Sobrien 766650397Sobrien /* Handle a special case. For functions whose return type is void, we 766750397Sobrien generate *no* type attribute. (Note that no object may have type 766850397Sobrien `void', so this only applies to function return types). */ 766950397Sobrien if (code == VOID_TYPE) 767050397Sobrien return; 767150397Sobrien 767250397Sobrien type_die = modified_type_die (type, 767350397Sobrien decl_const || TYPE_READONLY (type), 767450397Sobrien decl_volatile || TYPE_VOLATILE (type), 767550397Sobrien context_die); 767650397Sobrien if (type_die != NULL) 767750397Sobrien add_AT_die_ref (object_die, DW_AT_type, type_die); 767850397Sobrien} 767950397Sobrien 768050397Sobrien/* Given a tree pointer to a struct, class, union, or enum type node, return 768150397Sobrien a pointer to the (string) tag name for the given type, or zero if the type 768250397Sobrien was declared without a tag. */ 768350397Sobrien 768450397Sobrienstatic char * 768550397Sobrientype_tag (type) 768650397Sobrien register tree type; 768750397Sobrien{ 768850397Sobrien register char *name = 0; 768950397Sobrien 769050397Sobrien if (TYPE_NAME (type) != 0) 769150397Sobrien { 769250397Sobrien register tree t = 0; 769350397Sobrien 769450397Sobrien /* Find the IDENTIFIER_NODE for the type name. */ 769550397Sobrien if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) 769650397Sobrien t = TYPE_NAME (type); 769750397Sobrien 769850397Sobrien /* The g++ front end makes the TYPE_NAME of *each* tagged type point to 769950397Sobrien a TYPE_DECL node, regardless of whether or not a `typedef' was 770050397Sobrien involved. */ 770150397Sobrien else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL 770250397Sobrien && ! DECL_IGNORED_P (TYPE_NAME (type))) 770350397Sobrien t = DECL_NAME (TYPE_NAME (type)); 770450397Sobrien 770550397Sobrien /* Now get the name as a string, or invent one. */ 770650397Sobrien if (t != 0) 770750397Sobrien name = IDENTIFIER_POINTER (t); 770850397Sobrien } 770950397Sobrien 771050397Sobrien return (name == 0 || *name == '\0') ? 0 : name; 771150397Sobrien} 771250397Sobrien 771350397Sobrien/* Return the type associated with a data member, make a special check 771450397Sobrien for bit field types. */ 771550397Sobrien 771650397Sobrienstatic inline tree 771750397Sobrienmember_declared_type (member) 771850397Sobrien register tree member; 771950397Sobrien{ 772050397Sobrien return (DECL_BIT_FIELD_TYPE (member) 772150397Sobrien ? DECL_BIT_FIELD_TYPE (member) 772250397Sobrien : TREE_TYPE (member)); 772350397Sobrien} 772450397Sobrien 772550397Sobrien/* Get the decl's label, as described by its RTL. This may be different 772650397Sobrien from the DECL_NAME name used in the source file. */ 772750397Sobrien 772850397Sobrien#if 0 772950397Sobrienstatic char * 773050397Sobriendecl_start_label (decl) 773150397Sobrien register tree decl; 773250397Sobrien{ 773350397Sobrien rtx x; 773450397Sobrien char *fnname; 773550397Sobrien x = DECL_RTL (decl); 773650397Sobrien if (GET_CODE (x) != MEM) 773750397Sobrien abort (); 773850397Sobrien 773950397Sobrien x = XEXP (x, 0); 774050397Sobrien if (GET_CODE (x) != SYMBOL_REF) 774150397Sobrien abort (); 774250397Sobrien 774350397Sobrien fnname = XSTR (x, 0); 774450397Sobrien return fnname; 774550397Sobrien} 774650397Sobrien#endif 774750397Sobrien 774850397Sobrien/* These routines generate the internal representation of the DIE's for 774950397Sobrien the compilation unit. Debugging information is collected by walking 775050397Sobrien the declaration trees passed in from dwarf2out_decl(). */ 775150397Sobrien 775250397Sobrienstatic void 775350397Sobriengen_array_type_die (type, context_die) 775450397Sobrien register tree type; 775550397Sobrien register dw_die_ref context_die; 775650397Sobrien{ 775750397Sobrien register dw_die_ref scope_die = scope_die_for (type, context_die); 775850397Sobrien register dw_die_ref array_die; 775950397Sobrien register tree element_type; 776050397Sobrien 776150397Sobrien /* ??? The SGI dwarf reader fails for array of array of enum types unless 776250397Sobrien the inner array type comes before the outer array type. Thus we must 776350397Sobrien call gen_type_die before we call new_die. See below also. */ 776450397Sobrien#ifdef MIPS_DEBUGGING_INFO 776550397Sobrien gen_type_die (TREE_TYPE (type), context_die); 776650397Sobrien#endif 776750397Sobrien 776850397Sobrien array_die = new_die (DW_TAG_array_type, scope_die); 776950397Sobrien 777050397Sobrien#if 0 777150397Sobrien /* We default the array ordering. SDB will probably do 777250397Sobrien the right things even if DW_AT_ordering is not present. It's not even 777350397Sobrien an issue until we start to get into multidimensional arrays anyway. If 777450397Sobrien SDB is ever caught doing the Wrong Thing for multi-dimensional arrays, 777550397Sobrien then we'll have to put the DW_AT_ordering attribute back in. (But if 777650397Sobrien and when we find out that we need to put these in, we will only do so 777750397Sobrien for multidimensional arrays. */ 777850397Sobrien add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major); 777950397Sobrien#endif 778050397Sobrien 778150397Sobrien#ifdef MIPS_DEBUGGING_INFO 778250397Sobrien /* The SGI compilers handle arrays of unknown bound by setting 778350397Sobrien AT_declaration and not emitting any subrange DIEs. */ 778450397Sobrien if (! TYPE_DOMAIN (type)) 778550397Sobrien add_AT_unsigned (array_die, DW_AT_declaration, 1); 778650397Sobrien else 778750397Sobrien#endif 778850397Sobrien add_subscript_info (array_die, type); 778950397Sobrien 779050397Sobrien equate_type_number_to_die (type, array_die); 779150397Sobrien 779250397Sobrien /* Add representation of the type of the elements of this array type. */ 779350397Sobrien element_type = TREE_TYPE (type); 779450397Sobrien 779550397Sobrien /* ??? The SGI dwarf reader fails for multidimensional arrays with a 779650397Sobrien const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. 779750397Sobrien We work around this by disabling this feature. See also 779850397Sobrien add_subscript_info. */ 779950397Sobrien#ifndef MIPS_DEBUGGING_INFO 780050397Sobrien while (TREE_CODE (element_type) == ARRAY_TYPE) 780150397Sobrien element_type = TREE_TYPE (element_type); 780250397Sobrien 780350397Sobrien gen_type_die (element_type, context_die); 780450397Sobrien#endif 780550397Sobrien 780650397Sobrien add_type_attribute (array_die, element_type, 0, 0, context_die); 780750397Sobrien} 780850397Sobrien 780950397Sobrienstatic void 781050397Sobriengen_set_type_die (type, context_die) 781150397Sobrien register tree type; 781250397Sobrien register dw_die_ref context_die; 781350397Sobrien{ 781450397Sobrien register dw_die_ref type_die 781550397Sobrien = new_die (DW_TAG_set_type, scope_die_for (type, context_die)); 781650397Sobrien 781750397Sobrien equate_type_number_to_die (type, type_die); 781850397Sobrien add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die); 781950397Sobrien} 782050397Sobrien 782150397Sobrien#if 0 782250397Sobrienstatic void 782350397Sobriengen_entry_point_die (decl, context_die) 782450397Sobrien register tree decl; 782550397Sobrien register dw_die_ref context_die; 782650397Sobrien{ 782750397Sobrien register tree origin = decl_ultimate_origin (decl); 782850397Sobrien register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die); 782950397Sobrien if (origin != NULL) 783050397Sobrien add_abstract_origin_attribute (decl_die, origin); 783150397Sobrien else 783250397Sobrien { 783350397Sobrien add_name_and_src_coords_attributes (decl_die, decl); 783450397Sobrien add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)), 783550397Sobrien 0, 0, context_die); 783650397Sobrien } 783750397Sobrien 783850397Sobrien if (DECL_ABSTRACT (decl)) 783950397Sobrien equate_decl_number_to_die (decl, decl_die); 784050397Sobrien else 784150397Sobrien add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl)); 784250397Sobrien} 784350397Sobrien#endif 784450397Sobrien 784550397Sobrien/* Remember a type in the pending_types_list. */ 784650397Sobrien 784750397Sobrienstatic void 784850397Sobrienpend_type (type) 784950397Sobrien register tree type; 785050397Sobrien{ 785150397Sobrien if (pending_types == pending_types_allocated) 785250397Sobrien { 785350397Sobrien pending_types_allocated += PENDING_TYPES_INCREMENT; 785450397Sobrien pending_types_list 785550397Sobrien = (tree *) xrealloc (pending_types_list, 785650397Sobrien sizeof (tree) * pending_types_allocated); 785750397Sobrien } 785850397Sobrien 785950397Sobrien pending_types_list[pending_types++] = type; 786050397Sobrien} 786150397Sobrien 786250397Sobrien/* Output any pending types (from the pending_types list) which we can output 786350397Sobrien now (taking into account the scope that we are working on now). 786450397Sobrien 786550397Sobrien For each type output, remove the given type from the pending_types_list 786650397Sobrien *before* we try to output it. */ 786750397Sobrien 786850397Sobrienstatic void 786950397Sobrienoutput_pending_types_for_scope (context_die) 787050397Sobrien register dw_die_ref context_die; 787150397Sobrien{ 787250397Sobrien register tree type; 787350397Sobrien 787450397Sobrien while (pending_types) 787550397Sobrien { 787650397Sobrien --pending_types; 787750397Sobrien type = pending_types_list[pending_types]; 787850397Sobrien gen_type_die (type, context_die); 787950397Sobrien if (!TREE_ASM_WRITTEN (type)) 788050397Sobrien abort (); 788150397Sobrien } 788250397Sobrien} 788350397Sobrien 788450397Sobrien/* Generate a DIE to represent an inlined instance of an enumeration type. */ 788550397Sobrien 788650397Sobrienstatic void 788750397Sobriengen_inlined_enumeration_type_die (type, context_die) 788850397Sobrien register tree type; 788950397Sobrien register dw_die_ref context_die; 789050397Sobrien{ 789150397Sobrien register dw_die_ref type_die = new_die (DW_TAG_enumeration_type, 789250397Sobrien scope_die_for (type, context_die)); 789350397Sobrien 789450397Sobrien if (!TREE_ASM_WRITTEN (type)) 789550397Sobrien abort (); 789650397Sobrien add_abstract_origin_attribute (type_die, type); 789750397Sobrien} 789850397Sobrien 789950397Sobrien/* Generate a DIE to represent an inlined instance of a structure type. */ 790050397Sobrien 790150397Sobrienstatic void 790250397Sobriengen_inlined_structure_type_die (type, context_die) 790350397Sobrien register tree type; 790450397Sobrien register dw_die_ref context_die; 790550397Sobrien{ 790650397Sobrien register dw_die_ref type_die = new_die (DW_TAG_structure_type, 790750397Sobrien scope_die_for (type, context_die)); 790850397Sobrien 790950397Sobrien if (!TREE_ASM_WRITTEN (type)) 791050397Sobrien abort (); 791150397Sobrien add_abstract_origin_attribute (type_die, type); 791250397Sobrien} 791350397Sobrien 791450397Sobrien/* Generate a DIE to represent an inlined instance of a union type. */ 791550397Sobrien 791650397Sobrienstatic void 791750397Sobriengen_inlined_union_type_die (type, context_die) 791850397Sobrien register tree type; 791950397Sobrien register dw_die_ref context_die; 792050397Sobrien{ 792150397Sobrien register dw_die_ref type_die = new_die (DW_TAG_union_type, 792250397Sobrien scope_die_for (type, context_die)); 792350397Sobrien 792450397Sobrien if (!TREE_ASM_WRITTEN (type)) 792550397Sobrien abort (); 792650397Sobrien add_abstract_origin_attribute (type_die, type); 792750397Sobrien} 792850397Sobrien 792950397Sobrien/* Generate a DIE to represent an enumeration type. Note that these DIEs 793050397Sobrien include all of the information about the enumeration values also. Each 793150397Sobrien enumerated type name/value is listed as a child of the enumerated type 793250397Sobrien DIE. */ 793350397Sobrien 793450397Sobrienstatic void 793550397Sobriengen_enumeration_type_die (type, context_die) 793650397Sobrien register tree type; 793750397Sobrien register dw_die_ref context_die; 793850397Sobrien{ 793950397Sobrien register dw_die_ref type_die = lookup_type_die (type); 794050397Sobrien 794150397Sobrien if (type_die == NULL) 794250397Sobrien { 794350397Sobrien type_die = new_die (DW_TAG_enumeration_type, 794450397Sobrien scope_die_for (type, context_die)); 794550397Sobrien equate_type_number_to_die (type, type_die); 794650397Sobrien add_name_attribute (type_die, type_tag (type)); 794750397Sobrien } 794850397Sobrien else if (! TYPE_SIZE (type)) 794950397Sobrien return; 795050397Sobrien else 795150397Sobrien remove_AT (type_die, DW_AT_declaration); 795250397Sobrien 795350397Sobrien /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the 795450397Sobrien given enum type is incomplete, do not generate the DW_AT_byte_size 795550397Sobrien attribute or the DW_AT_element_list attribute. */ 795650397Sobrien if (TYPE_SIZE (type)) 795750397Sobrien { 795850397Sobrien register tree link; 795950397Sobrien 796050397Sobrien TREE_ASM_WRITTEN (type) = 1; 796150397Sobrien add_byte_size_attribute (type_die, type); 796250397Sobrien if (TYPE_STUB_DECL (type) != NULL_TREE) 796350397Sobrien add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); 796450397Sobrien 796550397Sobrien /* If the first reference to this type was as the return type of an 796650397Sobrien inline function, then it may not have a parent. Fix this now. */ 796750397Sobrien if (type_die->die_parent == NULL) 796850397Sobrien add_child_die (scope_die_for (type, context_die), type_die); 796950397Sobrien 797050397Sobrien for (link = TYPE_FIELDS (type); 797150397Sobrien link != NULL; link = TREE_CHAIN (link)) 797250397Sobrien { 797350397Sobrien register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die); 797450397Sobrien 797550397Sobrien add_name_attribute (enum_die, 797650397Sobrien IDENTIFIER_POINTER (TREE_PURPOSE (link))); 797750397Sobrien add_AT_unsigned (enum_die, DW_AT_const_value, 797850397Sobrien (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link))); 797950397Sobrien } 798050397Sobrien } 798150397Sobrien else 798250397Sobrien add_AT_flag (type_die, DW_AT_declaration, 1); 798350397Sobrien} 798450397Sobrien 798550397Sobrien 798650397Sobrien/* Generate a DIE to represent either a real live formal parameter decl or to 798750397Sobrien represent just the type of some formal parameter position in some function 798850397Sobrien type. 798950397Sobrien 799050397Sobrien Note that this routine is a bit unusual because its argument may be a 799150397Sobrien ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which 799250397Sobrien represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE 799350397Sobrien node. If it's the former then this function is being called to output a 799450397Sobrien DIE to represent a formal parameter object (or some inlining thereof). If 799550397Sobrien it's the latter, then this function is only being called to output a 799650397Sobrien DW_TAG_formal_parameter DIE to stand as a placeholder for some formal 799750397Sobrien argument type of some subprogram type. */ 799850397Sobrien 799950397Sobrienstatic dw_die_ref 800050397Sobriengen_formal_parameter_die (node, context_die) 800150397Sobrien register tree node; 800250397Sobrien register dw_die_ref context_die; 800350397Sobrien{ 800450397Sobrien register dw_die_ref parm_die 800550397Sobrien = new_die (DW_TAG_formal_parameter, context_die); 800650397Sobrien register tree origin; 800750397Sobrien 800850397Sobrien switch (TREE_CODE_CLASS (TREE_CODE (node))) 800950397Sobrien { 801050397Sobrien case 'd': 801150397Sobrien origin = decl_ultimate_origin (node); 801250397Sobrien if (origin != NULL) 801350397Sobrien add_abstract_origin_attribute (parm_die, origin); 801450397Sobrien else 801550397Sobrien { 801650397Sobrien add_name_and_src_coords_attributes (parm_die, node); 801750397Sobrien add_type_attribute (parm_die, TREE_TYPE (node), 801850397Sobrien TREE_READONLY (node), 801950397Sobrien TREE_THIS_VOLATILE (node), 802050397Sobrien context_die); 802150397Sobrien if (DECL_ARTIFICIAL (node)) 802250397Sobrien add_AT_flag (parm_die, DW_AT_artificial, 1); 802350397Sobrien } 802450397Sobrien 802550397Sobrien equate_decl_number_to_die (node, parm_die); 802650397Sobrien if (! DECL_ABSTRACT (node)) 802750397Sobrien add_location_or_const_value_attribute (parm_die, node); 802850397Sobrien 802950397Sobrien break; 803050397Sobrien 803150397Sobrien case 't': 803250397Sobrien /* We were called with some kind of a ..._TYPE node. */ 803350397Sobrien add_type_attribute (parm_die, node, 0, 0, context_die); 803450397Sobrien break; 803550397Sobrien 803650397Sobrien default: 803750397Sobrien abort (); 803850397Sobrien } 803950397Sobrien 804050397Sobrien return parm_die; 804150397Sobrien} 804250397Sobrien 804350397Sobrien/* Generate a special type of DIE used as a stand-in for a trailing ellipsis 804450397Sobrien at the end of an (ANSI prototyped) formal parameters list. */ 804550397Sobrien 804650397Sobrienstatic void 804750397Sobriengen_unspecified_parameters_die (decl_or_type, context_die) 804850397Sobrien register tree decl_or_type; 804950397Sobrien register dw_die_ref context_die; 805050397Sobrien{ 805150397Sobrien new_die (DW_TAG_unspecified_parameters, context_die); 805250397Sobrien} 805350397Sobrien 805450397Sobrien/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a 805550397Sobrien DW_TAG_unspecified_parameters DIE) to represent the types of the formal 805650397Sobrien parameters as specified in some function type specification (except for 805750397Sobrien those which appear as part of a function *definition*). 805850397Sobrien 805950397Sobrien Note we must be careful here to output all of the parameter DIEs before* 806050397Sobrien we output any DIEs needed to represent the types of the formal parameters. 806150397Sobrien This keeps svr4 SDB happy because it (incorrectly) thinks that the first 806250397Sobrien non-parameter DIE it sees ends the formal parameter list. */ 806350397Sobrien 806450397Sobrienstatic void 806550397Sobriengen_formal_types_die (function_or_method_type, context_die) 806650397Sobrien register tree function_or_method_type; 806750397Sobrien register dw_die_ref context_die; 806850397Sobrien{ 806950397Sobrien register tree link; 807050397Sobrien register tree formal_type = NULL; 807150397Sobrien register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type); 807250397Sobrien 807350397Sobrien#if 0 807450397Sobrien /* In the case where we are generating a formal types list for a C++ 807550397Sobrien non-static member function type, skip over the first thing on the 807650397Sobrien TYPE_ARG_TYPES list because it only represents the type of the hidden 807750397Sobrien `this pointer'. The debugger should be able to figure out (without 807850397Sobrien being explicitly told) that this non-static member function type takes a 807950397Sobrien `this pointer' and should be able to figure what the type of that hidden 808050397Sobrien parameter is from the DW_AT_member attribute of the parent 808150397Sobrien DW_TAG_subroutine_type DIE. */ 808250397Sobrien if (TREE_CODE (function_or_method_type) == METHOD_TYPE) 808350397Sobrien first_parm_type = TREE_CHAIN (first_parm_type); 808450397Sobrien#endif 808550397Sobrien 808650397Sobrien /* Make our first pass over the list of formal parameter types and output a 808750397Sobrien DW_TAG_formal_parameter DIE for each one. */ 808850397Sobrien for (link = first_parm_type; link; link = TREE_CHAIN (link)) 808950397Sobrien { 809050397Sobrien register dw_die_ref parm_die; 809150397Sobrien 809250397Sobrien formal_type = TREE_VALUE (link); 809350397Sobrien if (formal_type == void_type_node) 809450397Sobrien break; 809550397Sobrien 809650397Sobrien /* Output a (nameless) DIE to represent the formal parameter itself. */ 809750397Sobrien parm_die = gen_formal_parameter_die (formal_type, context_die); 809850397Sobrien if (TREE_CODE (function_or_method_type) == METHOD_TYPE 809950397Sobrien && link == first_parm_type) 810050397Sobrien add_AT_flag (parm_die, DW_AT_artificial, 1); 810150397Sobrien } 810250397Sobrien 810350397Sobrien /* If this function type has an ellipsis, add a 810450397Sobrien DW_TAG_unspecified_parameters DIE to the end of the parameter list. */ 810550397Sobrien if (formal_type != void_type_node) 810650397Sobrien gen_unspecified_parameters_die (function_or_method_type, context_die); 810750397Sobrien 810850397Sobrien /* Make our second (and final) pass over the list of formal parameter types 810950397Sobrien and output DIEs to represent those types (as necessary). */ 811050397Sobrien for (link = TYPE_ARG_TYPES (function_or_method_type); 811150397Sobrien link; 811250397Sobrien link = TREE_CHAIN (link)) 811350397Sobrien { 811450397Sobrien formal_type = TREE_VALUE (link); 811550397Sobrien if (formal_type == void_type_node) 811650397Sobrien break; 811750397Sobrien 811850397Sobrien gen_type_die (formal_type, context_die); 811950397Sobrien } 812050397Sobrien} 812150397Sobrien 812250397Sobrien/* Generate a DIE to represent a declared function (either file-scope or 812350397Sobrien block-local). */ 812450397Sobrien 812550397Sobrienstatic void 812650397Sobriengen_subprogram_die (decl, context_die) 812750397Sobrien register tree decl; 812850397Sobrien register dw_die_ref context_die; 812950397Sobrien{ 813050397Sobrien char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; 813150397Sobrien register tree origin = decl_ultimate_origin (decl); 813250397Sobrien register dw_die_ref subr_die; 813350397Sobrien register rtx fp_reg; 813450397Sobrien register tree fn_arg_types; 813550397Sobrien register tree outer_scope; 813650397Sobrien register dw_die_ref old_die = lookup_decl_die (decl); 813750397Sobrien register int declaration 813850397Sobrien = (current_function_decl != decl 813950397Sobrien || (context_die 814050397Sobrien && (context_die->die_tag == DW_TAG_structure_type 814150397Sobrien || context_die->die_tag == DW_TAG_union_type))); 814250397Sobrien 814350397Sobrien if (origin != NULL) 814450397Sobrien { 814550397Sobrien subr_die = new_die (DW_TAG_subprogram, context_die); 814650397Sobrien add_abstract_origin_attribute (subr_die, origin); 814750397Sobrien } 814850397Sobrien else if (old_die && DECL_ABSTRACT (decl) 814950397Sobrien && get_AT_unsigned (old_die, DW_AT_inline)) 815050397Sobrien { 815150397Sobrien /* This must be a redefinition of an extern inline function. 815250397Sobrien We can just reuse the old die here. */ 815350397Sobrien subr_die = old_die; 815450397Sobrien 815550397Sobrien /* Clear out the inlined attribute and parm types. */ 815650397Sobrien remove_AT (subr_die, DW_AT_inline); 815750397Sobrien remove_children (subr_die); 815850397Sobrien } 815950397Sobrien else if (old_die) 816050397Sobrien { 816150397Sobrien register unsigned file_index 816250397Sobrien = lookup_filename (DECL_SOURCE_FILE (decl)); 816350397Sobrien 816450397Sobrien if (get_AT_flag (old_die, DW_AT_declaration) != 1) 816550397Sobrien abort (); 816650397Sobrien 816750397Sobrien /* If the definition comes from the same place as the declaration, 816850397Sobrien maybe use the old DIE. We always want the DIE for this function 816950397Sobrien that has the *_pc attributes to be under comp_unit_die so the 817050397Sobrien debugger can find it. For inlines, that is the concrete instance, 817150397Sobrien so we can use the old DIE here. For non-inline methods, we want a 817250397Sobrien specification DIE at toplevel, so we need a new DIE. For local 817350397Sobrien class methods, this does not apply. */ 817450397Sobrien if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die 817550397Sobrien || context_die == NULL) 817650397Sobrien && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index 817750397Sobrien && (get_AT_unsigned (old_die, DW_AT_decl_line) 817850397Sobrien == DECL_SOURCE_LINE (decl))) 817950397Sobrien { 818050397Sobrien subr_die = old_die; 818150397Sobrien 818250397Sobrien /* Clear out the declaration attribute and the parm types. */ 818350397Sobrien remove_AT (subr_die, DW_AT_declaration); 818450397Sobrien remove_children (subr_die); 818550397Sobrien } 818650397Sobrien else 818750397Sobrien { 818850397Sobrien subr_die = new_die (DW_TAG_subprogram, context_die); 818950397Sobrien add_AT_die_ref (subr_die, DW_AT_specification, old_die); 819050397Sobrien if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) 819150397Sobrien add_AT_unsigned (subr_die, DW_AT_decl_file, file_index); 819250397Sobrien if (get_AT_unsigned (old_die, DW_AT_decl_line) 819350397Sobrien != DECL_SOURCE_LINE (decl)) 819450397Sobrien add_AT_unsigned 819550397Sobrien (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); 819650397Sobrien } 819750397Sobrien } 819850397Sobrien else 819950397Sobrien { 820050397Sobrien register dw_die_ref scope_die; 820150397Sobrien 820250397Sobrien if (DECL_CONTEXT (decl)) 820350397Sobrien scope_die = scope_die_for (decl, context_die); 820450397Sobrien else 820550397Sobrien /* Don't put block extern declarations under comp_unit_die. */ 820650397Sobrien scope_die = context_die; 820750397Sobrien 820850397Sobrien subr_die = new_die (DW_TAG_subprogram, scope_die); 820950397Sobrien 821050397Sobrien if (TREE_PUBLIC (decl)) 821150397Sobrien add_AT_flag (subr_die, DW_AT_external, 1); 821250397Sobrien 821350397Sobrien add_name_and_src_coords_attributes (subr_die, decl); 821450397Sobrien if (debug_info_level > DINFO_LEVEL_TERSE) 821550397Sobrien { 821650397Sobrien register tree type = TREE_TYPE (decl); 821750397Sobrien 821850397Sobrien add_prototyped_attribute (subr_die, type); 821950397Sobrien add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die); 822050397Sobrien } 822150397Sobrien 822250397Sobrien add_pure_or_virtual_attribute (subr_die, decl); 822350397Sobrien if (DECL_ARTIFICIAL (decl)) 822450397Sobrien add_AT_flag (subr_die, DW_AT_artificial, 1); 822550397Sobrien if (TREE_PROTECTED (decl)) 822650397Sobrien add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected); 822750397Sobrien else if (TREE_PRIVATE (decl)) 822850397Sobrien add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private); 822950397Sobrien } 823050397Sobrien 823150397Sobrien if (declaration) 823250397Sobrien { 823350397Sobrien add_AT_flag (subr_die, DW_AT_declaration, 1); 823450397Sobrien 823550397Sobrien /* The first time we see a member function, it is in the context of 823650397Sobrien the class to which it belongs. We make sure of this by emitting 823750397Sobrien the class first. The next time is the definition, which is 823850397Sobrien handled above. The two may come from the same source text. */ 823950397Sobrien if (DECL_CONTEXT (decl)) 824050397Sobrien equate_decl_number_to_die (decl, subr_die); 824150397Sobrien } 824250397Sobrien else if (DECL_ABSTRACT (decl)) 824350397Sobrien { 824450397Sobrien /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions, 824550397Sobrien but not for extern inline functions. We can't get this completely 824650397Sobrien correct because information about whether the function was declared 824750397Sobrien inline is not saved anywhere. */ 824850397Sobrien if (DECL_DEFER_OUTPUT (decl)) 824950397Sobrien { 825050397Sobrien if (DECL_INLINE (decl)) 825150397Sobrien add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined); 825250397Sobrien else 825350397Sobrien add_AT_unsigned (subr_die, DW_AT_inline, 825450397Sobrien DW_INL_declared_not_inlined); 825550397Sobrien } 825650397Sobrien else if (DECL_INLINE (decl)) 825750397Sobrien add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined); 825850397Sobrien else 825950397Sobrien abort (); 826050397Sobrien 826150397Sobrien equate_decl_number_to_die (decl, subr_die); 826250397Sobrien } 826350397Sobrien else if (!DECL_EXTERNAL (decl)) 826450397Sobrien { 826550397Sobrien if (origin == NULL_TREE) 826650397Sobrien equate_decl_number_to_die (decl, subr_die); 826750397Sobrien 826850397Sobrien ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, 826950397Sobrien current_funcdef_number); 827050397Sobrien add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); 827150397Sobrien ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, 827250397Sobrien current_funcdef_number); 827350397Sobrien add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); 827450397Sobrien 827550397Sobrien add_pubname (decl, subr_die); 827650397Sobrien add_arange (decl, subr_die); 827750397Sobrien 827850397Sobrien#ifdef MIPS_DEBUGGING_INFO 827950397Sobrien /* Add a reference to the FDE for this routine. */ 828050397Sobrien add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde); 828150397Sobrien#endif 828250397Sobrien 828350397Sobrien /* Define the "frame base" location for this routine. We use the 828450397Sobrien frame pointer or stack pointer registers, since the RTL for local 828550397Sobrien variables is relative to one of them. */ 828650397Sobrien fp_reg 828750397Sobrien = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx; 828850397Sobrien add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg)); 828950397Sobrien 829050397Sobrien#if 0 829150397Sobrien /* ??? This fails for nested inline functions, because context_display 829250397Sobrien is not part of the state saved/restored for inline functions. */ 829350397Sobrien if (current_function_needs_context) 829450397Sobrien add_AT_location_description (subr_die, DW_AT_static_link, 829550397Sobrien lookup_static_chain (decl)); 829650397Sobrien#endif 829750397Sobrien } 829850397Sobrien 829950397Sobrien /* Now output descriptions of the arguments for this function. This gets 830050397Sobrien (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list 830150397Sobrien for a FUNCTION_DECL doesn't indicate cases where there was a trailing 830250397Sobrien `...' at the end of the formal parameter list. In order to find out if 830350397Sobrien there was a trailing ellipsis or not, we must instead look at the type 830450397Sobrien associated with the FUNCTION_DECL. This will be a node of type 830550397Sobrien FUNCTION_TYPE. If the chain of type nodes hanging off of this 830650397Sobrien FUNCTION_TYPE node ends with a void_type_node then there should *not* be 830750397Sobrien an ellipsis at the end. */ 830850397Sobrien push_decl_scope (decl); 830950397Sobrien 831050397Sobrien /* In the case where we are describing a mere function declaration, all we 831150397Sobrien need to do here (and all we *can* do here) is to describe the *types* of 831250397Sobrien its formal parameters. */ 831350397Sobrien if (debug_info_level <= DINFO_LEVEL_TERSE) 831450397Sobrien ; 831550397Sobrien else if (declaration) 831650397Sobrien gen_formal_types_die (TREE_TYPE (decl), subr_die); 831750397Sobrien else 831850397Sobrien { 831950397Sobrien /* Generate DIEs to represent all known formal parameters */ 832050397Sobrien register tree arg_decls = DECL_ARGUMENTS (decl); 832150397Sobrien register tree parm; 832250397Sobrien 832350397Sobrien /* When generating DIEs, generate the unspecified_parameters DIE 832450397Sobrien instead if we come across the arg "__builtin_va_alist" */ 832550397Sobrien for (parm = arg_decls; parm; parm = TREE_CHAIN (parm)) 832650397Sobrien if (TREE_CODE (parm) == PARM_DECL) 832750397Sobrien { 832850397Sobrien if (DECL_NAME (parm) 832950397Sobrien && !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)), 833050397Sobrien "__builtin_va_alist")) 833150397Sobrien gen_unspecified_parameters_die (parm, subr_die); 833250397Sobrien else 833350397Sobrien gen_decl_die (parm, subr_die); 833450397Sobrien } 833550397Sobrien 833650397Sobrien /* Decide whether we need a unspecified_parameters DIE at the end. 833750397Sobrien There are 2 more cases to do this for: 1) the ansi ... declaration - 833850397Sobrien this is detectable when the end of the arg list is not a 833950397Sobrien void_type_node 2) an unprototyped function declaration (not a 834050397Sobrien definition). This just means that we have no info about the 834150397Sobrien parameters at all. */ 834250397Sobrien fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); 834350397Sobrien if (fn_arg_types != NULL) 834450397Sobrien { 834550397Sobrien /* this is the prototyped case, check for ... */ 834650397Sobrien if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node) 834750397Sobrien gen_unspecified_parameters_die (decl, subr_die); 834850397Sobrien } 834950397Sobrien else if (DECL_INITIAL (decl) == NULL_TREE) 835050397Sobrien gen_unspecified_parameters_die (decl, subr_die); 835150397Sobrien } 835250397Sobrien 835350397Sobrien /* Output Dwarf info for all of the stuff within the body of the function 835450397Sobrien (if it has one - it may be just a declaration). */ 835550397Sobrien outer_scope = DECL_INITIAL (decl); 835650397Sobrien 835750397Sobrien /* Note that here, `outer_scope' is a pointer to the outermost BLOCK 835850397Sobrien node created to represent a function. This outermost BLOCK actually 835950397Sobrien represents the outermost binding contour for the function, i.e. the 836050397Sobrien contour in which the function's formal parameters and labels get 836150397Sobrien declared. Curiously, it appears that the front end doesn't actually 836250397Sobrien put the PARM_DECL nodes for the current function onto the BLOCK_VARS 836350397Sobrien list for this outer scope. (They are strung off of the DECL_ARGUMENTS 836450397Sobrien list for the function instead.) The BLOCK_VARS list for the 836550397Sobrien `outer_scope' does provide us with a list of the LABEL_DECL nodes for 836650397Sobrien the function however, and we output DWARF info for those in 836750397Sobrien decls_for_scope. Just within the `outer_scope' there will be a BLOCK 836850397Sobrien node representing the function's outermost pair of curly braces, and 836950397Sobrien any blocks used for the base and member initializers of a C++ 837050397Sobrien constructor function. */ 837150397Sobrien if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK) 837250397Sobrien { 837350397Sobrien current_function_has_inlines = 0; 837450397Sobrien decls_for_scope (outer_scope, subr_die, 0); 837550397Sobrien 837650397Sobrien#if 0 && defined (MIPS_DEBUGGING_INFO) 837750397Sobrien if (current_function_has_inlines) 837850397Sobrien { 837950397Sobrien add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1); 838050397Sobrien if (! comp_unit_has_inlines) 838150397Sobrien { 838250397Sobrien add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1); 838350397Sobrien comp_unit_has_inlines = 1; 838450397Sobrien } 838550397Sobrien } 838650397Sobrien#endif 838750397Sobrien } 838850397Sobrien 838950397Sobrien pop_decl_scope (); 839050397Sobrien} 839150397Sobrien 839250397Sobrien/* Generate a DIE to represent a declared data object. */ 839350397Sobrien 839450397Sobrienstatic void 839550397Sobriengen_variable_die (decl, context_die) 839650397Sobrien register tree decl; 839750397Sobrien register dw_die_ref context_die; 839850397Sobrien{ 839950397Sobrien register tree origin = decl_ultimate_origin (decl); 840050397Sobrien register dw_die_ref var_die = new_die (DW_TAG_variable, context_die); 840150397Sobrien 840250397Sobrien dw_die_ref old_die = lookup_decl_die (decl); 840350397Sobrien int declaration 840450397Sobrien = (DECL_EXTERNAL (decl) 840550397Sobrien || current_function_decl != decl_function_context (decl) 840650397Sobrien || context_die->die_tag == DW_TAG_structure_type 840750397Sobrien || context_die->die_tag == DW_TAG_union_type); 840850397Sobrien 840950397Sobrien if (origin != NULL) 841050397Sobrien add_abstract_origin_attribute (var_die, origin); 841150397Sobrien /* Loop unrolling can create multiple blocks that refer to the same 841250397Sobrien static variable, so we must test for the DW_AT_declaration flag. */ 841350397Sobrien /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to 841450397Sobrien copy decls and set the DECL_ABSTRACT flag on them instead of 841550397Sobrien sharing them. */ 841650397Sobrien else if (old_die && TREE_STATIC (decl) 841750397Sobrien && get_AT_flag (old_die, DW_AT_declaration) == 1) 841850397Sobrien { 841950397Sobrien /* ??? This is an instantiation of a C++ class level static. */ 842050397Sobrien add_AT_die_ref (var_die, DW_AT_specification, old_die); 842150397Sobrien if (DECL_NAME (decl)) 842250397Sobrien { 842350397Sobrien register unsigned file_index 842450397Sobrien = lookup_filename (DECL_SOURCE_FILE (decl)); 842550397Sobrien 842650397Sobrien if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) 842750397Sobrien add_AT_unsigned (var_die, DW_AT_decl_file, file_index); 842850397Sobrien 842950397Sobrien if (get_AT_unsigned (old_die, DW_AT_decl_line) 843050397Sobrien != DECL_SOURCE_LINE (decl)) 843150397Sobrien 843250397Sobrien add_AT_unsigned (var_die, DW_AT_decl_line, 843350397Sobrien DECL_SOURCE_LINE (decl)); 843450397Sobrien } 843550397Sobrien } 843650397Sobrien else 843750397Sobrien { 843850397Sobrien add_name_and_src_coords_attributes (var_die, decl); 843950397Sobrien add_type_attribute (var_die, TREE_TYPE (decl), 844050397Sobrien TREE_READONLY (decl), 844150397Sobrien TREE_THIS_VOLATILE (decl), context_die); 844250397Sobrien 844350397Sobrien if (TREE_PUBLIC (decl)) 844450397Sobrien add_AT_flag (var_die, DW_AT_external, 1); 844550397Sobrien 844650397Sobrien if (DECL_ARTIFICIAL (decl)) 844750397Sobrien add_AT_flag (var_die, DW_AT_artificial, 1); 844850397Sobrien 844950397Sobrien if (TREE_PROTECTED (decl)) 845050397Sobrien add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected); 845150397Sobrien 845250397Sobrien else if (TREE_PRIVATE (decl)) 845350397Sobrien add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private); 845450397Sobrien } 845550397Sobrien 845650397Sobrien if (declaration) 845750397Sobrien add_AT_flag (var_die, DW_AT_declaration, 1); 845850397Sobrien 845950397Sobrien if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl)) 846050397Sobrien equate_decl_number_to_die (decl, var_die); 846150397Sobrien 846250397Sobrien if (! declaration && ! DECL_ABSTRACT (decl)) 846350397Sobrien { 846450397Sobrien equate_decl_number_to_die (decl, var_die); 846550397Sobrien add_location_or_const_value_attribute (var_die, decl); 846650397Sobrien add_pubname (decl, var_die); 846750397Sobrien } 846850397Sobrien} 846950397Sobrien 847050397Sobrien/* Generate a DIE to represent a label identifier. */ 847150397Sobrien 847250397Sobrienstatic void 847350397Sobriengen_label_die (decl, context_die) 847450397Sobrien register tree decl; 847550397Sobrien register dw_die_ref context_die; 847650397Sobrien{ 847750397Sobrien register tree origin = decl_ultimate_origin (decl); 847850397Sobrien register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die); 847950397Sobrien register rtx insn; 848050397Sobrien char label[MAX_ARTIFICIAL_LABEL_BYTES]; 848150397Sobrien char label2[MAX_ARTIFICIAL_LABEL_BYTES]; 848250397Sobrien 848350397Sobrien if (origin != NULL) 848450397Sobrien add_abstract_origin_attribute (lbl_die, origin); 848550397Sobrien else 848650397Sobrien add_name_and_src_coords_attributes (lbl_die, decl); 848750397Sobrien 848850397Sobrien if (DECL_ABSTRACT (decl)) 848950397Sobrien equate_decl_number_to_die (decl, lbl_die); 849050397Sobrien else 849150397Sobrien { 849250397Sobrien insn = DECL_RTL (decl); 849350397Sobrien if (GET_CODE (insn) == CODE_LABEL) 849450397Sobrien { 849550397Sobrien /* When optimization is enabled (via -O) some parts of the compiler 849650397Sobrien (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which 849750397Sobrien represent source-level labels which were explicitly declared by 849850397Sobrien the user. This really shouldn't be happening though, so catch 849950397Sobrien it if it ever does happen. */ 850050397Sobrien if (INSN_DELETED_P (insn)) 850150397Sobrien abort (); 850250397Sobrien 850350397Sobrien sprintf (label2, INSN_LABEL_FMT, current_funcdef_number); 850450397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, label2, 850550397Sobrien (unsigned) INSN_UID (insn)); 850650397Sobrien add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); 850750397Sobrien } 850850397Sobrien } 850950397Sobrien} 851050397Sobrien 851150397Sobrien/* Generate a DIE for a lexical block. */ 851250397Sobrien 851350397Sobrienstatic void 851450397Sobriengen_lexical_block_die (stmt, context_die, depth) 851550397Sobrien register tree stmt; 851650397Sobrien register dw_die_ref context_die; 851750397Sobrien int depth; 851850397Sobrien{ 851950397Sobrien register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die); 852050397Sobrien char label[MAX_ARTIFICIAL_LABEL_BYTES]; 852150397Sobrien 852250397Sobrien if (! BLOCK_ABSTRACT (stmt)) 852350397Sobrien { 852450397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, 852550397Sobrien next_block_number); 852650397Sobrien add_AT_lbl_id (stmt_die, DW_AT_low_pc, label); 852750397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); 852850397Sobrien add_AT_lbl_id (stmt_die, DW_AT_high_pc, label); 852950397Sobrien } 853050397Sobrien 853150397Sobrien push_decl_scope (stmt); 853250397Sobrien decls_for_scope (stmt, stmt_die, depth); 853350397Sobrien pop_decl_scope (); 853450397Sobrien} 853550397Sobrien 853650397Sobrien/* Generate a DIE for an inlined subprogram. */ 853750397Sobrien 853850397Sobrienstatic void 853950397Sobriengen_inlined_subroutine_die (stmt, context_die, depth) 854050397Sobrien register tree stmt; 854150397Sobrien register dw_die_ref context_die; 854250397Sobrien int depth; 854350397Sobrien{ 854450397Sobrien if (! BLOCK_ABSTRACT (stmt)) 854550397Sobrien { 854650397Sobrien register dw_die_ref subr_die 854750397Sobrien = new_die (DW_TAG_inlined_subroutine, context_die); 854850397Sobrien register tree decl = block_ultimate_origin (stmt); 854950397Sobrien char label[MAX_ARTIFICIAL_LABEL_BYTES]; 855050397Sobrien 855150397Sobrien add_abstract_origin_attribute (subr_die, decl); 855250397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, 855350397Sobrien next_block_number); 855450397Sobrien add_AT_lbl_id (subr_die, DW_AT_low_pc, label); 855550397Sobrien ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); 855650397Sobrien add_AT_lbl_id (subr_die, DW_AT_high_pc, label); 855750397Sobrien push_decl_scope (decl); 855850397Sobrien decls_for_scope (stmt, subr_die, depth); 855950397Sobrien pop_decl_scope (); 856050397Sobrien current_function_has_inlines = 1; 856150397Sobrien } 856250397Sobrien} 856350397Sobrien 856450397Sobrien/* Generate a DIE for a field in a record, or structure. */ 856550397Sobrien 856650397Sobrienstatic void 856750397Sobriengen_field_die (decl, context_die) 856850397Sobrien register tree decl; 856950397Sobrien register dw_die_ref context_die; 857050397Sobrien{ 857150397Sobrien register dw_die_ref decl_die = new_die (DW_TAG_member, context_die); 857250397Sobrien 857350397Sobrien add_name_and_src_coords_attributes (decl_die, decl); 857450397Sobrien add_type_attribute (decl_die, member_declared_type (decl), 857550397Sobrien TREE_READONLY (decl), TREE_THIS_VOLATILE (decl), 857650397Sobrien context_die); 857750397Sobrien 857850397Sobrien /* If this is a bit field... */ 857950397Sobrien if (DECL_BIT_FIELD_TYPE (decl)) 858050397Sobrien { 858150397Sobrien add_byte_size_attribute (decl_die, decl); 858250397Sobrien add_bit_size_attribute (decl_die, decl); 858350397Sobrien add_bit_offset_attribute (decl_die, decl); 858450397Sobrien } 858550397Sobrien 858650397Sobrien if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE) 858750397Sobrien add_data_member_location_attribute (decl_die, decl); 858850397Sobrien 858950397Sobrien if (DECL_ARTIFICIAL (decl)) 859050397Sobrien add_AT_flag (decl_die, DW_AT_artificial, 1); 859150397Sobrien 859250397Sobrien if (TREE_PROTECTED (decl)) 859350397Sobrien add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected); 859450397Sobrien 859550397Sobrien else if (TREE_PRIVATE (decl)) 859650397Sobrien add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private); 859750397Sobrien} 859850397Sobrien 859950397Sobrien#if 0 860050397Sobrien/* Don't generate either pointer_type DIEs or reference_type DIEs here. 860150397Sobrien Use modified_type_die instead. 860250397Sobrien We keep this code here just in case these types of DIEs may be needed to 860350397Sobrien represent certain things in other languages (e.g. Pascal) someday. */ 860450397Sobrienstatic void 860550397Sobriengen_pointer_type_die (type, context_die) 860650397Sobrien register tree type; 860750397Sobrien register dw_die_ref context_die; 860850397Sobrien{ 860950397Sobrien register dw_die_ref ptr_die 861050397Sobrien = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die)); 861150397Sobrien 861250397Sobrien equate_type_number_to_die (type, ptr_die); 861350397Sobrien add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); 861450397Sobrien add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); 861550397Sobrien} 861650397Sobrien 861750397Sobrien/* Don't generate either pointer_type DIEs or reference_type DIEs here. 861850397Sobrien Use modified_type_die instead. 861950397Sobrien We keep this code here just in case these types of DIEs may be needed to 862050397Sobrien represent certain things in other languages (e.g. Pascal) someday. */ 862150397Sobrienstatic void 862250397Sobriengen_reference_type_die (type, context_die) 862350397Sobrien register tree type; 862450397Sobrien register dw_die_ref context_die; 862550397Sobrien{ 862650397Sobrien register dw_die_ref ref_die 862750397Sobrien = new_die (DW_TAG_reference_type, scope_die_for (type, context_die)); 862850397Sobrien 862950397Sobrien equate_type_number_to_die (type, ref_die); 863050397Sobrien add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die); 863150397Sobrien add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); 863250397Sobrien} 863350397Sobrien#endif 863450397Sobrien 863550397Sobrien/* Generate a DIE for a pointer to a member type. */ 863650397Sobrienstatic void 863750397Sobriengen_ptr_to_mbr_type_die (type, context_die) 863850397Sobrien register tree type; 863950397Sobrien register dw_die_ref context_die; 864050397Sobrien{ 864150397Sobrien register dw_die_ref ptr_die 864250397Sobrien = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die)); 864350397Sobrien 864450397Sobrien equate_type_number_to_die (type, ptr_die); 864550397Sobrien add_AT_die_ref (ptr_die, DW_AT_containing_type, 864650397Sobrien lookup_type_die (TYPE_OFFSET_BASETYPE (type))); 864750397Sobrien add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); 864850397Sobrien} 864950397Sobrien 865050397Sobrien/* Generate the DIE for the compilation unit. */ 865150397Sobrien 865250397Sobrienstatic void 865350397Sobriengen_compile_unit_die (main_input_filename) 865450397Sobrien register char *main_input_filename; 865550397Sobrien{ 865650397Sobrien char producer[250]; 865750397Sobrien char *wd = getpwd (); 865850397Sobrien 865950397Sobrien comp_unit_die = new_die (DW_TAG_compile_unit, NULL); 866050397Sobrien add_name_attribute (comp_unit_die, main_input_filename); 866150397Sobrien 866250397Sobrien if (wd != NULL) 866350397Sobrien add_AT_string (comp_unit_die, DW_AT_comp_dir, wd); 866450397Sobrien 866550397Sobrien sprintf (producer, "%s %s", language_string, version_string); 866650397Sobrien 866750397Sobrien#ifdef MIPS_DEBUGGING_INFO 866850397Sobrien /* The MIPS/SGI compilers place the 'cc' command line options in the producer 866950397Sobrien string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do 867050397Sobrien not appear in the producer string, the debugger reaches the conclusion 867150397Sobrien that the object file is stripped and has no debugging information. 867250397Sobrien To get the MIPS/SGI debugger to believe that there is debugging 867350397Sobrien information in the object file, we add a -g to the producer string. */ 867450397Sobrien if (debug_info_level > DINFO_LEVEL_TERSE) 867550397Sobrien strcat (producer, " -g"); 867650397Sobrien#endif 867750397Sobrien 867850397Sobrien add_AT_string (comp_unit_die, DW_AT_producer, producer); 867950397Sobrien 868050397Sobrien if (strcmp (language_string, "GNU C++") == 0) 868150397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus); 868250397Sobrien 868350397Sobrien else if (strcmp (language_string, "GNU Ada") == 0) 868450397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83); 868550397Sobrien 868650397Sobrien else if (strcmp (language_string, "GNU F77") == 0) 868750397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77); 868850397Sobrien 868950397Sobrien else if (strcmp (language_string, "GNU Pascal") == 0) 869050397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83); 869150397Sobrien 869250397Sobrien else if (flag_traditional) 869350397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C); 869450397Sobrien 869550397Sobrien else 869650397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89); 869750397Sobrien 869850397Sobrien#if 0 /* unimplemented */ 869950397Sobrien if (debug_info_level >= DINFO_LEVEL_VERBOSE) 870050397Sobrien add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0); 870150397Sobrien#endif 870250397Sobrien} 870350397Sobrien 870450397Sobrien/* Generate a DIE for a string type. */ 870550397Sobrien 870650397Sobrienstatic void 870750397Sobriengen_string_type_die (type, context_die) 870850397Sobrien register tree type; 870950397Sobrien register dw_die_ref context_die; 871050397Sobrien{ 871150397Sobrien register dw_die_ref type_die 871250397Sobrien = new_die (DW_TAG_string_type, scope_die_for (type, context_die)); 871350397Sobrien 871450397Sobrien equate_type_number_to_die (type, type_die); 871550397Sobrien 871650397Sobrien /* Fudge the string length attribute for now. */ 871750397Sobrien 871850397Sobrien /* TODO: add string length info. 871950397Sobrien string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type))); 872050397Sobrien bound_representation (upper_bound, 0, 'u'); */ 872150397Sobrien} 872250397Sobrien 872350397Sobrien/* Generate the DIE for a base class. */ 872450397Sobrien 872550397Sobrienstatic void 872650397Sobriengen_inheritance_die (binfo, context_die) 872750397Sobrien register tree binfo; 872850397Sobrien register dw_die_ref context_die; 872950397Sobrien{ 873050397Sobrien dw_die_ref die = new_die (DW_TAG_inheritance, context_die); 873150397Sobrien 873250397Sobrien add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die); 873350397Sobrien add_data_member_location_attribute (die, binfo); 873450397Sobrien 873550397Sobrien if (TREE_VIA_VIRTUAL (binfo)) 873650397Sobrien add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); 873750397Sobrien if (TREE_VIA_PUBLIC (binfo)) 873850397Sobrien add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public); 873950397Sobrien else if (TREE_VIA_PROTECTED (binfo)) 874050397Sobrien add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected); 874150397Sobrien} 874250397Sobrien 874350397Sobrien/* Generate a DIE for a class member. */ 874450397Sobrien 874550397Sobrienstatic void 874650397Sobriengen_member_die (type, context_die) 874750397Sobrien register tree type; 874850397Sobrien register dw_die_ref context_die; 874950397Sobrien{ 875050397Sobrien register tree member; 875150397Sobrien 875250397Sobrien /* If this is not an incomplete type, output descriptions of each of its 875350397Sobrien members. Note that as we output the DIEs necessary to represent the 875450397Sobrien members of this record or union type, we will also be trying to output 875550397Sobrien DIEs to represent the *types* of those members. However the `type' 875650397Sobrien function (above) will specifically avoid generating type DIEs for member 875750397Sobrien types *within* the list of member DIEs for this (containing) type execpt 875850397Sobrien for those types (of members) which are explicitly marked as also being 875950397Sobrien members of this (containing) type themselves. The g++ front- end can 876050397Sobrien force any given type to be treated as a member of some other 876150397Sobrien (containing) type by setting the TYPE_CONTEXT of the given (member) type 876250397Sobrien to point to the TREE node representing the appropriate (containing) 876350397Sobrien type. */ 876450397Sobrien 876550397Sobrien /* First output info about the base classes. */ 876650397Sobrien if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type)) 876750397Sobrien { 876850397Sobrien register tree bases = TYPE_BINFO_BASETYPES (type); 876950397Sobrien register int n_bases = TREE_VEC_LENGTH (bases); 877050397Sobrien register int i; 877150397Sobrien 877250397Sobrien for (i = 0; i < n_bases; i++) 877350397Sobrien gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die); 877450397Sobrien } 877550397Sobrien 877650397Sobrien /* Now output info about the data members and type members. */ 877750397Sobrien for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member)) 877850397Sobrien gen_decl_die (member, context_die); 877950397Sobrien 878050397Sobrien /* Now output info about the function members (if any). */ 878150397Sobrien for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member)) 878250397Sobrien gen_decl_die (member, context_die); 878350397Sobrien} 878450397Sobrien 878550397Sobrien/* Generate a DIE for a structure or union type. */ 878650397Sobrien 878750397Sobrienstatic void 878850397Sobriengen_struct_or_union_type_die (type, context_die) 878950397Sobrien register tree type; 879050397Sobrien register dw_die_ref context_die; 879150397Sobrien{ 879250397Sobrien register dw_die_ref type_die = lookup_type_die (type); 879350397Sobrien register dw_die_ref scope_die = 0; 879450397Sobrien register int nested = 0; 879550397Sobrien 879650397Sobrien if (type_die && ! TYPE_SIZE (type)) 879750397Sobrien return; 879850397Sobrien 879950397Sobrien if (TYPE_CONTEXT (type) != NULL_TREE 880050397Sobrien && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't') 880150397Sobrien nested = 1; 880250397Sobrien 880350397Sobrien scope_die = scope_die_for (type, context_die); 880450397Sobrien 880550397Sobrien if (! type_die || (nested && scope_die == comp_unit_die)) 880650397Sobrien /* First occurrence of type or toplevel definition of nested class. */ 880750397Sobrien { 880850397Sobrien register dw_die_ref old_die = type_die; 880950397Sobrien 881050397Sobrien type_die = new_die (TREE_CODE (type) == RECORD_TYPE 881150397Sobrien ? DW_TAG_structure_type : DW_TAG_union_type, 881250397Sobrien scope_die); 881350397Sobrien equate_type_number_to_die (type, type_die); 881450397Sobrien add_name_attribute (type_die, type_tag (type)); 881550397Sobrien if (old_die) 881650397Sobrien add_AT_die_ref (type_die, DW_AT_specification, old_die); 881750397Sobrien } 881850397Sobrien else 881950397Sobrien remove_AT (type_die, DW_AT_declaration); 882050397Sobrien 882150397Sobrien /* If we're not in the right context to be defining this type, defer to 882250397Sobrien avoid tricky recursion. */ 882350397Sobrien if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die) 882450397Sobrien { 882550397Sobrien add_AT_flag (type_die, DW_AT_declaration, 1); 882650397Sobrien pend_type (type); 882750397Sobrien } 882850397Sobrien /* If this type has been completed, then give it a byte_size attribute and 882950397Sobrien then give a list of members. */ 883050397Sobrien else if (TYPE_SIZE (type)) 883150397Sobrien { 883250397Sobrien /* Prevent infinite recursion in cases where the type of some member of 883350397Sobrien this type is expressed in terms of this type itself. */ 883450397Sobrien TREE_ASM_WRITTEN (type) = 1; 883550397Sobrien add_byte_size_attribute (type_die, type); 883650397Sobrien if (TYPE_STUB_DECL (type) != NULL_TREE) 883750397Sobrien add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); 883850397Sobrien 883950397Sobrien /* If the first reference to this type was as the return type of an 884050397Sobrien inline function, then it may not have a parent. Fix this now. */ 884150397Sobrien if (type_die->die_parent == NULL) 884250397Sobrien add_child_die (scope_die, type_die); 884350397Sobrien 884450397Sobrien push_decl_scope (type); 884550397Sobrien gen_member_die (type, type_die); 884650397Sobrien pop_decl_scope (); 884750397Sobrien 884850397Sobrien /* GNU extension: Record what type our vtable lives in. */ 884950397Sobrien if (TYPE_VFIELD (type)) 885050397Sobrien { 885150397Sobrien tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type)); 885250397Sobrien 885350397Sobrien gen_type_die (vtype, context_die); 885450397Sobrien add_AT_die_ref (type_die, DW_AT_containing_type, 885550397Sobrien lookup_type_die (vtype)); 885650397Sobrien } 885750397Sobrien } 885850397Sobrien else 885950397Sobrien add_AT_flag (type_die, DW_AT_declaration, 1); 886050397Sobrien} 886150397Sobrien 886250397Sobrien/* Generate a DIE for a subroutine _type_. */ 886350397Sobrien 886450397Sobrienstatic void 886550397Sobriengen_subroutine_type_die (type, context_die) 886650397Sobrien register tree type; 886750397Sobrien register dw_die_ref context_die; 886850397Sobrien{ 886950397Sobrien register tree return_type = TREE_TYPE (type); 887050397Sobrien register dw_die_ref subr_die 887150397Sobrien = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die)); 887250397Sobrien 887350397Sobrien equate_type_number_to_die (type, subr_die); 887450397Sobrien add_prototyped_attribute (subr_die, type); 887550397Sobrien add_type_attribute (subr_die, return_type, 0, 0, context_die); 887650397Sobrien gen_formal_types_die (type, subr_die); 887750397Sobrien} 887850397Sobrien 887950397Sobrien/* Generate a DIE for a type definition */ 888050397Sobrien 888150397Sobrienstatic void 888250397Sobriengen_typedef_die (decl, context_die) 888350397Sobrien register tree decl; 888450397Sobrien register dw_die_ref context_die; 888550397Sobrien{ 888650397Sobrien register dw_die_ref type_die; 888750397Sobrien register tree origin; 888850397Sobrien 888950397Sobrien if (TREE_ASM_WRITTEN (decl)) 889050397Sobrien return; 889150397Sobrien TREE_ASM_WRITTEN (decl) = 1; 889250397Sobrien 889350397Sobrien type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die)); 889450397Sobrien origin = decl_ultimate_origin (decl); 889550397Sobrien if (origin != NULL) 889650397Sobrien add_abstract_origin_attribute (type_die, origin); 889750397Sobrien else 889850397Sobrien { 889950397Sobrien register tree type; 890050397Sobrien add_name_and_src_coords_attributes (type_die, decl); 890150397Sobrien if (DECL_ORIGINAL_TYPE (decl)) 890250397Sobrien { 890350397Sobrien type = DECL_ORIGINAL_TYPE (decl); 890450397Sobrien equate_type_number_to_die (TREE_TYPE (decl), type_die); 890550397Sobrien } 890650397Sobrien else 890750397Sobrien type = TREE_TYPE (decl); 890850397Sobrien add_type_attribute (type_die, type, TREE_READONLY (decl), 890950397Sobrien TREE_THIS_VOLATILE (decl), context_die); 891050397Sobrien } 891150397Sobrien 891250397Sobrien if (DECL_ABSTRACT (decl)) 891350397Sobrien equate_decl_number_to_die (decl, type_die); 891450397Sobrien} 891550397Sobrien 891650397Sobrien/* Generate a type description DIE. */ 891750397Sobrien 891850397Sobrienstatic void 891950397Sobriengen_type_die (type, context_die) 892050397Sobrien register tree type; 892150397Sobrien register dw_die_ref context_die; 892250397Sobrien{ 892350397Sobrien if (type == NULL_TREE || type == error_mark_node) 892450397Sobrien return; 892550397Sobrien 892650397Sobrien /* We are going to output a DIE to represent the unqualified version of 892750397Sobrien this type (i.e. without any const or volatile qualifiers) so get the 892850397Sobrien main variant (i.e. the unqualified version) of this type now. */ 892950397Sobrien type = type_main_variant (type); 893050397Sobrien 893150397Sobrien if (TREE_ASM_WRITTEN (type)) 893250397Sobrien return; 893350397Sobrien 893450397Sobrien if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL 893550397Sobrien && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) 893650397Sobrien { 893750397Sobrien TREE_ASM_WRITTEN (type) = 1; 893850397Sobrien gen_decl_die (TYPE_NAME (type), context_die); 893950397Sobrien return; 894050397Sobrien } 894150397Sobrien 894250397Sobrien switch (TREE_CODE (type)) 894350397Sobrien { 894450397Sobrien case ERROR_MARK: 894550397Sobrien break; 894650397Sobrien 894750397Sobrien case POINTER_TYPE: 894850397Sobrien case REFERENCE_TYPE: 894950397Sobrien /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This 895050397Sobrien ensures that the gen_type_die recursion will terminate even if the 895150397Sobrien type is recursive. Recursive types are possible in Ada. */ 895250397Sobrien /* ??? We could perhaps do this for all types before the switch 895350397Sobrien statement. */ 895450397Sobrien TREE_ASM_WRITTEN (type) = 1; 895550397Sobrien 895650397Sobrien /* For these types, all that is required is that we output a DIE (or a 895750397Sobrien set of DIEs) to represent the "basis" type. */ 895850397Sobrien gen_type_die (TREE_TYPE (type), context_die); 895950397Sobrien break; 896050397Sobrien 896150397Sobrien case OFFSET_TYPE: 896250397Sobrien /* This code is used for C++ pointer-to-data-member types. 896350397Sobrien Output a description of the relevant class type. */ 896450397Sobrien gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die); 896550397Sobrien 896650397Sobrien /* Output a description of the type of the object pointed to. */ 896750397Sobrien gen_type_die (TREE_TYPE (type), context_die); 896850397Sobrien 896950397Sobrien /* Now output a DIE to represent this pointer-to-data-member type 897050397Sobrien itself. */ 897150397Sobrien gen_ptr_to_mbr_type_die (type, context_die); 897250397Sobrien break; 897350397Sobrien 897450397Sobrien case SET_TYPE: 897550397Sobrien gen_type_die (TYPE_DOMAIN (type), context_die); 897650397Sobrien gen_set_type_die (type, context_die); 897750397Sobrien break; 897850397Sobrien 897950397Sobrien case FILE_TYPE: 898050397Sobrien gen_type_die (TREE_TYPE (type), context_die); 898150397Sobrien abort (); /* No way to represent these in Dwarf yet! */ 898250397Sobrien break; 898350397Sobrien 898450397Sobrien case FUNCTION_TYPE: 898550397Sobrien /* Force out return type (in case it wasn't forced out already). */ 898650397Sobrien gen_type_die (TREE_TYPE (type), context_die); 898750397Sobrien gen_subroutine_type_die (type, context_die); 898850397Sobrien break; 898950397Sobrien 899050397Sobrien case METHOD_TYPE: 899150397Sobrien /* Force out return type (in case it wasn't forced out already). */ 899250397Sobrien gen_type_die (TREE_TYPE (type), context_die); 899350397Sobrien gen_subroutine_type_die (type, context_die); 899450397Sobrien break; 899550397Sobrien 899650397Sobrien case ARRAY_TYPE: 899750397Sobrien if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE) 899850397Sobrien { 899950397Sobrien gen_type_die (TREE_TYPE (type), context_die); 900050397Sobrien gen_string_type_die (type, context_die); 900150397Sobrien } 900250397Sobrien else 900350397Sobrien gen_array_type_die (type, context_die); 900450397Sobrien break; 900550397Sobrien 900650397Sobrien case ENUMERAL_TYPE: 900750397Sobrien case RECORD_TYPE: 900850397Sobrien case UNION_TYPE: 900950397Sobrien case QUAL_UNION_TYPE: 901050397Sobrien /* If this is a nested type whose containing class hasn't been 901150397Sobrien written out yet, writing it out will cover this one, too. */ 901250397Sobrien if (TYPE_CONTEXT (type) 901350397Sobrien && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't' 901450397Sobrien && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) 901550397Sobrien { 901650397Sobrien gen_type_die (TYPE_CONTEXT (type), context_die); 901750397Sobrien 901850397Sobrien if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) 901950397Sobrien return; 902050397Sobrien 902150397Sobrien /* If that failed, attach ourselves to the stub. */ 902250397Sobrien push_decl_scope (TYPE_CONTEXT (type)); 902350397Sobrien context_die = lookup_type_die (TYPE_CONTEXT (type)); 902450397Sobrien } 902550397Sobrien 902650397Sobrien if (TREE_CODE (type) == ENUMERAL_TYPE) 902750397Sobrien gen_enumeration_type_die (type, context_die); 902850397Sobrien else 902950397Sobrien gen_struct_or_union_type_die (type, context_die); 903050397Sobrien 903150397Sobrien if (TYPE_CONTEXT (type) 903250397Sobrien && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't' 903350397Sobrien && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) 903450397Sobrien pop_decl_scope (); 903550397Sobrien 903650397Sobrien /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix 903750397Sobrien it up if it is ever completed. gen_*_type_die will set it for us 903850397Sobrien when appropriate. */ 903950397Sobrien return; 904050397Sobrien 904150397Sobrien case VOID_TYPE: 904250397Sobrien case INTEGER_TYPE: 904350397Sobrien case REAL_TYPE: 904450397Sobrien case COMPLEX_TYPE: 904550397Sobrien case BOOLEAN_TYPE: 904650397Sobrien case CHAR_TYPE: 904750397Sobrien /* No DIEs needed for fundamental types. */ 904850397Sobrien break; 904950397Sobrien 905050397Sobrien case LANG_TYPE: 905150397Sobrien /* No Dwarf representation currently defined. */ 905250397Sobrien break; 905350397Sobrien 905450397Sobrien default: 905550397Sobrien abort (); 905650397Sobrien } 905750397Sobrien 905850397Sobrien TREE_ASM_WRITTEN (type) = 1; 905950397Sobrien} 906050397Sobrien 906150397Sobrien/* Generate a DIE for a tagged type instantiation. */ 906250397Sobrien 906350397Sobrienstatic void 906450397Sobriengen_tagged_type_instantiation_die (type, context_die) 906550397Sobrien register tree type; 906650397Sobrien register dw_die_ref context_die; 906750397Sobrien{ 906850397Sobrien if (type == NULL_TREE || type == error_mark_node) 906950397Sobrien return; 907050397Sobrien 907150397Sobrien /* We are going to output a DIE to represent the unqualified version of 907250397Sobrien this type (i.e. without any const or volatile qualifiers) so make sure 907350397Sobrien that we have the main variant (i.e. the unqualified version) of this 907450397Sobrien type now. */ 907550397Sobrien if (type != type_main_variant (type) 907650397Sobrien || !TREE_ASM_WRITTEN (type)) 907750397Sobrien abort (); 907850397Sobrien 907950397Sobrien switch (TREE_CODE (type)) 908050397Sobrien { 908150397Sobrien case ERROR_MARK: 908250397Sobrien break; 908350397Sobrien 908450397Sobrien case ENUMERAL_TYPE: 908550397Sobrien gen_inlined_enumeration_type_die (type, context_die); 908650397Sobrien break; 908750397Sobrien 908850397Sobrien case RECORD_TYPE: 908950397Sobrien gen_inlined_structure_type_die (type, context_die); 909050397Sobrien break; 909150397Sobrien 909250397Sobrien case UNION_TYPE: 909350397Sobrien case QUAL_UNION_TYPE: 909450397Sobrien gen_inlined_union_type_die (type, context_die); 909550397Sobrien break; 909650397Sobrien 909750397Sobrien default: 909850397Sobrien abort (); 909950397Sobrien } 910050397Sobrien} 910150397Sobrien 910250397Sobrien/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the 910350397Sobrien things which are local to the given block. */ 910450397Sobrien 910550397Sobrienstatic void 910650397Sobriengen_block_die (stmt, context_die, depth) 910750397Sobrien register tree stmt; 910850397Sobrien register dw_die_ref context_die; 910950397Sobrien int depth; 911050397Sobrien{ 911150397Sobrien register int must_output_die = 0; 911250397Sobrien register tree origin; 911350397Sobrien register tree decl; 911450397Sobrien register enum tree_code origin_code; 911550397Sobrien 911650397Sobrien /* Ignore blocks never really used to make RTL. */ 911750397Sobrien 911850397Sobrien if (stmt == NULL_TREE || !TREE_USED (stmt)) 911950397Sobrien return; 912050397Sobrien 912150397Sobrien /* Determine the "ultimate origin" of this block. This block may be an 912250397Sobrien inlined instance of an inlined instance of inline function, so we have 912350397Sobrien to trace all of the way back through the origin chain to find out what 912450397Sobrien sort of node actually served as the original seed for the creation of 912550397Sobrien the current block. */ 912650397Sobrien origin = block_ultimate_origin (stmt); 912750397Sobrien origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK; 912850397Sobrien 912950397Sobrien /* Determine if we need to output any Dwarf DIEs at all to represent this 913050397Sobrien block. */ 913150397Sobrien if (origin_code == FUNCTION_DECL) 913250397Sobrien /* The outer scopes for inlinings *must* always be represented. We 913350397Sobrien generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */ 913450397Sobrien must_output_die = 1; 913550397Sobrien else 913650397Sobrien { 913750397Sobrien /* In the case where the current block represents an inlining of the 913850397Sobrien "body block" of an inline function, we must *NOT* output any DIE for 913950397Sobrien this block because we have already output a DIE to represent the 914050397Sobrien whole inlined function scope and the "body block" of any function 914150397Sobrien doesn't really represent a different scope according to ANSI C 914250397Sobrien rules. So we check here to make sure that this block does not 914350397Sobrien represent a "body block inlining" before trying to set the 914450397Sobrien `must_output_die' flag. */ 914550397Sobrien if (! is_body_block (origin ? origin : stmt)) 914650397Sobrien { 914750397Sobrien /* Determine if this block directly contains any "significant" 914850397Sobrien local declarations which we will need to output DIEs for. */ 914950397Sobrien if (debug_info_level > DINFO_LEVEL_TERSE) 915050397Sobrien /* We are not in terse mode so *any* local declaration counts 915150397Sobrien as being a "significant" one. */ 915250397Sobrien must_output_die = (BLOCK_VARS (stmt) != NULL); 915350397Sobrien else 915450397Sobrien /* We are in terse mode, so only local (nested) function 915550397Sobrien definitions count as "significant" local declarations. */ 915650397Sobrien for (decl = BLOCK_VARS (stmt); 915750397Sobrien decl != NULL; decl = TREE_CHAIN (decl)) 915850397Sobrien if (TREE_CODE (decl) == FUNCTION_DECL 915950397Sobrien && DECL_INITIAL (decl)) 916050397Sobrien { 916150397Sobrien must_output_die = 1; 916250397Sobrien break; 916350397Sobrien } 916450397Sobrien } 916550397Sobrien } 916650397Sobrien 916750397Sobrien /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block 916850397Sobrien DIE for any block which contains no significant local declarations at 916950397Sobrien all. Rather, in such cases we just call `decls_for_scope' so that any 917050397Sobrien needed Dwarf info for any sub-blocks will get properly generated. Note 917150397Sobrien that in terse mode, our definition of what constitutes a "significant" 917250397Sobrien local declaration gets restricted to include only inlined function 917350397Sobrien instances and local (nested) function definitions. */ 917450397Sobrien if (must_output_die) 917550397Sobrien { 917650397Sobrien if (origin_code == FUNCTION_DECL) 917750397Sobrien gen_inlined_subroutine_die (stmt, context_die, depth); 917850397Sobrien else 917950397Sobrien gen_lexical_block_die (stmt, context_die, depth); 918050397Sobrien } 918150397Sobrien else 918250397Sobrien decls_for_scope (stmt, context_die, depth); 918350397Sobrien} 918450397Sobrien 918550397Sobrien/* Generate all of the decls declared within a given scope and (recursively) 918650397Sobrien all of its sub-blocks. */ 918750397Sobrien 918850397Sobrienstatic void 918950397Sobriendecls_for_scope (stmt, context_die, depth) 919050397Sobrien register tree stmt; 919150397Sobrien register dw_die_ref context_die; 919250397Sobrien int depth; 919350397Sobrien{ 919450397Sobrien register tree decl; 919550397Sobrien register tree subblocks; 919650397Sobrien 919750397Sobrien /* Ignore blocks never really used to make RTL. */ 919850397Sobrien if (stmt == NULL_TREE || ! TREE_USED (stmt)) 919950397Sobrien return; 920050397Sobrien 920150397Sobrien if (!BLOCK_ABSTRACT (stmt) && depth > 0) 920250397Sobrien next_block_number++; 920350397Sobrien 920450397Sobrien /* Output the DIEs to represent all of the data objects and typedefs 920550397Sobrien declared directly within this block but not within any nested 920650397Sobrien sub-blocks. Also, nested function and tag DIEs have been 920750397Sobrien generated with a parent of NULL; fix that up now. */ 920850397Sobrien for (decl = BLOCK_VARS (stmt); 920950397Sobrien decl != NULL; decl = TREE_CHAIN (decl)) 921050397Sobrien { 921150397Sobrien register dw_die_ref die; 921250397Sobrien 921350397Sobrien if (TREE_CODE (decl) == FUNCTION_DECL) 921450397Sobrien die = lookup_decl_die (decl); 921550397Sobrien else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)) 921650397Sobrien die = lookup_type_die (TREE_TYPE (decl)); 921750397Sobrien else 921850397Sobrien die = NULL; 921950397Sobrien 922050397Sobrien if (die != NULL && die->die_parent == NULL) 922150397Sobrien add_child_die (context_die, die); 922250397Sobrien else 922350397Sobrien gen_decl_die (decl, context_die); 922450397Sobrien } 922550397Sobrien 922650397Sobrien /* Output the DIEs to represent all sub-blocks (and the items declared 922750397Sobrien therein) of this block. */ 922850397Sobrien for (subblocks = BLOCK_SUBBLOCKS (stmt); 922950397Sobrien subblocks != NULL; 923050397Sobrien subblocks = BLOCK_CHAIN (subblocks)) 923150397Sobrien gen_block_die (subblocks, context_die, depth + 1); 923250397Sobrien} 923350397Sobrien 923450397Sobrien/* Is this a typedef we can avoid emitting? */ 923550397Sobrien 923650397Sobrienstatic inline int 923750397Sobrienis_redundant_typedef (decl) 923850397Sobrien register tree decl; 923950397Sobrien{ 924050397Sobrien if (TYPE_DECL_IS_STUB (decl)) 924150397Sobrien return 1; 924250397Sobrien 924350397Sobrien if (DECL_ARTIFICIAL (decl) 924450397Sobrien && DECL_CONTEXT (decl) 924550397Sobrien && is_tagged_type (DECL_CONTEXT (decl)) 924650397Sobrien && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL 924750397Sobrien && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)))) 924850397Sobrien /* Also ignore the artificial member typedef for the class name. */ 924950397Sobrien return 1; 925050397Sobrien 925150397Sobrien return 0; 925250397Sobrien} 925350397Sobrien 925450397Sobrien/* Generate Dwarf debug information for a decl described by DECL. */ 925550397Sobrien 925650397Sobrienstatic void 925750397Sobriengen_decl_die (decl, context_die) 925850397Sobrien register tree decl; 925950397Sobrien register dw_die_ref context_die; 926050397Sobrien{ 926150397Sobrien register tree origin; 926250397Sobrien 926350397Sobrien /* Make a note of the decl node we are going to be working on. We may need 926450397Sobrien to give the user the source coordinates of where it appeared in case we 926550397Sobrien notice (later on) that something about it looks screwy. */ 926650397Sobrien dwarf_last_decl = decl; 926750397Sobrien 926850397Sobrien if (TREE_CODE (decl) == ERROR_MARK) 926950397Sobrien return; 927050397Sobrien 927150397Sobrien /* If this ..._DECL node is marked to be ignored, then ignore it. But don't 927250397Sobrien ignore a function definition, since that would screw up our count of 927350397Sobrien blocks, and that in turn will completely screw up the labels we will 927450397Sobrien reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for 927550397Sobrien subsequent blocks). */ 927650397Sobrien if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL) 927750397Sobrien return; 927850397Sobrien 927950397Sobrien switch (TREE_CODE (decl)) 928050397Sobrien { 928150397Sobrien case CONST_DECL: 928250397Sobrien /* The individual enumerators of an enum type get output when we output 928350397Sobrien the Dwarf representation of the relevant enum type itself. */ 928450397Sobrien break; 928550397Sobrien 928650397Sobrien case FUNCTION_DECL: 928750397Sobrien /* Don't output any DIEs to represent mere function declarations, 928850397Sobrien unless they are class members or explicit block externs. */ 928950397Sobrien if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE 929050397Sobrien && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl))) 929150397Sobrien break; 929250397Sobrien 929350397Sobrien if (debug_info_level > DINFO_LEVEL_TERSE) 929450397Sobrien { 929550397Sobrien /* Before we describe the FUNCTION_DECL itself, make sure that we 929650397Sobrien have described its return type. */ 929750397Sobrien gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die); 929850397Sobrien 929950397Sobrien /* And its containing type. */ 930050397Sobrien origin = decl_class_context (decl); 930150397Sobrien if (origin != NULL_TREE) 930250397Sobrien gen_type_die (origin, context_die); 930350397Sobrien 930450397Sobrien /* And its virtual context. */ 930550397Sobrien if (DECL_VINDEX (decl) != NULL_TREE) 930650397Sobrien gen_type_die (DECL_CONTEXT (decl), context_die); 930750397Sobrien } 930850397Sobrien 930950397Sobrien /* Now output a DIE to represent the function itself. */ 931050397Sobrien gen_subprogram_die (decl, context_die); 931150397Sobrien break; 931250397Sobrien 931350397Sobrien case TYPE_DECL: 931450397Sobrien /* If we are in terse mode, don't generate any DIEs to represent any 931550397Sobrien actual typedefs. */ 931650397Sobrien if (debug_info_level <= DINFO_LEVEL_TERSE) 931750397Sobrien break; 931850397Sobrien 931950397Sobrien /* In the special case of a TYPE_DECL node representing the 932050397Sobrien declaration of some type tag, if the given TYPE_DECL is marked as 932150397Sobrien having been instantiated from some other (original) TYPE_DECL node 932250397Sobrien (e.g. one which was generated within the original definition of an 932350397Sobrien inline function) we have to generate a special (abbreviated) 932450397Sobrien DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration_type 932550397Sobrien DIE here. */ 932650397Sobrien if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) 932750397Sobrien { 932850397Sobrien gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die); 932950397Sobrien break; 933050397Sobrien } 933150397Sobrien 933250397Sobrien if (is_redundant_typedef (decl)) 933350397Sobrien gen_type_die (TREE_TYPE (decl), context_die); 933450397Sobrien else 933550397Sobrien /* Output a DIE to represent the typedef itself. */ 933650397Sobrien gen_typedef_die (decl, context_die); 933750397Sobrien break; 933850397Sobrien 933950397Sobrien case LABEL_DECL: 934050397Sobrien if (debug_info_level >= DINFO_LEVEL_NORMAL) 934150397Sobrien gen_label_die (decl, context_die); 934250397Sobrien break; 934350397Sobrien 934450397Sobrien case VAR_DECL: 934550397Sobrien /* If we are in terse mode, don't generate any DIEs to represent any 934650397Sobrien variable declarations or definitions. */ 934750397Sobrien if (debug_info_level <= DINFO_LEVEL_TERSE) 934850397Sobrien break; 934950397Sobrien 935050397Sobrien /* Output any DIEs that are needed to specify the type of this data 935150397Sobrien object. */ 935250397Sobrien gen_type_die (TREE_TYPE (decl), context_die); 935350397Sobrien 935450397Sobrien /* And its containing type. */ 935550397Sobrien origin = decl_class_context (decl); 935650397Sobrien if (origin != NULL_TREE) 935750397Sobrien gen_type_die (origin, context_die); 935850397Sobrien 935950397Sobrien /* Now output the DIE to represent the data object itself. This gets 936050397Sobrien complicated because of the possibility that the VAR_DECL really 936150397Sobrien represents an inlined instance of a formal parameter for an inline 936250397Sobrien function. */ 936350397Sobrien origin = decl_ultimate_origin (decl); 936450397Sobrien if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL) 936550397Sobrien gen_formal_parameter_die (decl, context_die); 936650397Sobrien else 936750397Sobrien gen_variable_die (decl, context_die); 936850397Sobrien break; 936950397Sobrien 937050397Sobrien case FIELD_DECL: 937150397Sobrien /* Ignore the nameless fields that are used to skip bits, but 937250397Sobrien handle C++ anonymous unions. */ 937350397Sobrien if (DECL_NAME (decl) != NULL_TREE 937450397Sobrien || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE) 937550397Sobrien { 937650397Sobrien gen_type_die (member_declared_type (decl), context_die); 937750397Sobrien gen_field_die (decl, context_die); 937850397Sobrien } 937950397Sobrien break; 938050397Sobrien 938150397Sobrien case PARM_DECL: 938250397Sobrien gen_type_die (TREE_TYPE (decl), context_die); 938350397Sobrien gen_formal_parameter_die (decl, context_die); 938450397Sobrien break; 938550397Sobrien 938650397Sobrien default: 938750397Sobrien abort (); 938850397Sobrien } 938950397Sobrien} 939050397Sobrien 939150397Sobrien/* Write the debugging output for DECL. */ 939250397Sobrien 939350397Sobrienvoid 939450397Sobriendwarf2out_decl (decl) 939550397Sobrien register tree decl; 939650397Sobrien{ 939750397Sobrien register dw_die_ref context_die = comp_unit_die; 939850397Sobrien 939950397Sobrien if (TREE_CODE (decl) == ERROR_MARK) 940050397Sobrien return; 940150397Sobrien 940250397Sobrien /* If this ..._DECL node is marked to be ignored, then ignore it. We gotta 940350397Sobrien hope that the node in question doesn't represent a function definition. 940450397Sobrien If it does, then totally ignoring it is bound to screw up our count of 940550397Sobrien blocks, and that in turn will completely screw up the labels we will 940650397Sobrien reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for 940750397Sobrien subsequent blocks). (It's too bad that BLOCK nodes don't carry their 940850397Sobrien own sequence numbers with them!) */ 940950397Sobrien if (DECL_IGNORED_P (decl)) 941050397Sobrien { 941150397Sobrien if (TREE_CODE (decl) == FUNCTION_DECL 941250397Sobrien && DECL_INITIAL (decl) != NULL) 941350397Sobrien abort (); 941450397Sobrien 941550397Sobrien return; 941650397Sobrien } 941750397Sobrien 941850397Sobrien switch (TREE_CODE (decl)) 941950397Sobrien { 942050397Sobrien case FUNCTION_DECL: 942150397Sobrien /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a 942250397Sobrien builtin function. Explicit programmer-supplied declarations of 942350397Sobrien these same functions should NOT be ignored however. */ 942450397Sobrien if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl)) 942550397Sobrien return; 942650397Sobrien 942750397Sobrien /* What we would really like to do here is to filter out all mere 942850397Sobrien file-scope declarations of file-scope functions which are never 942950397Sobrien referenced later within this translation unit (and keep all of ones 943050397Sobrien that *are* referenced later on) but we aren't clairvoyant, so we have 943150397Sobrien no idea which functions will be referenced in the future (i.e. later 943250397Sobrien on within the current translation unit). So here we just ignore all 943350397Sobrien file-scope function declarations which are not also definitions. If 943450397Sobrien and when the debugger needs to know something about these functions, 943550397Sobrien it wil have to hunt around and find the DWARF information associated 943650397Sobrien with the definition of the function. Note that we can't just check 943750397Sobrien `DECL_EXTERNAL' to find out which FUNCTION_DECL nodes represent 943850397Sobrien definitions and which ones represent mere declarations. We have to 943950397Sobrien check `DECL_INITIAL' instead. That's because the C front-end 944050397Sobrien supports some weird semantics for "extern inline" function 944150397Sobrien definitions. These can get inlined within the current translation 944250397Sobrien unit (an thus, we need to generate DWARF info for their abstract 944350397Sobrien instances so that the DWARF info for the concrete inlined instances 944450397Sobrien can have something to refer to) but the compiler never generates any 944550397Sobrien out-of-lines instances of such things (despite the fact that they 944650397Sobrien *are* definitions). The important point is that the C front-end 944750397Sobrien marks these "extern inline" functions as DECL_EXTERNAL, but we need 944850397Sobrien to generate DWARF for them anyway. Note that the C++ front-end also 944950397Sobrien plays some similar games for inline function definitions appearing 945050397Sobrien within include files which also contain 945150397Sobrien `#pragma interface' pragmas. */ 945250397Sobrien if (DECL_INITIAL (decl) == NULL_TREE) 945350397Sobrien return; 945450397Sobrien 945550397Sobrien /* If we're a nested function, initially use a parent of NULL; if we're 945650397Sobrien a plain function, this will be fixed up in decls_for_scope. If 945750397Sobrien we're a method, it will be ignored, since we already have a DIE. */ 945850397Sobrien if (decl_function_context (decl)) 945950397Sobrien context_die = NULL; 946050397Sobrien 946150397Sobrien break; 946250397Sobrien 946350397Sobrien case VAR_DECL: 946450397Sobrien /* Ignore this VAR_DECL if it refers to a file-scope extern data object 946550397Sobrien declaration and if the declaration was never even referenced from 946650397Sobrien within this entire compilation unit. We suppress these DIEs in 946750397Sobrien order to save space in the .debug section (by eliminating entries 946850397Sobrien which are probably useless). Note that we must not suppress 946950397Sobrien block-local extern declarations (whether used or not) because that 947050397Sobrien would screw-up the debugger's name lookup mechanism and cause it to 947150397Sobrien miss things which really ought to be in scope at a given point. */ 947250397Sobrien if (DECL_EXTERNAL (decl) && !TREE_USED (decl)) 947350397Sobrien return; 947450397Sobrien 947550397Sobrien /* If we are in terse mode, don't generate any DIEs to represent any 947650397Sobrien variable declarations or definitions. */ 947750397Sobrien if (debug_info_level <= DINFO_LEVEL_TERSE) 947850397Sobrien return; 947950397Sobrien break; 948050397Sobrien 948150397Sobrien case TYPE_DECL: 948250397Sobrien /* Don't bother trying to generate any DIEs to represent any of the 948350397Sobrien normal built-in types for the language we are compiling. */ 948450397Sobrien if (DECL_SOURCE_LINE (decl) == 0) 948550397Sobrien { 948650397Sobrien /* OK, we need to generate one for `bool' so GDB knows what type 948750397Sobrien comparisons have. */ 948850397Sobrien if ((get_AT_unsigned (comp_unit_die, DW_AT_language) 948950397Sobrien == DW_LANG_C_plus_plus) 949050397Sobrien && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE) 949150397Sobrien modified_type_die (TREE_TYPE (decl), 0, 0, NULL); 949250397Sobrien 949350397Sobrien return; 949450397Sobrien } 949550397Sobrien 949650397Sobrien /* If we are in terse mode, don't generate any DIEs for types. */ 949750397Sobrien if (debug_info_level <= DINFO_LEVEL_TERSE) 949850397Sobrien return; 949950397Sobrien 950050397Sobrien /* If we're a function-scope tag, initially use a parent of NULL; 950150397Sobrien this will be fixed up in decls_for_scope. */ 950250397Sobrien if (decl_function_context (decl)) 950350397Sobrien context_die = NULL; 950450397Sobrien 950550397Sobrien break; 950650397Sobrien 950750397Sobrien default: 950850397Sobrien return; 950950397Sobrien } 951050397Sobrien 951150397Sobrien gen_decl_die (decl, context_die); 951250397Sobrien output_pending_types_for_scope (comp_unit_die); 951350397Sobrien} 951450397Sobrien 951550397Sobrien/* Output a marker (i.e. a label) for the beginning of the generated code for 951650397Sobrien a lexical block. */ 951750397Sobrien 951850397Sobrienvoid 951950397Sobriendwarf2out_begin_block (blocknum) 952050397Sobrien register unsigned blocknum; 952150397Sobrien{ 952250397Sobrien function_section (current_function_decl); 952350397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum); 952450397Sobrien} 952550397Sobrien 952650397Sobrien/* Output a marker (i.e. a label) for the end of the generated code for a 952750397Sobrien lexical block. */ 952850397Sobrien 952950397Sobrienvoid 953050397Sobriendwarf2out_end_block (blocknum) 953150397Sobrien register unsigned blocknum; 953250397Sobrien{ 953350397Sobrien function_section (current_function_decl); 953450397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum); 953550397Sobrien} 953650397Sobrien 953750397Sobrien/* Output a marker (i.e. a label) at a point in the assembly code which 953850397Sobrien corresponds to a given source level label. */ 953950397Sobrien 954050397Sobrienvoid 954150397Sobriendwarf2out_label (insn) 954250397Sobrien register rtx insn; 954350397Sobrien{ 954450397Sobrien char label[MAX_ARTIFICIAL_LABEL_BYTES]; 954550397Sobrien 954650397Sobrien if (debug_info_level >= DINFO_LEVEL_NORMAL) 954750397Sobrien { 954850397Sobrien function_section (current_function_decl); 954950397Sobrien sprintf (label, INSN_LABEL_FMT, current_funcdef_number); 955050397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label, 955150397Sobrien (unsigned) INSN_UID (insn)); 955250397Sobrien } 955350397Sobrien} 955450397Sobrien 955550397Sobrien/* Lookup a filename (in the list of filenames that we know about here in 955650397Sobrien dwarf2out.c) and return its "index". The index of each (known) filename is 955750397Sobrien just a unique number which is associated with only that one filename. 955850397Sobrien We need such numbers for the sake of generating labels 955950397Sobrien (in the .debug_sfnames section) and references to those 956050397Sobrien files numbers (in the .debug_srcinfo and.debug_macinfo sections). 956150397Sobrien If the filename given as an argument is not found in our current list, 956250397Sobrien add it to the list and assign it the next available unique index number. 956350397Sobrien In order to speed up searches, we remember the index of the filename 956450397Sobrien was looked up last. This handles the majority of all searches. */ 956550397Sobrien 956650397Sobrienstatic unsigned 956750397Sobrienlookup_filename (file_name) 956850397Sobrien char *file_name; 956950397Sobrien{ 957050397Sobrien static unsigned last_file_lookup_index = 0; 957150397Sobrien register unsigned i; 957250397Sobrien 957350397Sobrien /* Check to see if the file name that was searched on the previous call 957450397Sobrien matches this file name. If so, return the index. */ 957550397Sobrien if (last_file_lookup_index != 0) 957650397Sobrien if (strcmp (file_name, file_table[last_file_lookup_index]) == 0) 957750397Sobrien return last_file_lookup_index; 957850397Sobrien 957950397Sobrien /* Didn't match the previous lookup, search the table */ 958050397Sobrien for (i = 1; i < file_table_in_use; ++i) 958150397Sobrien if (strcmp (file_name, file_table[i]) == 0) 958250397Sobrien { 958350397Sobrien last_file_lookup_index = i; 958450397Sobrien return i; 958550397Sobrien } 958650397Sobrien 958750397Sobrien /* Prepare to add a new table entry by making sure there is enough space in 958850397Sobrien the table to do so. If not, expand the current table. */ 958950397Sobrien if (file_table_in_use == file_table_allocated) 959050397Sobrien { 959150397Sobrien file_table_allocated += FILE_TABLE_INCREMENT; 959250397Sobrien file_table 959350397Sobrien = (char **) xrealloc (file_table, 959450397Sobrien file_table_allocated * sizeof (char *)); 959550397Sobrien } 959650397Sobrien 959750397Sobrien /* Add the new entry to the end of the filename table. */ 959850397Sobrien file_table[file_table_in_use] = xstrdup (file_name); 959950397Sobrien last_file_lookup_index = file_table_in_use++; 960050397Sobrien 960150397Sobrien return last_file_lookup_index; 960250397Sobrien} 960350397Sobrien 960450397Sobrien/* Output a label to mark the beginning of a source code line entry 960550397Sobrien and record information relating to this source line, in 960650397Sobrien 'line_info_table' for later output of the .debug_line section. */ 960750397Sobrien 960850397Sobrienvoid 960950397Sobriendwarf2out_line (filename, line) 961050397Sobrien register char *filename; 961150397Sobrien register unsigned line; 961250397Sobrien{ 961350397Sobrien if (debug_info_level >= DINFO_LEVEL_NORMAL) 961450397Sobrien { 961550397Sobrien function_section (current_function_decl); 961650397Sobrien 961750397Sobrien if (DECL_SECTION_NAME (current_function_decl)) 961850397Sobrien { 961950397Sobrien register dw_separate_line_info_ref line_info; 962050397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL, 962150397Sobrien separate_line_info_table_in_use); 962250397Sobrien fputc ('\n', asm_out_file); 962350397Sobrien 962450397Sobrien /* expand the line info table if necessary */ 962550397Sobrien if (separate_line_info_table_in_use 962650397Sobrien == separate_line_info_table_allocated) 962750397Sobrien { 962850397Sobrien separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; 962950397Sobrien separate_line_info_table 963050397Sobrien = (dw_separate_line_info_ref) 963150397Sobrien xrealloc (separate_line_info_table, 963250397Sobrien separate_line_info_table_allocated 963350397Sobrien * sizeof (dw_separate_line_info_entry)); 963450397Sobrien } 963550397Sobrien 963650397Sobrien /* Add the new entry at the end of the line_info_table. */ 963750397Sobrien line_info 963850397Sobrien = &separate_line_info_table[separate_line_info_table_in_use++]; 963950397Sobrien line_info->dw_file_num = lookup_filename (filename); 964050397Sobrien line_info->dw_line_num = line; 964150397Sobrien line_info->function = current_funcdef_number; 964250397Sobrien } 964350397Sobrien else 964450397Sobrien { 964550397Sobrien register dw_line_info_ref line_info; 964650397Sobrien 964750397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL, 964850397Sobrien line_info_table_in_use); 964950397Sobrien fputc ('\n', asm_out_file); 965050397Sobrien 965150397Sobrien /* Expand the line info table if necessary. */ 965250397Sobrien if (line_info_table_in_use == line_info_table_allocated) 965350397Sobrien { 965450397Sobrien line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; 965550397Sobrien line_info_table 965650397Sobrien = (dw_line_info_ref) 965750397Sobrien xrealloc (line_info_table, 965850397Sobrien (line_info_table_allocated 965950397Sobrien * sizeof (dw_line_info_entry))); 966050397Sobrien } 966150397Sobrien 966250397Sobrien /* Add the new entry at the end of the line_info_table. */ 966350397Sobrien line_info = &line_info_table[line_info_table_in_use++]; 966450397Sobrien line_info->dw_file_num = lookup_filename (filename); 966550397Sobrien line_info->dw_line_num = line; 966650397Sobrien } 966750397Sobrien } 966850397Sobrien} 966950397Sobrien 967050397Sobrien/* Record the beginning of a new source file, for later output 967150397Sobrien of the .debug_macinfo section. At present, unimplemented. */ 967250397Sobrien 967350397Sobrienvoid 967450397Sobriendwarf2out_start_source_file (filename) 967550397Sobrien register char *filename ATTRIBUTE_UNUSED; 967650397Sobrien{ 967750397Sobrien} 967850397Sobrien 967950397Sobrien/* Record the end of a source file, for later output 968050397Sobrien of the .debug_macinfo section. At present, unimplemented. */ 968150397Sobrien 968250397Sobrienvoid 968350397Sobriendwarf2out_end_source_file () 968450397Sobrien{ 968550397Sobrien} 968650397Sobrien 968750397Sobrien/* Called from check_newline in c-parse.y. The `buffer' parameter contains 968850397Sobrien the tail part of the directive line, i.e. the part which is past the 968950397Sobrien initial whitespace, #, whitespace, directive-name, whitespace part. */ 969050397Sobrien 969150397Sobrienvoid 969250397Sobriendwarf2out_define (lineno, buffer) 969350397Sobrien register unsigned lineno; 969450397Sobrien register char *buffer; 969550397Sobrien{ 969650397Sobrien static int initialized = 0; 969750397Sobrien if (!initialized) 969850397Sobrien { 969950397Sobrien dwarf2out_start_source_file (primary_filename); 970050397Sobrien initialized = 1; 970150397Sobrien } 970250397Sobrien} 970350397Sobrien 970450397Sobrien/* Called from check_newline in c-parse.y. The `buffer' parameter contains 970550397Sobrien the tail part of the directive line, i.e. the part which is past the 970650397Sobrien initial whitespace, #, whitespace, directive-name, whitespace part. */ 970750397Sobrien 970850397Sobrienvoid 970950397Sobriendwarf2out_undef (lineno, buffer) 971050397Sobrien register unsigned lineno ATTRIBUTE_UNUSED; 971150397Sobrien register char *buffer ATTRIBUTE_UNUSED; 971250397Sobrien{ 971350397Sobrien} 971450397Sobrien 971550397Sobrien/* Set up for Dwarf output at the start of compilation. */ 971650397Sobrien 971750397Sobrienvoid 971850397Sobriendwarf2out_init (asm_out_file, main_input_filename) 971950397Sobrien register FILE *asm_out_file; 972050397Sobrien register char *main_input_filename; 972150397Sobrien{ 972250397Sobrien /* Remember the name of the primary input file. */ 972350397Sobrien primary_filename = main_input_filename; 972450397Sobrien 972550397Sobrien /* Allocate the initial hunk of the file_table. */ 972650397Sobrien file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *)); 972750397Sobrien bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *)); 972850397Sobrien file_table_allocated = FILE_TABLE_INCREMENT; 972950397Sobrien 973050397Sobrien /* Skip the first entry - file numbers begin at 1. */ 973150397Sobrien file_table_in_use = 1; 973250397Sobrien 973350397Sobrien /* Allocate the initial hunk of the decl_die_table. */ 973450397Sobrien decl_die_table 973550397Sobrien = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); 973650397Sobrien bzero ((char *) decl_die_table, 973750397Sobrien DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); 973850397Sobrien decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT; 973950397Sobrien decl_die_table_in_use = 0; 974050397Sobrien 974150397Sobrien /* Allocate the initial hunk of the decl_scope_table. */ 974250397Sobrien decl_scope_table 974350397Sobrien = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT 974450397Sobrien * sizeof (decl_scope_node)); 974550397Sobrien bzero ((char *) decl_scope_table, 974650397Sobrien DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node)); 974750397Sobrien decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT; 974850397Sobrien decl_scope_depth = 0; 974950397Sobrien 975050397Sobrien /* Allocate the initial hunk of the abbrev_die_table. */ 975150397Sobrien abbrev_die_table 975250397Sobrien = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT 975350397Sobrien * sizeof (dw_die_ref)); 975450397Sobrien bzero ((char *) abbrev_die_table, 975550397Sobrien ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); 975650397Sobrien abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT; 975750397Sobrien /* Zero-th entry is allocated, but unused */ 975850397Sobrien abbrev_die_table_in_use = 1; 975950397Sobrien 976050397Sobrien /* Allocate the initial hunk of the line_info_table. */ 976150397Sobrien line_info_table 976250397Sobrien = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT 976350397Sobrien * sizeof (dw_line_info_entry)); 976450397Sobrien bzero ((char *) line_info_table, 976550397Sobrien LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry)); 976650397Sobrien line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; 976750397Sobrien /* Zero-th entry is allocated, but unused */ 976850397Sobrien line_info_table_in_use = 1; 976950397Sobrien 977050397Sobrien /* Generate the initial DIE for the .debug section. Note that the (string) 977150397Sobrien value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE 977250397Sobrien will (typically) be a relative pathname and that this pathname should be 977350397Sobrien taken as being relative to the directory from which the compiler was 977450397Sobrien invoked when the given (base) source file was compiled. */ 977550397Sobrien gen_compile_unit_die (main_input_filename); 977650397Sobrien 977750397Sobrien ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0); 977850397Sobrien} 977950397Sobrien 978050397Sobrien/* Output stuff that dwarf requires at the end of every file, 978150397Sobrien and generate the DWARF-2 debugging info. */ 978250397Sobrien 978350397Sobrienvoid 978450397Sobriendwarf2out_finish () 978550397Sobrien{ 978650397Sobrien limbo_die_node *node, *next_node; 978750397Sobrien dw_die_ref die; 978850397Sobrien dw_attr_ref a; 978950397Sobrien 979050397Sobrien /* Traverse the limbo die list, and add parent/child links. The only 979150397Sobrien dies without parents that should be here are concrete instances of 979250397Sobrien inline functions, and the comp_unit_die. We can ignore the comp_unit_die. 979350397Sobrien For concrete instances, we can get the parent die from the abstract 979450397Sobrien instance. */ 979550397Sobrien for (node = limbo_die_list; node; node = next_node) 979650397Sobrien { 979750397Sobrien next_node = node->next; 979850397Sobrien die = node->die; 979950397Sobrien 980050397Sobrien if (die->die_parent == NULL) 980150397Sobrien { 980250397Sobrien a = get_AT (die, DW_AT_abstract_origin); 980350397Sobrien if (a) 980450397Sobrien add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die); 980550397Sobrien else if (die == comp_unit_die) 980650397Sobrien ; 980750397Sobrien else 980850397Sobrien abort (); 980950397Sobrien } 981050397Sobrien free (node); 981150397Sobrien } 981250397Sobrien 981350397Sobrien /* Traverse the DIE tree and add sibling attributes to those DIE's 981450397Sobrien that have children. */ 981550397Sobrien add_sibling_attributes (comp_unit_die); 981650397Sobrien 981750397Sobrien /* Output a terminator label for the .text section. */ 981850397Sobrien fputc ('\n', asm_out_file); 981950397Sobrien ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION); 982050397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0); 982150397Sobrien 982250397Sobrien#if 0 982350397Sobrien /* Output a terminator label for the .data section. */ 982450397Sobrien fputc ('\n', asm_out_file); 982550397Sobrien ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION); 982650397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0); 982750397Sobrien 982850397Sobrien /* Output a terminator label for the .bss section. */ 982950397Sobrien fputc ('\n', asm_out_file); 983050397Sobrien ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION); 983150397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0); 983250397Sobrien#endif 983350397Sobrien 983450397Sobrien /* Output the source line correspondence table. */ 983550397Sobrien if (line_info_table_in_use > 1 || separate_line_info_table_in_use) 983650397Sobrien { 983750397Sobrien fputc ('\n', asm_out_file); 983850397Sobrien ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION); 983950397Sobrien output_line_info (); 984050397Sobrien 984150397Sobrien /* We can only use the low/high_pc attributes if all of the code 984250397Sobrien was in .text. */ 984350397Sobrien if (separate_line_info_table_in_use == 0) 984450397Sobrien { 984550397Sobrien add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, TEXT_SECTION); 984650397Sobrien add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label); 984750397Sobrien } 984850397Sobrien 984950397Sobrien add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION); 985050397Sobrien } 985150397Sobrien 985250397Sobrien /* Output the abbreviation table. */ 985350397Sobrien fputc ('\n', asm_out_file); 985450397Sobrien ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION); 985550397Sobrien build_abbrev_table (comp_unit_die); 985650397Sobrien output_abbrev_section (); 985750397Sobrien 985850397Sobrien /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ 985950397Sobrien next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; 986050397Sobrien calc_die_sizes (comp_unit_die); 986150397Sobrien 986250397Sobrien /* Output debugging information. */ 986350397Sobrien fputc ('\n', asm_out_file); 986450397Sobrien ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION); 986550397Sobrien output_compilation_unit_header (); 986650397Sobrien output_die (comp_unit_die); 986750397Sobrien 986850397Sobrien if (pubname_table_in_use) 986950397Sobrien { 987050397Sobrien /* Output public names table. */ 987150397Sobrien fputc ('\n', asm_out_file); 987250397Sobrien ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION); 987350397Sobrien output_pubnames (); 987450397Sobrien } 987550397Sobrien 987650397Sobrien if (fde_table_in_use) 987750397Sobrien { 987850397Sobrien /* Output the address range information. */ 987950397Sobrien fputc ('\n', asm_out_file); 988050397Sobrien ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION); 988150397Sobrien output_aranges (); 988250397Sobrien } 988350397Sobrien} 988450397Sobrien#endif /* DWARF2_DEBUGGING_INFO */ 9885