📄 dwarfout.c
字号:
return FT_void; case INTEGER_TYPE: /* Carefully distinguish all the standard types of C, without messing up if the language is not C. Note that we check only for the names that contain spaces; other names might occur by coincidence in other languages. */ if (TYPE_NAME (type) != 0 && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && DECL_NAME (TYPE_NAME (type)) != 0 && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE) { char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); if (!strcmp (name, "unsigned char")) return FT_unsigned_char; if (!strcmp (name, "signed char")) return FT_signed_char; if (!strcmp (name, "unsigned int")) return FT_unsigned_integer; if (!strcmp (name, "short int")) return FT_short; if (!strcmp (name, "short unsigned int")) return FT_unsigned_short; if (!strcmp (name, "long int")) return FT_long; if (!strcmp (name, "long unsigned int")) return FT_unsigned_long; if (!strcmp (name, "long long int")) return FT_long_long; /* Not grok'ed by svr4 SDB */ if (!strcmp (name, "long long unsigned int")) return FT_unsigned_long_long; /* Not grok'ed by svr4 SDB */ } /* Most integer types will be sorted out above, however, for the sake of special `array index' integer types, the following code is also provided. */ if (TYPE_PRECISION (type) == INT_TYPE_SIZE) return (TREE_UNSIGNED (type) ? FT_unsigned_integer : FT_integer); if (TYPE_PRECISION (type) == LONG_TYPE_SIZE) return (TREE_UNSIGNED (type) ? FT_unsigned_long : FT_long); if (TYPE_PRECISION (type) == LONG_LONG_TYPE_SIZE) return (TREE_UNSIGNED (type) ? FT_unsigned_long_long : FT_long_long); if (TYPE_PRECISION (type) == SHORT_TYPE_SIZE) return (TREE_UNSIGNED (type) ? FT_unsigned_short : FT_short); if (TYPE_PRECISION (type) == CHAR_TYPE_SIZE) return (TREE_UNSIGNED (type) ? FT_unsigned_char : FT_char); abort (); case REAL_TYPE: /* Carefully distinguish all the standard types of C, without messing up if the language is not C. */ if (TYPE_NAME (type) != 0 && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && DECL_NAME (TYPE_NAME (type)) != 0 && TREE_CODE (DECL_NAME (TYPE_NAME (type))) == IDENTIFIER_NODE) { char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); /* Note that here we can run afowl of a serious bug in "classic" svr4 SDB debuggers. They don't seem to understand the FT_ext_prec_float type (even though they should). */ if (!strcmp (name, "long double")) return FT_ext_prec_float; } if (TYPE_PRECISION (type) == DOUBLE_TYPE_SIZE) return FT_dbl_prec_float; if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE) return FT_float; /* Note that here we can run afowl of a serious bug in "classic" svr4 SDB debuggers. They don't seem to understand the FT_ext_prec_float type (even though they should). */ if (TYPE_PRECISION (type) == LONG_DOUBLE_TYPE_SIZE) return FT_ext_prec_float; abort (); case COMPLEX_TYPE: return FT_complex; /* GNU FORTRAN COMPLEX type. */ case CHAR_TYPE: return FT_char; /* GNU Pascal CHAR type. Not used in C. */ case BOOLEAN_TYPE: return FT_boolean; /* GNU FORTRAN BOOLEAN type. */ default: abort (); /* No other TREE_CODEs are Dwarf fundamental types. */ } return 0;}/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to the Dwarf "root" type for the given input type. The Dwarf "root" type of a given type is generally the same as the given type, except that if the given type is a pointer or reference type, then the root type of the given type is the root type of the "basis" type for the pointer or reference type. (This definition of the "root" type is recursive.) Also, the root type of a `const' qualified type or a `volatile' qualified type is the root type of the given type without the qualifiers. */static treeroot_type (type) register tree type;{ if (TREE_CODE (type) == ERROR_MARK) return error_mark_node; switch (TREE_CODE (type)) { case ERROR_MARK: return error_mark_node; case POINTER_TYPE: case REFERENCE_TYPE: return type_main_variant (root_type (TREE_TYPE (type))); default: return type_main_variant (type); }}/* Given a pointer to an arbitrary ..._TYPE tree node, write out a sequence of zero or more Dwarf "type-modifier" bytes applicable to the type. */static voidwrite_modifier_bytes (type, decl_const, decl_volatile) register tree type; register int decl_const; register int decl_volatile;{ if (TREE_CODE (type) == ERROR_MARK) return; if (TYPE_READONLY (type) || decl_const) ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_const); if (TYPE_VOLATILE (type) || decl_volatile) ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_volatile); switch (TREE_CODE (type)) { case POINTER_TYPE: ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_pointer_to); write_modifier_bytes (TREE_TYPE (type), 0, 0); return; case REFERENCE_TYPE: ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_reference_to); write_modifier_bytes (TREE_TYPE (type), 0, 0); return; case ERROR_MARK: default: return; }}/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the given input type is a Dwarf "fundamental" type. Otherwise return zero. */inline inttype_is_fundamental (type) register tree type;{ switch (TREE_CODE (type)) { case ERROR_MARK: case VOID_TYPE: case INTEGER_TYPE: case REAL_TYPE: case COMPLEX_TYPE: case BOOLEAN_TYPE: case CHAR_TYPE: return 1; case SET_TYPE: case ARRAY_TYPE: case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: case ENUMERAL_TYPE: case FUNCTION_TYPE: case METHOD_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: case FILE_TYPE: case OFFSET_TYPE: case LANG_TYPE: return 0; default: abort (); } return 0;}/* Given a pointer to some ..._DECL tree node, generate an assembly language equate directive which will associate a symbolic name with the current DIE. The name used is an artificial label generated from the DECL_UID number associated with the given decl node. The name it gets equated to is the symbolic label that we (previously) output at the start of the DIE that we are currently generating. Calling this function while generating some "decl related" form of DIE makes it possible to later refer to the DIE which represents the given decl simply by re-generating the symbolic name from the ..._DECL node's UID number. */static voidequate_decl_number_to_die_number (decl) register tree decl;{ /* In the case where we are generating a DIE for some ..._DECL node which represents either some inline function declaration or some entity declared within an inline function declaration/definition, setup a symbolic name for the current DIE so that we have a name for this DIE that we can easily refer to later on within AT_abstract_origin attributes. */ char decl_label[MAX_ARTIFICIAL_LABEL_BYTES]; char die_label[MAX_ARTIFICIAL_LABEL_BYTES]; sprintf (decl_label, DECL_NAME_FMT, DECL_UID (decl)); sprintf (die_label, DIE_BEGIN_LABEL_FMT, current_dienum); ASM_OUTPUT_DEF (asm_out_file, decl_label, die_label);}/* Given a pointer to some ..._TYPE tree node, generate an assembly language equate directive which will associate a symbolic name with the current DIE. The name used is an artificial label generated from the TYPE_UID number associated with the given type node. The name it gets equated to is the symbolic label that we (previously) output at the start of the DIE that we are currently generating. Calling this function while generating some "type related" form of DIE makes it easy to later refer to the DIE which represents the given type simply by re-generating the alternative name from the ..._TYPE node's UID number. */inline voidequate_type_number_to_die_number (type) register tree type;{ char type_label[MAX_ARTIFICIAL_LABEL_BYTES]; char die_label[MAX_ARTIFICIAL_LABEL_BYTES]; /* We are generating a DIE to represent the main variant of this type (i.e the type without any const or volatile qualifiers) so in order to get the equate to come out right, we need to get the main variant itself here. */ type = type_main_variant (type); sprintf (type_label, TYPE_NAME_FMT, TYPE_UID (type)); sprintf (die_label, DIE_BEGIN_LABEL_FMT, current_dienum); ASM_OUTPUT_DEF (asm_out_file, type_label, die_label);}static voidoutput_reg_number (rtl) register rtx rtl;{ register unsigned regno = REGNO (rtl); if (regno >= FIRST_PSEUDO_REGISTER) { warning_with_decl (dwarf_last_decl, "internal regno botch: regno = %d\n", regno); regno = 0; } fprintf (asm_out_file, "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, DBX_REGISTER_NUMBER (regno)); if (flag_verbose_asm) { fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START); PRINT_REG (rtl, 0, asm_out_file); } fputc ('\n', asm_out_file);}/* The following routine is a nice and simple transducer. It converts the RTL for a variable or parameter (resident in memory) into an equivalent Dwarf representation of a mechanism for getting the address of that same variable onto the top of a hypothetical "address evaluation" stack. When creating memory location descriptors, we are effectively trans- forming the RTL for a memory-resident object into its Dwarf postfix expression equivalent. This routine just recursively descends an RTL tree, turning it into Dwarf postfix code as it goes. */static voidoutput_mem_loc_descriptor (rtl) register rtx rtl;{ /* Note that for a dynamically sized array, the location we will generate a description of here will be the lowest numbered location which is actually within the array. That's *not* necessarily the same as the zeroth element of the array. */ switch (GET_CODE (rtl)) { case SUBREG: /* The case of a subreg may arise when we have a local (register) variable or a formal (register) parameter which doesn't quite fill up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ rtl = XEXP (rtl, 0); /* Drop thru. */ case REG: /* Whenever a register number forms a part of the description of the method for calculating the (dynamic) address of a memory resident object, DWARF rules require the register number to be referred to as a "base register". This distinction is not based in any way upon what category of register the hardware believes the given register belongs to. This is strictly DWARF terminology we're dealing with here. Note that in cases where the location of a memory-resident data object could be expressed as: OP_ADD (OP_BASEREG (basereg), OP_CONST (0)) the actual DWARF location descriptor that we generate may just be OP_BASEREG (basereg). This may look deceptively like the object in question was allocated to a register (rather than in memory) so DWARF consumers need to be aware of the subtle distinction between OP_REG and OP_BASEREG. */ ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_BASEREG); output_reg_number (rtl); break; case MEM: output_mem_loc_descriptor (XEXP (rtl, 0)); ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_DEREF4); break; case CONST: case SYMBOL_REF: ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_ADDR); ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, rtl); break; case PLUS: output_mem_loc_descriptor (XEXP (rtl, 0)); output_mem_loc_descriptor (XEXP (rtl, 1)); ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_ADD); break; case CONST_INT: ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_CONST); ASM_OUTPUT_DWARF_DATA4 (asm_out_file, INTVAL (rtl)); break; default: abort (); }}/* Output a proper Dwarf location descriptor for a variable or parameter which is either allocated in a register or in a memory location. For a register, we just generate an OP_REG and the register number. For a memory location we provide a Dwarf postfix expression describing how to generate the (dynamic) address of the object onto the address stack. */static voidoutput_loc_descriptor (rtl) register rtx rtl;{ switch (GET_CODE (rtl)) { case SUBREG: /* The case of a subreg may arise when we have a local (register) variable or a formal (register) parameter which doesn't quite fill up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ rtl = XEXP (rtl, 0); /* Drop thru. */ case REG: ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_REG); output_reg_number (rtl); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -