From 71fd392a233813678a9c7587ed69f6cd8051a062 Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Sat, 16 Nov 2013 01:16:24 +0000 Subject: [PATCH] gcc: add femit-struct-debug support to reduce Reduce dwarf debug size Obtained from: gcc 4.3 (rev. 123909; GPLv2) MFC after: 3 weeks --- contrib/gcc/ChangeLog.gcc43 | 51 ++++++++ contrib/gcc/c-opts.c | 12 ++ contrib/gcc/c.opt | 12 ++ contrib/gcc/cp/cp-lang.c | 2 + contrib/gcc/cp/cp-tree.h | 1 + contrib/gcc/cp/tree.c | 8 ++ contrib/gcc/doc/invoke.texi | 74 +++++++++++ contrib/gcc/dwarf2out.c | 44 +++++-- contrib/gcc/flags.h | 20 +++ contrib/gcc/langhooks-def.h | 2 + contrib/gcc/langhooks.h | 4 + contrib/gcc/opts.c | 254 ++++++++++++++++++++++++++++++++++++ 12 files changed, 474 insertions(+), 10 deletions(-) diff --git a/contrib/gcc/ChangeLog.gcc43 b/contrib/gcc/ChangeLog.gcc43 index ac73097617c7..6d9d4807a08d 100644 --- a/contrib/gcc/ChangeLog.gcc43 +++ b/contrib/gcc/ChangeLog.gcc43 @@ -27,6 +27,57 @@ alignment for amdfam10 architecture. Increasing the max loop alignment to 24 bytes. +2007-04-16 Lawrence Crowl + + * doc/invoke.texi (Debugging Options): Add documentation for the + -femit-struct-debug options -femit-struct-debug-baseonly, + -femit-struct-debug-reduced, and + -femit-struct-debug-detailed[=...]. + + * c-opts.c (c_common_handle_option): Add + OPT_femit_struct_debug_baseonly, OPT_femit_struct_debug_reduced, + and OPT_femit_struct_debug_detailed_. + * c.opt: Add specifications for + -femit-struct-debug-baseonly, -femit-struct-debug-reduced, + and -femit-struct-debug-detailed[=...]. + * opts.c (set_struct_debug_option): Parse the + -femit-struct-debug-... options. + * opts.c (matches_main_base, main_input_basename, + main_input_baselength, base_of_path, matches_main_base): Add + variables and functions to compare header base name to compilation + unit base name. + * opts.c (should_emit_struct_debug): Add to determine to emit a + structure based on the option. + (dump_struct_debug) Also disabled function to debug this + function. + * opts.c (handle_options): Save the base name of the + compilation unit. + + * langhooks-def.h (LANG_HOOKS_GENERIC_TYPE_P): Define. + (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add. + This hook indicates if a type is generic. Set it by default + to "never generic". + * langhooks.h (struct lang_hooks_for_types): Add a new hook + to determine if a struct type is generic or not. + * cp/cp-tree.h (class_tmpl_impl_spec_p): Declare a C++ hook. + * cp/tree.c (class_tmpl_impl_spec_p): Implement the C++ hook. + * cp/cp-lang.c (LANG_HOOKS_GENERIC_TYPE_P): Override null C hook + with live C++ hook. + + * flags.h (enum debug_info_usage): Add an enumeration to describe + a program's use of a structure type. + * dwarf2out.c (gen_struct_or_union_type_die): Add a new parameter + to indicate the program's usage of the type. Filter structs based + on the -femit-struct-debug-... specification. + (gen_type_die): Split into two routines, gen_type_die and + gen_type_die_with_usage. gen_type_die is now a wrapper + that assumes direct usage. + (gen_type_die_with_usage): Replace calls to gen_type_die + with gen_type_die_with_usage adding the program usage of + the referenced type. + (dwarf2out_imported_module_or_decl): Suppress struct debug + information using should_emit_struct_debug when appropriate. + 2007-04-12 Richard Guenther (r123736) PR tree-optimization/24689 diff --git a/contrib/gcc/c-opts.c b/contrib/gcc/c-opts.c index 3e89ec290201..7f193749fd6a 100644 --- a/contrib/gcc/c-opts.c +++ b/contrib/gcc/c-opts.c @@ -818,6 +818,18 @@ c_common_handle_option (size_t scode, const char *arg, int value) flag_gen_declaration = 1; break; + case OPT_femit_struct_debug_baseonly: + set_struct_debug_option ("base"); + break; + + case OPT_femit_struct_debug_reduced: + set_struct_debug_option ("dir:ord:sys,dir:gen:any,ind:base"); + break; + + case OPT_femit_struct_debug_detailed_: + set_struct_debug_option (arg); + break; + case OPT_idirafter: add_path (xstrdup (arg), AFTER, 0, true); break; diff --git a/contrib/gcc/c.opt b/contrib/gcc/c.opt index f09c5763ba05..820e5c986b6b 100644 --- a/contrib/gcc/c.opt +++ b/contrib/gcc/c.opt @@ -765,6 +765,18 @@ gen-decls ObjC ObjC++ Dump declarations to a .decl file +femit-struct-debug-baseonly +C ObjC C++ ObjC++ +-femit-struct-debug-baseonly Aggressive reduced debug info for structs + +femit-struct-debug-reduced +C ObjC C++ ObjC++ +-femit-struct-debug-reduced Conservative reduced debug info for structs + +femit-struct-debug-detailed= +C ObjC C++ ObjC++ Joined +-femit-struct-debug-detailed= Detailed reduced debug info for structs + idirafter C ObjC C++ ObjC++ Joined Separate -idirafter Add to the end of the system include path diff --git a/contrib/gcc/cp/cp-lang.c b/contrib/gcc/cp/cp-lang.c index 605032789309..c33d488cb62c 100644 --- a/contrib/gcc/cp/cp-lang.c +++ b/contrib/gcc/cp/cp-lang.c @@ -44,6 +44,8 @@ static void cp_init_ts (void); #define LANG_HOOKS_NAME "GNU C++" #undef LANG_HOOKS_INIT #define LANG_HOOKS_INIT cxx_init +#undef LANG_HOOKS_GENERIC_TYPE_P +#define LANG_HOOKS_GENERIC_TYPE_P class_tmpl_impl_spec_p #undef LANG_HOOKS_DECL_PRINTABLE_NAME #define LANG_HOOKS_DECL_PRINTABLE_NAME cxx_printable_name #undef LANG_HOOKS_FOLD_OBJ_TYPE_REF diff --git a/contrib/gcc/cp/cp-tree.h b/contrib/gcc/cp/cp-tree.h index ab84b62e043f..0b30f38809f3 100644 --- a/contrib/gcc/cp/cp-tree.h +++ b/contrib/gcc/cp/cp-tree.h @@ -4373,6 +4373,7 @@ extern tree add_stmt_to_compound (tree, tree); extern tree cxx_maybe_build_cleanup (tree); extern void init_tree (void); extern int pod_type_p (tree); +extern bool class_tmpl_impl_spec_p (tree); extern int zero_init_p (tree); extern tree canonical_type_variant (tree); extern tree copy_binfo (tree, tree, tree, diff --git a/contrib/gcc/cp/tree.c b/contrib/gcc/cp/tree.c index e3391a51d448..eee91514bf24 100644 --- a/contrib/gcc/cp/tree.c +++ b/contrib/gcc/cp/tree.c @@ -1762,6 +1762,14 @@ pod_type_p (tree t) return 1; } +/* Nonzero iff type T is a class template implicit specialization. */ + +bool +class_tmpl_impl_spec_p (tree t) +{ + return CLASS_TYPE_P (t) && CLASSTYPE_TEMPLATE_INSTANTIATION (t); +} + /* Returns 1 iff zero initialization of type T means actually storing zeros in it. */ diff --git a/contrib/gcc/doc/invoke.texi b/contrib/gcc/doc/invoke.texi index 495e32ee44b6..ce6f071909a4 100644 --- a/contrib/gcc/doc/invoke.texi +++ b/contrib/gcc/doc/invoke.texi @@ -275,6 +275,8 @@ in the following sections. -ftest-coverage -ftime-report -fvar-tracking @gol -g -g@var{level} -gcoff -gdwarf-2 @gol -ggdb -gstabs -gstabs+ -gvms -gxcoff -gxcoff+ @gol +-femit-struct-debug-baseonly -femit-struct-debug-reduced @gol +-femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} @gol -p -pg -print-file-name=@var{library} -print-libgcc-file-name @gol -print-multi-directory -print-multi-lib @gol -print-prog-name=@var{program} -print-search-dirs -Q @gol @@ -3411,6 +3413,78 @@ Compress DWARF2 debugging information by eliminating duplicated information about each symbol. This option only makes sense when generating DWARF2 debugging information with @option{-gdwarf-2}. +@item -femit-struct-debug-baseonly +Emit debug information for struct-like types +only when the base name of the compilation source file +matches the base name of file in which the struct was defined. + +This option substantially reduces the size of debugging information, +but at significant potential loss in type information to the debugger. +See @option{-femit-struct-debug-reduced} for a less aggressive option. +See @option{-femit-struct-debug-detailed} for more detailed control. + +This option works only with DWARF 2. + +@item -femit-struct-debug-reduced +Emit debug information for struct-like types +only when the base name of the compilation source file +matches the base name of file in which the type was defined, +unless the struct is a template or defined in a system header. + +This option significantly reduces the size of debugging information, +with some potential loss in type information to the debugger. +See @option{-femit-struct-debug-baseonly} for a more aggressive option. +See @option{-femit-struct-debug-detailed} for more detailed control. + +This option works only with DWARF 2. + +@item -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} +Specify the struct-like types +for which the compiler will generate debug information. +The intent is to reduce duplicate struct debug information +between different object files within the same program. + +This option is a detailed version of +@option{-femit-struct-debug-reduced} and @option{-femit-struct-debug-baseonly}, +which will serve for most needs. + +A specification has the syntax +[@samp{dir:}|@samp{ind:}][@samp{ord:}|@samp{gen:}](@samp{any}|@samp{sys}|@samp{base}|@samp{none}) + +The optional first word limits the specification to +structs that are used directly (@samp{dir:}) or used indirectly (@samp{ind:}). +A struct type is used directly when it is the type of a variable, member. +Indirect uses arise through pointers to structs. +That is, when use of an incomplete struct would be legal, the use is indirect. +An example is +@samp{struct one direct; struct two * indirect;}. + +The optional second word limits the specification to +ordinary structs (@samp{ord:}) or generic structs (@samp{gen:}). +Generic structs are a bit complicated to explain. +For C++, these are non-explicit specializations of template classes, +or non-template classes within the above. +Other programming languages have generics, +but @samp{-femit-struct-debug-detailed} does not yet implement them. + +The third word specifies the source files for those +structs for which the compiler will emit debug information. +The values @samp{none} and @samp{any} have the normal meaning. +The value @samp{base} means that +the base of name of the file in which the type declaration appears +must match the base of the name of the main compilation file. +In practice, this means that +types declared in @file{foo.c} and @file{foo.h} will have debug information, +but types declared in other header will not. +The value @samp{sys} means those types satisfying @samp{base} +or declared in system or compiler headers. + +You may need to experiment to determine the best settings for your application. + +The default is @samp{-femit-struct-debug-detailed=all}. + +This option works only with DWARF 2. + @cindex @command{prof} @item -p @opindex p diff --git a/contrib/gcc/dwarf2out.c b/contrib/gcc/dwarf2out.c index 5e4354a40b00..461990bf4dfd 100644 --- a/contrib/gcc/dwarf2out.c +++ b/contrib/gcc/dwarf2out.c @@ -4215,7 +4215,8 @@ static void gen_ptr_to_mbr_type_die (tree, dw_die_ref); static dw_die_ref gen_compile_unit_die (const char *); static void gen_inheritance_die (tree, tree, dw_die_ref); static void gen_member_die (tree, dw_die_ref); -static void gen_struct_or_union_type_die (tree, dw_die_ref); +static void gen_struct_or_union_type_die (tree, dw_die_ref, + enum debug_info_usage); static void gen_subroutine_type_die (tree, dw_die_ref); static void gen_typedef_die (tree, dw_die_ref); static void gen_type_die (tree, dw_die_ref); @@ -12473,7 +12474,8 @@ gen_member_die (tree type, dw_die_ref context_die) member DIEs needed by later specification DIEs. */ static void -gen_struct_or_union_type_die (tree type, dw_die_ref context_die) +gen_struct_or_union_type_die (tree type, dw_die_ref context_die, + enum debug_info_usage usage) { dw_die_ref type_die = lookup_type_die (type); dw_die_ref scope_die = 0; @@ -12482,6 +12484,7 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die) && (! TYPE_STUB_DECL (type) || ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)))); int ns_decl = (context_die && context_die->die_tag == DW_TAG_namespace); + complete = complete && should_emit_struct_debug (type, usage); if (type_die && ! complete) return; @@ -12609,7 +12612,8 @@ gen_typedef_die (tree decl, dw_die_ref context_die) /* Generate a type description DIE. */ static void -gen_type_die (tree type, dw_die_ref context_die) +gen_type_die_with_usage (tree type, dw_die_ref context_die, + enum debug_info_usage usage) { int need_pop; @@ -12657,16 +12661,19 @@ gen_type_die (tree type, dw_die_ref context_die) /* For these types, all that is required is that we output a DIE (or a set of DIEs) to represent the "basis" type. */ - gen_type_die (TREE_TYPE (type), context_die); + gen_type_die_with_usage (TREE_TYPE (type), context_die, + DINFO_USAGE_IND_USE); break; case OFFSET_TYPE: /* This code is used for C++ pointer-to-data-member types. Output a description of the relevant class type. */ - gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die); + gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die, + DINFO_USAGE_IND_USE); /* Output a description of the type of the object pointed to. */ - gen_type_die (TREE_TYPE (type), context_die); + gen_type_die_with_usage (TREE_TYPE (type), context_die, + DINFO_USAGE_IND_USE); /* Now output a DIE to represent this pointer-to-data-member type itself. */ @@ -12675,13 +12682,15 @@ gen_type_die (tree type, dw_die_ref context_die) case FUNCTION_TYPE: /* Force out return type (in case it wasn't forced out already). */ - gen_type_die (TREE_TYPE (type), context_die); + gen_type_die_with_usage (TREE_TYPE (type), context_die, + DINFO_USAGE_DIR_USE); gen_subroutine_type_die (type, context_die); break; case METHOD_TYPE: /* Force out return type (in case it wasn't forced out already). */ - gen_type_die (TREE_TYPE (type), context_die); + gen_type_die_with_usage (TREE_TYPE (type), context_die, + DINFO_USAGE_DIR_USE); gen_subroutine_type_die (type, context_die); break; @@ -12707,7 +12716,7 @@ gen_type_die (tree type, dw_die_ref context_die) && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) { - gen_type_die (TYPE_CONTEXT (type), context_die); + gen_type_die_with_usage (TYPE_CONTEXT (type), context_die, usage); if (TREE_ASM_WRITTEN (type)) return; @@ -12731,7 +12740,7 @@ gen_type_die (tree type, dw_die_ref context_die) gen_enumeration_type_die (type, context_die); } else - gen_struct_or_union_type_die (type, context_die); + gen_struct_or_union_type_die (type, context_die, usage); if (need_pop) pop_decl_scope (); @@ -12760,6 +12769,12 @@ gen_type_die (tree type, dw_die_ref context_die) TREE_ASM_WRITTEN (type) = 1; } +static void +gen_type_die (tree type, dw_die_ref context_die) +{ + gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE); +} + /* Generate a DIE for a tagged type instantiation. */ static void @@ -13357,7 +13372,11 @@ dwarf2out_imported_module_or_decl (tree decl, tree context) if (!context) scope_die = comp_unit_die; else if (TYPE_P (context)) + { + if (!should_emit_struct_debug (context, DINFO_USAGE_DIR_USE)) + return; scope_die = force_type_die (context); + } else scope_die = force_decl_die (context); @@ -13383,7 +13402,12 @@ dwarf2out_imported_module_or_decl (tree decl, tree context) if (TYPE_CONTEXT (type)) if (TYPE_P (TYPE_CONTEXT (type))) + { + if (!should_emit_struct_debug (TYPE_CONTEXT (type), + DINFO_USAGE_DIR_USE)) + return; type_context_die = force_type_die (TYPE_CONTEXT (type)); + } else type_context_die = force_decl_die (TYPE_CONTEXT (type)); else diff --git a/contrib/gcc/flags.h b/contrib/gcc/flags.h index 226fb6031107..d94c76ca8688 100644 --- a/contrib/gcc/flags.h +++ b/contrib/gcc/flags.h @@ -23,6 +23,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #ifndef GCC_FLAGS_H #define GCC_FLAGS_H +#include "coretypes.h" #include "options.h" enum debug_info_type @@ -54,6 +55,25 @@ enum debug_info_level /* Specify how much debugging info to generate. */ extern enum debug_info_level debug_info_level; +/* A major contribution to object and executable size is debug + information size. A major contribution to debug information + size is struct descriptions replicated in several object files. + The following function determines whether or not debug information + should be generated for a given struct. The indirect parameter + indicates that the struct is being handled indirectly, via + a pointer. See opts.c for the implementation. */ + +enum debug_info_usage +{ + DINFO_USAGE_DFN, /* A struct definition. */ + DINFO_USAGE_DIR_USE, /* A direct use, such as the type of a variable. */ + DINFO_USAGE_IND_USE, /* An indirect use, such as through a pointer. */ + DINFO_USAGE_NUM_ENUMS /* The number of enumerators. */ +}; + +extern bool should_emit_struct_debug (tree type_decl, enum debug_info_usage); +extern void set_struct_debug_option (const char *value); + /* Nonzero means use GNU-only extensions in the generated symbolic debugging information. */ extern bool use_gnu_debug_info_extensions; diff --git a/contrib/gcc/langhooks-def.h b/contrib/gcc/langhooks-def.h index eae7c928d4e0..633642ca31cc 100644 --- a/contrib/gcc/langhooks-def.h +++ b/contrib/gcc/langhooks-def.h @@ -217,6 +217,7 @@ extern tree lhd_make_node (enum tree_code); so we create a compile-time error instead. */ #define LANG_HOOKS_MAKE_TYPE lhd_make_node #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR lhd_incomplete_type_error +#define LANG_HOOKS_GENERIC_TYPE_P hook_bool_tree_false #define LANG_HOOKS_TYPE_PROMOTES_TO lhd_type_promotes_to #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lhd_register_builtin_type #define LANG_HOOKS_TYPE_MAX_SIZE lhd_return_null_tree @@ -231,6 +232,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_UNSIGNED_TYPE, \ LANG_HOOKS_SIGNED_TYPE, \ LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE, \ + LANG_HOOKS_GENERIC_TYPE_P, \ LANG_HOOKS_TYPE_PROMOTES_TO, \ LANG_HOOKS_REGISTER_BUILTIN_TYPE, \ LANG_HOOKS_INCOMPLETE_TYPE_ERROR, \ diff --git a/contrib/gcc/langhooks.h b/contrib/gcc/langhooks.h index e6148936829c..1254c63992a2 100644 --- a/contrib/gcc/langhooks.h +++ b/contrib/gcc/langhooks.h @@ -119,6 +119,10 @@ struct lang_hooks_for_types according to UNSIGNEDP. */ tree (*signed_or_unsigned_type) (int, tree); + /* True if the type is an instantiation of a generic type, + e.g. C++ template implicit specializations. */ + bool (*generic_p) (tree); + /* Given a type, apply default promotions to unnamed function arguments and return the new type. Return the same type if no change. Required by any language that supports variadic diff --git a/contrib/gcc/opts.c b/contrib/gcc/opts.c index fb122ba017a8..1ded3c711b74 100644 --- a/contrib/gcc/opts.c +++ b/contrib/gcc/opts.c @@ -79,6 +79,256 @@ enum debug_info_type write_symbols = NO_DEBUG; the definitions of the different possible levels. */ enum debug_info_level debug_info_level = DINFO_LEVEL_NONE; +/* A major contribution to object and executable size is debug + information size. A major contribution to debug information size + is struct descriptions replicated in several object files. The + following flags attempt to reduce this information. The basic + idea is to not emit struct debugging information in the current + compilation unit when that information will be generated by + another compilation unit. + + Debug information for a struct defined in the current source + file should be generated in the object file. Likewise the + debug information for a struct defined in a header should be + generated in the object file of the corresponding source file. + Both of these case are handled when the base name of the file of + the struct definition matches the base name of the source file + of thet current compilation unit. This matching emits minimal + struct debugging information. + + The base file name matching rule above will fail to emit debug + information for structs defined in system headers. So a second + category of files includes system headers in addition to files + with matching bases. + + The remaining types of files are library headers and application + headers. We cannot currently distinguish these two types. */ + +enum debug_struct_file +{ + DINFO_STRUCT_FILE_NONE, /* Debug no structs. */ + DINFO_STRUCT_FILE_BASE, /* Debug structs defined in files with the + same base name as the compilation unit. */ + DINFO_STRUCT_FILE_SYS, /* Also debug structs defined in system + header files. */ + DINFO_STRUCT_FILE_ANY /* Debug structs defined in all files. */ +}; + +/* Generic structs (e.g. templates not explicitly specialized) + may not have a compilation unit associated with them, and so + may need to be treated differently from ordinary structs. + + Structs only handled by reference (indirectly), will also usually + not need as much debugging information. */ + +static enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS] + = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }; +static enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS] + = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }; + +/* Parse the -femit-struct-debug-detailed option value + and set the flag variables. */ + +#define MATCH( prefix, string ) \ + ((strncmp (prefix, string, sizeof prefix - 1) == 0) \ + ? ((string += sizeof prefix - 1), 1) : 0) + +void +set_struct_debug_option (const char *spec) +{ + /* various labels for comparison */ + static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:"; + static char ord_lbl[] = "ord:", gen_lbl[] = "gen:"; + static char none_lbl[] = "none", any_lbl[] = "any"; + static char base_lbl[] = "base", sys_lbl[] = "sys"; + + enum debug_struct_file files = DINFO_STRUCT_FILE_ANY; + /* Default is to apply to as much as possible. */ + enum debug_info_usage usage = DINFO_USAGE_NUM_ENUMS; + int ord = 1, gen = 1; + + /* What usage? */ + if (MATCH (dfn_lbl, spec)) + usage = DINFO_USAGE_DFN; + else if (MATCH (dir_lbl, spec)) + usage = DINFO_USAGE_DIR_USE; + else if (MATCH (ind_lbl, spec)) + usage = DINFO_USAGE_IND_USE; + + /* Generics or not? */ + if (MATCH (ord_lbl, spec)) + gen = 0; + else if (MATCH (gen_lbl, spec)) + ord = 0; + + /* What allowable environment? */ + if (MATCH (none_lbl, spec)) + files = DINFO_STRUCT_FILE_NONE; + else if (MATCH (any_lbl, spec)) + files = DINFO_STRUCT_FILE_ANY; + else if (MATCH (sys_lbl, spec)) + files = DINFO_STRUCT_FILE_SYS; + else if (MATCH (base_lbl, spec)) + files = DINFO_STRUCT_FILE_BASE; + else + error ("argument %qs to %<-femit-struct-debug-detailed%> not recognized", + spec); + + /* Effect the specification. */ + if (usage == DINFO_USAGE_NUM_ENUMS) + { + if (ord) + { + debug_struct_ordinary[DINFO_USAGE_DFN] = files; + debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files; + debug_struct_ordinary[DINFO_USAGE_IND_USE] = files; + } + if (gen) + { + debug_struct_generic[DINFO_USAGE_DFN] = files; + debug_struct_generic[DINFO_USAGE_DIR_USE] = files; + debug_struct_generic[DINFO_USAGE_IND_USE] = files; + } + } + else + { + if (ord) + debug_struct_ordinary[usage] = files; + if (gen) + debug_struct_generic[usage] = files; + } + + if (*spec == ',') + set_struct_debug_option (spec+1); + else + { + /* No more -femit-struct-debug-detailed specifications. + Do final checks. */ + if (*spec != '\0') + error ("argument %qs to %<-femit-struct-debug-detailed%> unknown", + spec); + if (debug_struct_ordinary[DINFO_USAGE_DIR_USE] + < debug_struct_ordinary[DINFO_USAGE_IND_USE] + || debug_struct_generic[DINFO_USAGE_DIR_USE] + < debug_struct_generic[DINFO_USAGE_IND_USE]) + error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least" + " as much as %<-femit-struct-debug-detailed=ind:...%>"); + } +} + +/* Find the base name of a path, stripping off both directories and + a single final extension. */ +static int +base_of_path (const char *path, const char **base_out) +{ + const char *base = path; + const char *dot = 0; + const char *p = path; + char c = *p; + while (c) + { + if (IS_DIR_SEPARATOR(c)) + { + base = p + 1; + dot = 0; + } + else if (c == '.') + dot = p; + c = *++p; + } + if (!dot) + dot = p; + *base_out = base; + return dot - base; +} + +/* Match the base name of a file to the base name of a compilation unit. */ + +static const char *main_input_basename; +static int main_input_baselength; + +static int +matches_main_base (const char *path) +{ + /* Cache the last query. */ + static const char *last_path = NULL; + static int last_match = 0; + if (path != last_path) + { + const char *base; + int length = base_of_path (path, &base); + last_path = path; + last_match = (length == main_input_baselength + && memcmp (base, main_input_basename, length) == 0); + } + return last_match; +} + +#ifdef DEBUG_DEBUG_STRUCT + +static int +dump_struct_debug (tree type, enum debug_info_usage usage, + enum debug_struct_file criterion, int generic, + int matches, int result) +{ + /* Find the type name. */ + tree type_decl = TYPE_STUB_DECL (type); + tree t = type_decl; + const char *name = 0; + if (TREE_CODE (t) == TYPE_DECL) + t = DECL_NAME (t); + if (t) + name = IDENTIFIER_POINTER (t); + + fprintf (stderr, " struct %d %s %s %s %s %d %p %s\n", + criterion, + DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr", + matches ? "bas" : "hdr", + generic ? "gen" : "ord", + usage == DINFO_USAGE_DFN ? ";" : + usage == DINFO_USAGE_DIR_USE ? "." : "*", + result, + (void*) type_decl, name); + return result; +} +#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \ + dump_struct_debug (type, usage, criterion, generic, matches, result) + +#else + +#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \ + (result) + +#endif + + +bool +should_emit_struct_debug (tree type, enum debug_info_usage usage) +{ + enum debug_struct_file criterion; + tree type_decl; + bool generic = lang_hooks.types.generic_p (type); + + if (generic) + criterion = debug_struct_generic[usage]; + else + criterion = debug_struct_ordinary[usage]; + + if (criterion == DINFO_STRUCT_FILE_NONE) + return DUMP_GSTRUCT (type, usage, criterion, generic, false, false); + if (criterion == DINFO_STRUCT_FILE_ANY) + return DUMP_GSTRUCT (type, usage, criterion, generic, false, true); + + type_decl = TYPE_STUB_DECL (type); + + if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl)) + return DUMP_GSTRUCT (type, usage, criterion, generic, false, true); + + if (matches_main_base (DECL_SOURCE_FILE (type_decl))) + return DUMP_GSTRUCT (type, usage, criterion, generic, true, true); + return DUMP_GSTRUCT (type, usage, criterion, generic, false, false); +} + /* Nonzero means use GNU-only extensions in the generated symbolic debugging information. Currently, this only has an effect when write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG. */ @@ -370,7 +620,11 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) if (opt[0] != '-' || opt[1] == '\0') { if (main_input_filename == NULL) + { main_input_filename = opt; + main_input_baselength + = base_of_path (main_input_filename, &main_input_basename); + } add_input_filename (opt); n = 1; continue;