gcc: add femit-struct-debug support to reduce Reduce dwarf debug size
Obtained from: gcc 4.3 (rev. 123909; GPLv2) MFC after: 3 weeks
This commit is contained in:
parent
966b6fbbae
commit
71fd392a23
@ -27,6 +27,57 @@
|
||||
alignment for amdfam10 architecture. Increasing the max loop
|
||||
alignment to 24 bytes.
|
||||
|
||||
2007-04-16 Lawrence Crowl <crowl@google.com>
|
||||
|
||||
* 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 <rguenther@suse.de> (r123736)
|
||||
|
||||
PR tree-optimization/24689
|
||||
|
@ -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;
|
||||
|
@ -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=<spec-list> Detailed reduced debug info for structs
|
||||
|
||||
idirafter
|
||||
C ObjC C++ ObjC++ Joined Separate
|
||||
-idirafter <dir> Add <dir> to the end of the system include path
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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, \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user