📄 dbxout.c
字号:
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, NULL_RTX);#ifdef LEAF_REG_REMAP if (leaf_function) leaf_renumber_regs_insn (DECL_RTL (decl));#endif dbxout_symbol_location (decl, type, 0, DECL_RTL (decl)); }}/* Output the stab for DECL, a VAR_DECL, RESULT_DECL or PARM_DECL. Add SUFFIX to its name, if SUFFIX is not 0. Describe the variable as residing in HOME (usually HOME is DECL_RTL (DECL), but not always). */static voiddbxout_symbol_location (decl, type, suffix, home) tree decl, type; char *suffix; rtx home;{ int letter = 0; int regno = -1; /* Don't mention a variable at all if it was completely optimized into nothingness. If the decl was from an inline function, then it's rtl is not identically the rtl that was used in this particular compilation. */ if (GET_CODE (home) == REG) { regno = REGNO (home); if (regno >= FIRST_PSEUDO_REGISTER) return; } else if (GET_CODE (home) == SUBREG) { rtx value = home; 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 (home); } /* 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 (home) == MEM && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) { if (TREE_PUBLIC (decl)) { letter = 'G'; current_sym_code = N_GSYM; } else { current_sym_addr = XEXP (home, 0); letter = decl_function_context (decl) ? 'V' : 'S'; /* This should be the same condition as in assemble_variable, but we don't have access to dont_output_data here. So, instead, we rely on the fact that error_mark_node initializers always end up in bss for C++ and never end up in bss for C. */ if (DECL_INITIAL (decl) == 0 || (!strcmp (lang_identify (), "cplusplus") && DECL_INITIAL (decl) == error_mark_node)) current_sym_code = N_LCSYM; else if (DECL_IN_TEXT_SECTION (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 (home) == MEM && (GET_CODE (XEXP (home, 0)) == MEM || (GET_CODE (XEXP (home, 0)) == REG && REGNO (XEXP (home, 0)) != HARD_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 (home, 0)) == REG) { letter = 'r'; current_sym_code = N_RSYM; current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0))); } else { current_sym_code = N_LSYM; /* RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). We want the value of that CONST_INT. */ current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0)); } /* Effectively do build_pointer_type, but don't cache this type, since it might be temporary whereas the type it points to might have been saved for inlining. */ /* Don't use REFERENCE_TYPE because dbx can't handle that. */ type = make_node (POINTER_TYPE); TREE_TYPE (type) = TREE_TYPE (decl); } else if (GET_CODE (home) == MEM && GET_CODE (XEXP (home, 0)) == REG) { current_sym_code = N_LSYM; current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); } else if (GET_CODE (home) == MEM && GET_CODE (XEXP (home, 0)) == PLUS && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) { current_sym_code = N_LSYM; /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) We want the value of that CONST_INT. */ current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); } else if (GET_CODE (home) == MEM && GET_CODE (XEXP (home, 0)) == CONST) { /* Handle an obscure case which can arise when optimizing and when there are few available registers. (This is *always* the case for i386/i486 targets). The RTL looks like (MEM (CONST ...)) even though this variable is a local `auto' or a local `register' variable. In effect, what has happened is that the reload pass has seen that all assignments and references for one such a local variable can be replaced by equivalent assignments and references to some static storage variable, thereby avoiding the need for a register. In such cases we're forced to lie to debuggers and tell them that this variable was itself `static'. */ current_sym_code = N_LCSYM; letter = 'V'; current_sym_addr = XEXP (XEXP (home, 0), 0); } else if (GET_CODE (home) == CONCAT) { tree subtype = TREE_TYPE (type); /* If the variable's storage is in two parts, output each as a separate stab with a modified name. */ if (WORDS_BIG_ENDIAN) dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 0)); else dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0)); /* Cast avoids warning in old compilers. */ current_sym_code = (STAB_CODE_TYPE) 0; current_sym_value = 0; current_sym_addr = 0; dbxout_prepare_symbol (decl); if (WORDS_BIG_ENDIAN) dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1)); else dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 1)); return; } else /* Address might be a MEM, when DECL is a variable-sized object. Or it might be const0_rtx, meaning previous passes want us to ignore this variable. */ return; /* Ok, start a symtab entry and output the variable name. */ FORCE_TEXT;#ifdef DBX_STATIC_BLOCK_START DBX_STATIC_BLOCK_START (asmfile, current_sym_code);#endif dbxout_symbol_name (decl, suffix, letter); dbxout_type (type, 0, 0); dbxout_finish_symbol (decl);#ifdef DBX_STATIC_BLOCK_END DBX_STATIC_BLOCK_END (asmfile, current_sym_code);#endif}/* Output the symbol name of DECL for a stabs, with suffix SUFFIX. Then output LETTER to indicate the kind of location the symbol has. */static voiddbxout_symbol_name (decl, suffix, letter) tree decl; char *suffix; int letter;{ /* One slight hitch: if this is a VAR_DECL which is a static class member, we must put out the mangled name instead of the DECL_NAME. Note also that static member (variable) names DO NOT begin with underscores in .stabs directives. */ char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (name == 0) name = "(anon)"; fprintf (asmfile, "%s \"%s%s:", ASM_STABS_OP, name, (suffix ? suffix : "")); if (letter) putc (letter, asmfile);}static voiddbxout_prepare_symbol (decl) tree decl;{#ifdef WINNING_GDB char *filename = DECL_SOURCE_FILE (decl); dbxout_source_file (asmfile, filename);#endif}static voiddbxout_finish_symbol (sym) tree sym;{#ifdef DBX_FINISH_SYMBOL DBX_FINISH_SYMBOL (sym);#else int line = 0; if (use_gnu_debug_info_extensions && sym != 0) line = DECL_SOURCE_LINE (sym); fprintf (asmfile, "\",%d,0,%d,", current_sym_code, line); if (current_sym_addr) output_addr_const (asmfile, current_sym_addr); else fprintf (asmfile, "%d", current_sym_value); putc ('\n', asmfile);#endif}/* Output definitions of all the decls in a chain. */voiddbxout_syms (syms) tree syms;{ while (syms) { dbxout_symbol (syms, 1); syms = TREE_CHAIN (syms); }}/* The following two functions output definitions of function parameters. Each parameter gets a definition locating it in the parameter list. Each parameter that is a register variable gets a second definition locating it in the register. Printing or argument lists in gdb uses the definitions that locate in the parameter list. But reference to the variable in expressions uses preferentially the definition as a register. *//* Output definitions, referring to storage in the parmlist, of all the parms in PARMS, which is a chain of PARM_DECL nodes. */voiddbxout_parms (parms) tree parms;{ for (; parms; parms = TREE_CHAIN (parms)) if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) { dbxout_prepare_symbol (parms); /* Perform any necessary register eliminations on the parameter's rtl, so that the debugging output will be accurate. */ DECL_INCOMING_RTL (parms) = eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX); DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, NULL_RTX);#ifdef LEAF_REG_REMAP if (leaf_function) { leaf_renumber_regs_insn (DECL_INCOMING_RTL (parms)); leaf_renumber_regs_insn (DECL_RTL (parms)); }#endif if (PARM_PASSED_IN_MEMORY (parms)) { rtx addr = XEXP (DECL_INCOMING_RTL (parms), 0); /* ??? Here we assume that the parm address is indexed off the frame pointer or arg pointer. If that is not true, we produce meaningless results, but do not crash. */ if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT) current_sym_value = INTVAL (XEXP (addr, 1)); else current_sym_value = 0; current_sym_code = N_PSYM; current_sym_addr = 0; FORCE_TEXT; if (DECL_NAME (parms)) { current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP, IDENTIFIER_POINTER (DECL_NAME (parms)), DBX_MEMPARM_STABS_LETTER); } else { current_sym_nchars = 8; fprintf (asmfile, "%s \"(anon):%c", ASM_STABS_OP, DBX_MEMPARM_STABS_LETTER); } dbxout_type (DECL_ARG_TYPE (parms), 0, 0); current_sym_value = DEBUGGER_ARG_OFFSET (current_sym_value, addr); dbxout_finish_symbol (parms); } else if (GET_CODE (DECL_RTL (parms)) == REG) { rtx best_rtl; char regparm_letter; tree parm_type; /* Parm passed in registers and lives in registers or nowhere. */ current_sym_code = DBX_REGPARM_STABS_CODE; regparm_letter = DBX_REGPARM_STABS_LETTER; current_sym_addr = 0; /* If parm lives in a register, use that register; pretend the parm was passed there. It would be more consistent to describe the register where the parm was passed, but in practice that register usually holds something else. If we use DECL_RTL, then we must use the declared type of the variable, not the type that it arrived in. */ if (REGNO (DECL_RTL (parms)) >= 0 && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) { best_rtl = DECL_RTL (parms); parm_type = TREE_TYPE (parms); } /* If the parm lives nowhere, use the regis
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -