📄 sdbout.c
字号:
}}/* Call sdbout_symbol on each decl in the chain SYMS. */static voidsdbout_syms (syms) tree syms;{ while (syms) { sdbout_symbol (syms, 1); syms = TREE_CHAIN (syms); }}/* Output SDB information for a symbol described by DECL. LOCAL is nonzero if the symbol is not file-scope except at the end of compilation when we really want those symbols to be output. In the case of a variable, we do not really output the variable if LOCAL is 0. */voidsdbout_symbol (decl, local) tree decl; int local;{ int letter = 0; tree type = TREE_TYPE (decl); rtx value; /* If global, first output all types and all struct, enum and union tags that have been created and not yet output. */ if (local == 0) { sdbout_tags (gettags ()); sdbout_types (nreverse (get_permanent_types ())); }#ifdef SDB_NO_FORWARD_REFS sdbout_one_type (type);#endif switch (TREE_CODE (decl)) { case CONST_DECL: /* Enum values are defined by defining the enum type. */ return; case FUNCTION_DECL: if (TREE_EXTERNAL (decl)) return; if (GET_CODE (DECL_RTL (decl)) != MEM || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) return; PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl))); PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0)); PUT_SDB_SCL (TREE_PUBLIC (decl) ? C_EXT : C_STAT); break; case TYPE_DECL: /* Output typedef name. */ PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl))); PUT_SDB_SCL (C_TPDEF); break; case PARM_DECL: /* Parm decls go in their own separate chains and are output by sdbout_reg_parms and sdbout_parms. */ abort (); case VAR_DECL: /* Don't mention a variable that is external. Let the file that defines it describe it. */ if (TREE_EXTERNAL (decl)) return; /* Don't outpuit a file-scope variable where it is defined. At the end of compilation, this function is called once again for those variable, but this time with LOCAL nonzero. This is because COFF requires all file-scope variables to follow all typedefs. We satisfy this requirement by putting all file-scope variables at the end. */ if (!local) return; value = DECL_RTL (decl); /* Don't mention a variable at all if it was completely optimized into nothingness. */ if (GET_CODE (value) == REG && (REGNO (value) < 0 || REGNO (value) >= FIRST_PSEUDO_REGISTER)) return; /* Ok, start a symtab entry and output the variable name. */ PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl))); if (GET_CODE (value) == MEM && GET_CODE (XEXP (value, 0)) == SYMBOL_REF) { if (TREE_PUBLIC (decl)) { PUT_SDB_VAL (XEXP (value, 0)); PUT_SDB_SCL (C_EXT); } else { PUT_SDB_VAL (XEXP (value, 0)); PUT_SDB_SCL (C_STAT); } } else if (GET_CODE (value) == REG) { PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (value))); PUT_SDB_SCL (C_REG); } else if (GET_CODE (value) == SUBREG) { int offset = 0; while (GET_CODE (value) == SUBREG) { offset += SUBREG_WORD (value); value = SUBREG_REG (value); } PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (value) + offset)); PUT_SDB_SCL (C_REG); } else if (GET_CODE (value) == MEM && (GET_CODE (XEXP (value, 0)) == MEM || (GET_CODE (XEXP (value, 0)) == REG && REGNO (XEXP (value, 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 (GET_CODE (XEXP (value, 0)) == REG) { PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (XEXP (value, 0)))); PUT_SDB_SCL (C_REG); } else { /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). We want the value of that CONST_INT. */ /* Encore compiler hates a newline in a macro arg, it seems. */ PUT_SDB_INT_VAL (INTVAL (XEXP (XEXP (XEXP (value, 0), 0), 1))); PUT_SDB_SCL (C_AUTO); } type = build_pointer_type (TREE_TYPE (decl)); } else if (GET_CODE (value) == MEM && GET_CODE (XEXP (value, 0)) == PLUS && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG && GET_CODE (XEXP (XEXP (value, 0), 1)) == CONST_INT) { /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))). We want the value of that CONST_INT. */ PUT_SDB_INT_VAL (INTVAL (XEXP (XEXP (value, 0), 1))); PUT_SDB_SCL (C_AUTO); } else { /* It is something we don't know how to represent for SDB. */ } break; } PUT_SDB_TYPE (plain_type (type)); PUT_SDB_ENDEF;}/* Given a list of TREE_LIST nodes that point at types, output those types for SDB. We must check to include those that have been mentioned already with only a cross-reference. */voidsdbout_tags (tags) tree tags;{ register tree link; for (link = tags; link; link = TREE_CHAIN (link)) { register tree type = TREE_VALUE (link); if (TREE_PURPOSE (link) != 0 && TYPE_SIZE (type) != 0) sdbout_one_type (type); }}/* Given a chain of ..._TYPE nodes, all of which have names, output definitions of those names, as typedefs. */voidsdbout_types (types) register tree types;{ register tree link; for (link = types; link; link = TREE_CHAIN (link)) sdbout_one_type (link);}static voidsdbout_type (type) tree type;{ register tree tem; if (type == error_mark_node) type = integer_type_node; PUT_SDB_TYPE (plain_type (type));}/* Output types of the fields of type TYPE, if they are structs. Formerly did not chase through pointer types, since that could be circular. They must come before TYPE, since forward refs are not allowed. Now james@bigtex.cactus.org says to try them. */static voidsdbout_field_types (type) tree type;{ tree tail; for (tail = TYPE_FIELDS (type); tail; tail = TREE_CHAIN (tail)) {#ifdef SDB_NO_FORWARD_REFS if (TREE_CODE (TREE_TYPE (tail)) == POINTER_TYPE) sdbout_one_type (TREE_TYPE (TREE_TYPE (tail))); else#endif sdbout_one_type (TREE_TYPE (tail)); }}/* Use this to put out the top level defined record and union types for later reference. If this is a struct with a name, then put that name out. Other unnamed structs will have .xxfake labels generated so that they may be referred to later. The label will be stored in the KNOWN_TYPE_TAG slot of a type. It may NOT be called recursively. */static voidsdbout_one_type (type) tree type;{ text_section (); switch (TREE_CODE (type)) { case RECORD_TYPE: case UNION_TYPE: case ENUMERAL_TYPE: type = TYPE_MAIN_VARIANT (type); /* Don't output a type twice. */ if (TREE_ASM_WRITTEN (type)) return; /* Output nothing if type is not yet defined. */ if (TYPE_SIZE (type) == 0) return; TREE_ASM_WRITTEN (type) = 1;#ifdef SDB_NO_FORWARD_REFS /* Before really doing anything, output types we want to refer to. */ if (TREE_CODE (type) != ENUMERAL_TYPE) sdbout_field_types (type);#endif sdbout_record_type_name (type); /* Output a structure type. */ { int size = int_size_in_bytes (type); int member_scl; tree tem; PUT_SDB_DEF (KNOWN_TYPE_TAG (type)); switch (TREE_CODE (type)) { case UNION_TYPE: PUT_SDB_SCL (C_UNTAG); PUT_SDB_TYPE (T_UNION); member_scl = C_MOU; break; case RECORD_TYPE: PUT_SDB_SCL (C_STRTAG); PUT_SDB_TYPE (T_STRUCT); member_scl = C_MOS; break; case ENUMERAL_TYPE: PUT_SDB_SCL (C_ENTAG); PUT_SDB_TYPE (T_ENUM); member_scl = C_MOE; break; } PUT_SDB_SIZE (size); PUT_SDB_ENDEF; /* output the individual fields */ if (TREE_CODE (type) == ENUMERAL_TYPE) for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) { PUT_SDB_DEF (IDENTIFIER_POINTER (TREE_PURPOSE (tem))); PUT_SDB_INT_VAL (TREE_INT_CST_LOW (TREE_VALUE (tem))); PUT_SDB_SCL (C_MOE); PUT_SDB_TYPE (T_MOE); PUT_SDB_ENDEF; } else /* record or union type */ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) /* Output the name, type, position (in bits), size (in bits) of each field. */ /* Omit here the nameless fields that are used to skip bits. */ if (DECL_NAME (tem) != 0) { CONTIN; PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (tem))); if (TREE_PACKED (tem)) { PUT_SDB_INT_VAL (DECL_OFFSET (tem)); PUT_SDB_SCL (C_FIELD); sdbout_type (TREE_TYPE (tem)); PUT_SDB_SIZE (TREE_INT_CST_LOW (DECL_SIZE (tem)) * DECL_SIZE_UNIT (tem)); } else { PUT_SDB_INT_VAL (DECL_OFFSET (tem) / BITS_PER_UNIT); PUT_SDB_SCL (member_scl); sdbout_type (TREE_TYPE (tem)); } PUT_SDB_ENDEF; } /* output end of a structure,union, or enumeral definition */ PUT_SDB_PLAIN_DEF ("eos"); PUT_SDB_INT_VAL (size); PUT_SDB_SCL (C_EOS); PUT_SDB_TAG (KNOWN_TYPE_TAG (type)); PUT_SDB_SIZE (size); PUT_SDB_ENDEF; break; } }}/* Output definitions of all parameters, referring when possible to the place where the parameters were passed rather than the copies used within the function. This is done as part of starting the function. PARMS is a chain of PARM_DECL nodes. */static voidsdbout_parms (parms1) tree parms1;{ tree type; tree parms; for (parms = parms1; parms; parms = TREE_CHAIN (parms)) { int current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT; if (DECL_NAME (parms)) PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (parms))); else PUT_SDB_DEF (gen_fake_label ()); if (GET_CODE (DECL_RTL (parms)) == REG && REGNO (DECL_RTL (parms)) >= 0 && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) type = DECL_ARG_TYPE (parms); else { /* This is the case where the parm is passed as an int or double and it is converted to a char, short or float and stored back in the parmlist. In this case, describe the parm with the variable's declared type, and adjust the address if the least significant bytes (which we are using) are not the first ones. */#ifdef BYTES_BIG_ENDIAN if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));#endif if (GET_CODE (DECL_RTL (parms)) == MEM && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT && (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == current_sym_value)) type = TREE_TYPE (parms); else { current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT; type = DECL_ARG_TYPE (parms); } } PUT_SDB_INT_VAL (current_sym_value); PUT_SDB_SCL (C_ARG); PUT_SDB_TYPE (plain_type (type)); PUT_SDB_ENDEF; }}/* Output definitions, referring to registers, of all the parms in PARMS which are stored in registers during the function. PARMS is a chain of PARM_DECL nodes. This is done as part of starting the function. */static voidsdbout_reg_parms (parms) tree parms;{ while (parms) { if (GET_CODE (DECL_RTL (parms)) == REG && REGNO (DECL_RTL (parms)) >= 0 && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) { PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (parms))); PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms)))); PUT_SDB_SCL (C_REG); PUT_SDB_TYPE (plain_type (TREE_TYPE (parms), 0)); PUT_SDB_ENDEF; } else if (GET_CODE (DECL_RTL (parms)) == MEM && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT) { int offset = DECL_OFFSET (parms) / BITS_PER_UNIT; /* A parm declared char is really passed as an int, so it occupies the least significant bytes. On a big-endian machine those are not the low-numbered ones. */#ifdef BYTES_BIG_ENDIAN if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));#endif if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset) { PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (parms))); PUT_SDB_INT_VAL (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1))); PUT_SDB_SCL (C_AUTO); PUT_SDB_TYPE (plain_type (TREE_TYPE (parms))); PUT_SDB_ENDEF; } } parms = TREE_CHAIN (parms); }}/* Describe the beginning of an internal block within a function. Also output descriptions of variables defined in this block. N is the number of the block, by order of beginning, counting from 1, and not counting the outermost (function top-level) block. The blocks match the LET_STMTS in DECL_INITIAL (current_function_decl), if the count starts at 0 for the outermost one. */voidsdbout_begin_block (file, line, n) FILE *file; int line; int n;{ tree decl = current_function_decl; MAKE_LINE_SAFE (line); PUT_SDB_BLOCK_START (line - sdb_begin_function_line); if (n == 1) { /* Include the outermost LET_STMT's variables in block 1. */ next_block_number = 0; do_block = 0; sdbout_block (DECL_INITIAL (decl)); } next_block_number = 0; do_block = n; sdbout_block (DECL_INITIAL (decl));}/* Describe the end line-number of an internal block within a function. */ voidsdbout_end_block (file, line) FILE *file; int line;{ MAKE_LINE_SAFE (line); PUT_SDB_BLOCK_END (line - sdb_begin_function_line);}/* Output sdb info for the current function name. Called from assemble_function. */voidsdbout_mark_begin_function (){ sdbout_symbol (current_function_decl, 0);}/* Called at beginning of function body (after prologue). Record the function's starting line number, so we can output relative line numbers for the other lines. Describe beginning of outermost block. Also describe the parameter list. */voidsdbout_begin_function (line) int line;{ sdb_begin_function_line = line - 1; PUT_SDB_FUNCTION_START (line); sdbout_parms (DECL_ARGUMENTS (current_function_decl)); sdbout_reg_parms (DECL_ARGUMENTS (current_function_decl));}/* Called at end of function (before epilogue). Describe end of outermost block. */voidsdbout_end_function (line) int line;{ MAKE_LINE_SAFE (line); PUT_SDB_FUNCTION_END (line - sdb_begin_function_line); /* Indicate we are between functions, for line-number output. */ sdb_begin_function_line = -1;}/* Output sdb info for the absolute end of a function. Called after the epilogue is output. */voidsdbout_end_epilogue (){ char *name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); PUT_SDB_EPILOGUE_END (name);}#endif /* SDB_DEBUGGING_INFO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -