📄 dbxout.c
字号:
static voidprint_int_cst_octal (c) tree c;{ unsigned HOST_WIDE_INT high = TREE_INT_CST_HIGH (c); unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (c); int excess = (3 - (HOST_BITS_PER_WIDE_INT % 3)); fprintf (asmfile, "0"); if (excess == 3) { print_octal (high, HOST_BITS_PER_WIDE_INT / 3); print_octal (low, HOST_BITS_PER_WIDE_INT / 3); } else { unsigned HOST_WIDE_INT beg = high >> excess; unsigned HOST_WIDE_INT middle = ((high & (((HOST_WIDE_INT) 1 << excess) - 1)) << (3 - excess) | (low >> (HOST_BITS_PER_WIDE_INT / 3 * 3))); unsigned HOST_WIDE_INT end = low & (((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 3 * 3)) - 1); fprintf (asmfile, "%o%01o", beg, middle); print_octal (end, HOST_BITS_PER_WIDE_INT / 3); }}static voidprint_octal (value, digits) unsigned HOST_WIDE_INT value; int digits;{ int i; for (i = digits - 1; i >= 0; i--) fprintf (asmfile, "%01o", ((value >> (3 * i)) & 7));}/* Output the name of type TYPE, with no punctuation. Such names can be set up either by typedef declarations or by struct, enum and union tags. */static voiddbxout_type_name (type) register tree type;{ tree t; if (TYPE_NAME (type) == 0) abort (); if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) { t = TYPE_NAME (type); } else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) { t = DECL_NAME (TYPE_NAME (type)); } else abort (); fprintf (asmfile, "%s", IDENTIFIER_POINTER (t)); CHARS (IDENTIFIER_LENGTH (t));}/* Output a .stabs for the symbol defined by DECL, which must be a ..._DECL node in the normal namespace. It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL. LOCAL is nonzero if the scope is less than the entire file. */voiddbxout_symbol (decl, local) tree decl; int local;{ int letter = 0; tree type = TREE_TYPE (decl); tree context = NULL_TREE; int regno = -1; /* Cast avoids warning in old compilers. */ current_sym_code = (STAB_CODE_TYPE) 0; current_sym_value = 0; current_sym_addr = 0; /* Ignore nameless syms, but don't ignore type tags. */ if ((DECL_NAME (decl) == 0 && TREE_CODE (decl) != TYPE_DECL) || DECL_IGNORED_P (decl)) return; dbxout_prepare_symbol (decl); /* The output will always start with the symbol name, so always count that in the length-output-so-far. */ if (DECL_NAME (decl) != 0) current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (decl)); switch (TREE_CODE (decl)) { case CONST_DECL: /* Enum values are defined by defining the enum type. */ break; case FUNCTION_DECL: if (DECL_RTL (decl) == 0) return; if (DECL_EXTERNAL (decl)) break; /* Don't mention a nested function under its parent. */ context = decl_function_context (decl); if (context == current_function_decl) break; if (GET_CODE (DECL_RTL (decl)) != MEM || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) break; FORCE_TEXT; fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), TREE_PUBLIC (decl) ? 'F' : 'f'); current_sym_code = N_FUN; current_sym_addr = XEXP (DECL_RTL (decl), 0); if (TREE_TYPE (type)) dbxout_type (TREE_TYPE (type), 0, 0); else dbxout_type (void_type_node, 0, 0); /* For a nested function, when that function is compiled, mention the containing function name as well as (since dbx wants it) our own assembler-name. */ if (context != 0) fprintf (asmfile, ",%s,%s", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), IDENTIFIER_POINTER (DECL_NAME (context))); dbxout_finish_symbol (decl); break; case TYPE_DECL:#if 0 /* This seems all wrong. Outputting most kinds of types gives no name at all. A true definition gives no name; a cross-ref for a structure can give the tag name, but not a type name. It seems that no typedef name is defined by outputting a type. */ /* If this typedef name was defined by outputting the type, don't duplicate it. */ if (typevec[TYPE_SYMTAB_ADDRESS (type)] == TYPE_DEFINED && TYPE_NAME (TREE_TYPE (decl)) == decl) return;#endif /* Don't output the same typedef twice. And don't output what language-specific stuff doesn't want output. */ if (TREE_ASM_WRITTEN (decl) || DECL_IGNORED_P (decl)) return; FORCE_TEXT; { int tag_needed = 1; int did_output = 0; if (DECL_NAME (decl)) { /* Nonzero means we must output a tag as well as a typedef. */ tag_needed = 0; /* Handle the case of a C++ structure or union where the TYPE_NAME is a TYPE_DECL which gives both a typedef name and a tag. */ /* dbx requires the tag first and the typedef second. */ if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE) && TYPE_NAME (type) == decl && !(use_gnu_debug_info_extensions && have_used_extensions) && !TREE_ASM_WRITTEN (TYPE_NAME (type)) /* Distinguish the implicit typedefs of C++ from explicit ones that might be found in C. */ && DECL_SOURCE_LINE (decl) == 0) { tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); current_sym_code = DBX_TYPE_DECL_STABS_CODE; current_sym_value = 0; current_sym_addr = 0; current_sym_nchars = 2 + IDENTIFIER_LENGTH (name); fprintf (asmfile, "%s \"%s:T", ASM_STABS_OP, IDENTIFIER_POINTER (name)); dbxout_type (type, 1, 0); dbxout_finish_symbol (NULL_TREE); } /* Output typedef name. */ fprintf (asmfile, "%s \"%s:", ASM_STABS_OP, IDENTIFIER_POINTER (DECL_NAME (decl))); /* Short cut way to output a tag also. */ if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE) && TYPE_NAME (type) == decl) { if (use_gnu_debug_info_extensions && have_used_extensions) { putc ('T', asmfile); TREE_ASM_WRITTEN (TYPE_NAME (type)) = 1; }#if 0 /* Now we generate the tag for this case up above. */ else tag_needed = 1;#endif } putc ('t', asmfile); current_sym_code = DBX_TYPE_DECL_STABS_CODE; dbxout_type (type, 1, 0); dbxout_finish_symbol (decl); did_output = 1; } if (tag_needed && TYPE_NAME (type) != 0 && !TREE_ASM_WRITTEN (TYPE_NAME (type))) { /* For a TYPE_DECL with no name, but the type has a name, output a tag. This is what represents `struct foo' with no typedef. */ /* In C++, the name of a type is the corresponding typedef. In C, it is an IDENTIFIER_NODE. */ tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); current_sym_code = DBX_TYPE_DECL_STABS_CODE; current_sym_value = 0; current_sym_addr = 0; current_sym_nchars = 2 + IDENTIFIER_LENGTH (name); fprintf (asmfile, "%s \"%s:T", ASM_STABS_OP, IDENTIFIER_POINTER (name)); dbxout_type (type, 1, 0); dbxout_finish_symbol (NULL_TREE); did_output = 1; } /* If an enum type has no name, it cannot be referred to, but we must output it anyway, since the enumeration constants can be referred to. */ if (!did_output && TREE_CODE (type) == ENUMERAL_TYPE) { current_sym_code = DBX_TYPE_DECL_STABS_CODE; current_sym_value = 0; current_sym_addr = 0; current_sym_nchars = 2; /* Some debuggers fail when given NULL names, so give this a harmless name of ` '. */ fprintf (asmfile, "%s \" :T", ASM_STABS_OP); dbxout_type (type, 1, 0); dbxout_finish_symbol (NULL_TREE); } /* Prevent duplicate output of a typedef. */ TREE_ASM_WRITTEN (decl) = 1; break; } case PARM_DECL: /* Parm decls go in their own separate chains and are output by dbxout_reg_parms and dbxout_parms. */ abort (); case RESULT_DECL: /* Named return value, treat like a VAR_DECL. */ case VAR_DECL: if (DECL_RTL (decl) == 0) return; /* Don't mention a variable that is external. Let the file that defines it describe it. */ if (DECL_EXTERNAL (decl)) break; /* If the variable is really a constant and not written in memory, inform the debugger. */ if (TREE_STATIC (decl) && TREE_READONLY (decl) && DECL_INITIAL (decl) != 0 && ! TREE_ASM_WRITTEN (decl) && (DECL_FIELD_CONTEXT (decl) == NULL_TREE || TREE_CODE (DECL_FIELD_CONTEXT (decl)) == BLOCK)) { if (TREE_PUBLIC (decl) == 0) { /* The sun4 assembler does not grok this. */ char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); if (TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE) { HOST_WIDE_INT ival = TREE_INT_CST_LOW (DECL_INITIAL (decl));#ifdef DBX_OUTPUT_CONSTANT_SYMBOL DBX_OUTPUT_CONSTANT_SYMBOL (asmfile, name, ival);#else fprintf (asmfile, "%s \"%s:c=i%d\",0x%x,0,0,0\n", ASM_STABS_OP, name, ival, N_LSYM);#endif return; } else if (TREE_CODE (TREE_TYPE (decl)) == REAL_TYPE) { /* don't know how to do this yet. */ } break; } /* else it is something we handle like a normal variable. */ } DECL_RTL (decl) = eliminate_regs (DECL_RTL (decl), 0, 0);#ifdef LEAF_REG_REMAP if (leaf_function) leaf_renumber_regs_insn (DECL_RTL (decl));#endif /* Don't mention a variable at all if it was completely optimized into nothingness. If DECL was from an inline function, then it's rtl is not identically the rtl that was used in this particular compilation. */ if (GET_CODE (DECL_RTL (decl)) == REG) { regno = REGNO (DECL_RTL (decl)); if (regno >= FIRST_PSEUDO_REGISTER) return; } else if (GET_CODE (DECL_RTL (decl)) == SUBREG) { rtx value = DECL_RTL (decl); int offset = 0; while (GET_CODE (value) == SUBREG) { offset += SUBREG_WORD (value); value = SUBREG_REG (value); } if (GET_CODE (value) == REG) { regno = REGNO (value); if (regno >= FIRST_PSEUDO_REGISTER) return; regno += offset; } alter_subreg (DECL_RTL (decl)); } /* The kind-of-variable letter depends on where the variable is and on the scope of its name: G and N_GSYM for static storage and global scope, S for static storage and file scope, V for static storage and local scope, for those two, use N_LCSYM if data is in bss segment, N_STSYM if in data segment, N_FUN otherwise. (We used N_FUN originally, then changed to N_STSYM to please GDB. However, it seems that confused ld. Now GDB has been fixed to like N_FUN, says Kingdon.) no letter at all, and N_LSYM, for auto variable, r and N_RSYM for register variable. */ if (GET_CODE (DECL_RTL (decl)) == MEM && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF) { if (TREE_PUBLIC (decl)) { letter = 'G'; current_sym_code = N_GSYM; } else { current_sym_addr = XEXP (DECL_RTL (decl), 0); letter = decl_function_context (decl) ? 'V' : 'S'; if (!DECL_INITIAL (decl)) current_sym_code = N_LCSYM; else if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl)) /* This is not quite right, but it's the closest of all the codes that Unix defines. */ current_sym_code = DBX_STATIC_CONST_VAR_CODE; else {/* Ultrix `as' seems to need this. */#ifdef DBX_STATIC_STAB_DATA_SECTION data_section ();#endif current_sym_code = N_STSYM; } } } else if (regno >= 0) { letter = 'r'; current_sym_code = N_RSYM; current_sym_value = DBX_REGISTER_NUMBER (regno); } else if (GET_CODE (DECL_RTL (decl)) == MEM && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM))) /* If the value is indirect by memory or by a register that isn't the frame pointer then it means the object is variable-sized and address through that register or stack slot. DBX has no way to represent this so all we can do is output the variable as a pointer. If it's not a parameter, ignore it. (VAR_DECLs like this can be made by integrate.c.) */ { if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) { letter = 'r'; current_sym_code = N_RSYM; current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (DECL_RTL (decl), 0))); } else { current_sym_code = N_LSYM; /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -