📄 dwarfout.c
字号:
case MEM: output_mem_loc_descriptor (XEXP (rtl, 0)); break; default: abort (); /* Should never happen */ }}/* Given a tree node describing an array bound (either lower or upper) output a representation for that bound. */static voidoutput_bound_representation (bound, dim_num, u_or_l) register tree bound; register unsigned dim_num; /* For multi-dimensional arrays. */ register char u_or_l; /* Designates upper or lower bound. */{ switch (TREE_CODE (bound)) { case ERROR_MARK: return; /* All fixed-bounds are represented by INTEGER_CST nodes. */ case INTEGER_CST: ASM_OUTPUT_DWARF_DATA4 (asm_out_file, (unsigned) TREE_INT_CST_LOW (bound)); break; /* Dynamic bounds may be represented by NOP_EXPR nodes containing SAVE_EXPR nodes. */ case NOP_EXPR: bound = TREE_OPERAND (bound, 0); /* ... fall thru... */ case SAVE_EXPR: { char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; sprintf (begin_label, BOUND_BEGIN_LABEL_FMT, current_dienum, dim_num, u_or_l); sprintf (end_label, BOUND_END_LABEL_FMT, current_dienum, dim_num, u_or_l); ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); ASM_OUTPUT_LABEL (asm_out_file, begin_label); /* If we are working on a bound for a dynamic dimension in C, the dynamic dimension in question had better have a static (zero) lower bound and a dynamic *upper* bound. */ if (u_or_l != 'u') abort (); /* If optimization is turned on, the SAVE_EXPRs that describe how to access the upper bound values are essentially bogus. They only describe (at best) how to get at these values at the points in the generated code right after they have just been computed. Worse yet, in the typical case, the upper bound values will not even *be* computed in the optimized code, so these SAVE_EXPRs are entirely bogus. In order to compensate for this fact, we check here to see if optimization is enabled, and if so, we effectively create an empty location description for the (unknown and unknowable) upper bound. This should not cause too much trouble for existing (stupid?) debuggers because they have to deal with empty upper bounds location descriptions anyway in order to be able to deal with incomplete array types. Of course an intelligent debugger (GDB?) should be able to comprehend that a missing upper bound specification in a array type used for a storage class `auto' local array variable indicates that the upper bound is both unknown (at compile- time) and unknowable (at run-time) due to optimization. */ if (! optimize) output_loc_descriptor (eliminate_regs (SAVE_EXPR_RTL (bound), 0, NULL_RTX)); ASM_OUTPUT_LABEL (asm_out_file, end_label); } break; default: abort (); }}/* Recursive function to output a sequence of value/name pairs for enumeration constants in reversed order. This is called from enumeration_type_die. */static voidoutput_enumeral_list (link) register tree link;{ if (link) { output_enumeral_list (TREE_CHAIN (link)); ASM_OUTPUT_DWARF_DATA4 (asm_out_file, (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link))); ASM_OUTPUT_DWARF_STRING (asm_out_file, IDENTIFIER_POINTER (TREE_PURPOSE (link))); }}/* Given an unsigned value, round it up to the lowest multiple of `boundary' which is not less than the value itself. */inline unsignedceiling (value, boundary) register unsigned value; register unsigned boundary;{ return (((value + boundary - 1) / boundary) * boundary);}/* Given a pointer to what is assumed to be a FIELD_DECL node, return a pointer to the declared type for the relevant field variable, or return `integer_type_node' if the given node turns out to be an ERROR_MARK node. */inline treefield_type (decl) register tree decl;{ register tree type; if (TREE_CODE (decl) == ERROR_MARK) return integer_type_node; type = DECL_BIT_FIELD_TYPE (decl); if (type == NULL) type = TREE_TYPE (decl); return type;}/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE node, return the alignment in bits for the type, or else return BITS_PER_WORD if the node actually turns out to be an ERROR_MARK node. */inline unsignedsimple_type_align_in_bits (type) register tree type;{ return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;}/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE node, return the size in bits for the type if it is a constant, or else return the alignment for the type if the type's size is not constant, or else return BITS_PER_WORD if the type actually turns out to be an ERROR_MARK node. */inline unsignedsimple_type_size_in_bits (type) register tree type;{ if (TREE_CODE (type) == ERROR_MARK) return BITS_PER_WORD; else { register tree type_size_tree = TYPE_SIZE (type); if (TREE_CODE (type_size_tree) != INTEGER_CST) return TYPE_ALIGN (type); return (unsigned) TREE_INT_CST_LOW (type_size_tree); }}/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and return the byte offset of the lowest addressed byte of the "containing object" for the given FIELD_DECL, or return 0 if we are unable to deter- mine what that offset is, either because the argument turns out to be a pointer to an ERROR_MARK node, or because the offset is actually variable. (We can't handle the latter case just yet.) */static unsignedfield_byte_offset (decl) register tree decl;{ register unsigned type_align_in_bytes; register unsigned type_align_in_bits; register unsigned type_size_in_bits; register unsigned object_offset_in_align_units; register unsigned object_offset_in_bits; register unsigned object_offset_in_bytes; register tree type; register tree bitpos_tree; register tree field_size_tree; register unsigned bitpos_int; register unsigned deepest_bitpos; register unsigned field_size_in_bits; if (TREE_CODE (decl) == ERROR_MARK) return 0; if (TREE_CODE (decl) != FIELD_DECL) abort (); type = field_type (decl); bitpos_tree = DECL_FIELD_BITPOS (decl); field_size_tree = DECL_SIZE (decl); /* We cannot yet cope with fields whose positions or sizes are variable, so for now, when we see such things, we simply return 0. Someday, we may be able to handle such cases, but it will be damn difficult. */ if (TREE_CODE (bitpos_tree) != INTEGER_CST) return 0; bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); if (TREE_CODE (field_size_tree) != INTEGER_CST) return 0; field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree); type_size_in_bits = simple_type_size_in_bits (type); type_align_in_bits = simple_type_align_in_bits (type); type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT; /* Note that the GCC front-end doesn't make any attempt to keep track of the starting bit offset (relative to the start of the containing structure type) of the hypothetical "containing object" for a bit- field. Thus, when computing the byte offset value for the start of the "containing object" of a bit-field, we must deduce this infor- mation on our own. This can be rather tricky to do in some cases. For example, handling the following structure type definition when compiling for an i386/i486 target (which only aligns long long's to 32-bit boundaries) can be very tricky: struct S { int field1; long long field2:31; }; Fortunately, there is a simple rule-of-thumb which can be used in such cases. When compiling for an i386/i486, GCC will allocate 8 bytes for the structure shown above. It decides to do this based upon one simple rule for bit-field allocation. Quite simply, GCC allocates each "con- taining object" for each bit-field at the first (i.e. lowest addressed) legitimate alignment boundary (based upon the required minimum alignment for the declared type of the field) which it can possibly use, subject to the condition that there is still enough available space remaining in the containing object (when allocated at the selected point) to fully accommodate all of the bits of the bit-field itself. This simple rule makes it obvious why GCC allocates 8 bytes for each object of the structure type shown above. When looking for a place to allocate the "containing object" for `field2', the compiler simply tries to allocate a 64-bit "containing object" at each successive 32-bit boundary (starting at zero) until it finds a place to allocate that 64- bit field such that at least 31 contiguous (and previously unallocated) bits remain within that selected 64 bit field. (As it turns out, for the example above, the compiler finds that it is OK to allocate the "containing object" 64-bit field at bit-offset zero within the structure type.) Here we attempt to work backwards from the limited set of facts we're given, and we try to deduce from those facts, where GCC must have believed that the containing object started (within the structure type). The value we deduce is then used (by the callers of this routine) to generate AT_location and AT_bit_offset attributes for fields (both bit-fields and, in the case of AT_location, regular fields as well). */ /* Figure out the bit-distance from the start of the structure to the "deepest" bit of the bit-field. */ deepest_bitpos = bitpos_int + field_size_in_bits; /* This is the tricky part. Use some fancy footwork to deduce where the lowest addressed bit of the containing object must be. */ object_offset_in_bits = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits; /* Compute the offset of the containing object in "alignment units". */ object_offset_in_align_units = object_offset_in_bits / type_align_in_bits; /* Compute the offset of the containing object in bytes. */ object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes; return object_offset_in_bytes;}/****************************** attributes *********************************//* The following routines are responsible for writing out the various types of Dwarf attributes (and any following data bytes associated with them). These routines are listed in order based on the numerical codes of their associated attributes. *//* Generate an AT_sibling attribute. */inline voidsibling_attribute (){ char label[MAX_ARTIFICIAL_LABEL_BYTES]; ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_sibling); sprintf (label, DIE_BEGIN_LABEL_FMT, NEXT_DIE_NUM); ASM_OUTPUT_DWARF_REF (asm_out_file, label);}/* Output the form of location attributes suitable for whole variables and whole parameters. Note that the location attributes for struct fields are generated by the routine `data_member_location_attribute' below. */static voidlocation_attribute (rtl) register rtx rtl;{ char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location); sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum); sprintf (end_label, LOC_END_LABEL_FMT, current_dienum); ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); ASM_OUTPUT_LABEL (asm_out_file, begin_label); /* Handle a special case. If we are about to output a location descriptor for a variable or parameter which has been optimized out of existence, don't do that. Instead we output a zero-length location descriptor value as part of the location attribute. A variable which has been optimized out of existence will have a DECL_RTL value which denotes a pseudo-reg. Currently, in some rare cases, variables can have DECL_RTL values which look like (MEM (REG pseudo-reg#)). These cases are due to bugs elsewhere in the compiler. We treat such cases as if the variable(s) in question had been optimized out of existence. Note that in all cases where we wish to express the fact that a variable has been optimized out of existence, we do not simply suppress the generation of the entire location attribute because the absence of a location attribute in certain kinds of DIEs is used to indicate something else entirely... i.e. that the DIE represents an object declaration, but not a definition. So saith the PLSIG. */ if (! is_pseudo_reg (rtl) && (GET_CODE (rtl) != MEM || ! is_pseudo_reg (XEXP (rtl, 0)))) output_loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX)); ASM_OUTPUT_LABEL (asm_out_file, end_label);}/* Output the specialized form of location attribute used for data members of struct and union types. In the special case of a FIELD_DECL node which represents a bit-field, the "offset" part of this special location descriptor must indicate the distance in bytes from the lowest-addressed byte of the containing struct or union type to the lowest-addressed byte of the "containing object" for the bit-field. (See the `field_byte_offset' function above.) For any given bit-field, the "containing object" is a hypothetical object (of some integral or enum type) within which the given bit-field lives. The type of this hypothetical "containing object" is always the same as the declared type of the individual bit-field itself (for GCC anyway... the DWARF spec doesn't actually mandate this). Note that it is the size (in bytes) of the hypothetical "containing object" which will be given in the AT_byte_size attribute for this bit-field. (See the `byte_size_attribute' function below.) It is also used when calculating the value of the AT_bit_offset attribute. (See the `bit_offset_attribute' function below.)*/static voiddata_member_location_attribute (decl) register tree decl;{ register unsigned object_offset_in_bytes = field_byte_offset (decl); char begin_label[MAX_ARTIFICIAL_LABEL_BYTES]; char end_label[MAX_ARTIFICIAL_LABEL_BYTES]; ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location); sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum); sprintf (end_label, LOC_END_LABEL_FMT, current_dienum); ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label); ASM_OUTPUT_LABEL (asm_out_file, begin_label); ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_CONST); ASM_OUTPUT_DWARF_DATA4 (asm_out_file, object_offset_in_bytes); ASM_OUTPUT_DWARF_STACK_O
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -