aboutsummaryrefslogtreecommitdiff
path: root/libiberty
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2017-08-21 10:29:00 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2017-08-21 10:29:00 +0000
commit1ea85365b430b5ade1d0b824e5406c006e6ffdb7 (patch)
tree3f66db94dd051305b43f1de3bf2077e236deb8a7 /libiberty
parent9f33a5d9acbed950bf446849e9d6968cf22cb9a2 (diff)
downloadgcc-1ea85365b430b5ade1d0b824e5406c006e6ffdb7.zip
gcc-1ea85365b430b5ade1d0b824e5406c006e6ffdb7.tar.gz
gcc-1ea85365b430b5ade1d0b824e5406c006e6ffdb7.tar.bz2
re PR go/78628 (GO fails to build a translation unit decl)
2017-08-21 Richard Biener <rguenther@suse.de> include/ * simple-object.h (simple_object_copy_lto_debug_sections): New function. libiberty/ * simple-object-common.h (struct simple_object_functions): Add copy_lto_debug_sections hook. * simple-object.c: Include fcntl.h. (handle_lto_debug_sections): New helper function. (simple_object_copy_lto_debug_sections): New function copying early LTO debug sections to regular debug sections in a new file. (simple_object_start_write): Handle NULL segment_name. * simple-object-coff.c (simple_object_coff_functions): Adjust for not implemented copy_lto_debug_sections hook. * simple-object-mach-o.c (simple_object_mach_o_functions): Likewise. * simple-object-xcoff.c (simple_object_xcoff_functions): Likewise. * simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL, SHT_GROUP): Add various sectopn header types. (SHF_EXCLUDE): Add flag. (Elf32_External_Sym, Elf64_External_Sym): Add symbol struct. (ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors. (STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types. (STV_DEFAULT): Add symbol visibility. (SHN_COMMON): Add special section index name. (struct simple_object_elf_write): New. (simple_object_elf_start_write): Adjust for new private data. (simple_object_elf_write_shdr): Pass in values for all fields we write. (simple_object_elf_write_to_file): Adjust. Copy from recorded section headers if requested. (simple_object_elf_release_write): Release private data. (simple_object_elf_copy_lto_debug_sections): Copy and rename sections as denoted by PFN and all their dependences, symbols and relocations to the empty destination file. (simple_object_elf_functions): Adjust for copy_lto_debug_sections hook. gcc/ * debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and register_external_die hooks. (debug_false_tree_charstarstar_uhwistar): Declare. (debug_nothing_tree_charstar_uhwi): Likewise. * debug.c (do_nothing_debug_hooks): Adjust. (debug_false_tree_charstarstar_uhwistar): New do nothing. (debug_nothing_tree_charstar_uhwi): Likewise. * dbxout.c (dbx_debug_hooks): Adjust. (xcoff_debug_hooks): Likewise. * sdbout.c (sdb_debug_hooks): Likewise. * vmsdbgout.c (vmsdbg_debug_hooks): Likewise. * dwarf2out.c (macinfo_label_base): New global. (dwarf2out_register_external_die): New function for the register_external_die hook. (dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl. (dwarf2_debug_hooks): Use them. (dwarf2_lineno_debug_hooks): Adjust. (struct die_struct): Add with_offset flag. (DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION, DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION, DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION, DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION, DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros defining section names for the early LTO debug variants. (reset_indirect_string): New helper. (add_AT_external_die_ref): Helper for dwarf2out_register_external_die. (print_dw_val): Add support for offsetted symbol references. (get_ultimate_context): Split out from is_cxx. (is_cxx): Use get_ultimate_context. (is_fortran): Add decl overload. (compute_comp_unit_symbol): Split out worker from compute_section_prefix. (compute_section_prefix): Call compute_comp_unit_symbol and set comdat_type_p here. (output_die): Skip DIE symbol output for the LTO added one. Handle DIE symbol references with offset. (output_comp_unit): Guard section name mangling properly. For LTO debug sections emit a symbol at the section beginning which we use to refer to its DIEs. (add_abstract_origin_attribute): For DIEs registered via dwarf2out_register_external_die directly refer to the early DIE rather than indirectly through the shadow one we created. Remove obsolete call to dwarf2out_abstract_function for non-function/block origins. (gen_array_type_die): When generating early LTO debug do not emit DW_AT_string_length. (gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs late when in LTO. As suggested place a gcc_unreachable for the DECL_ABSTRACT_P case. (gen_subprogram_die): Avoid another specification DIE for early built declarations/definitions for the late LTO case. (gen_variable_die): Add type references for late duplicated VLA dies when in late LTO. (gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function, we have the abstract instance already. (process_scope_var): Adjust decl DIE contexts in LTO which first puts them in limbo. (gen_decl_die): Do not generate type DIEs late apart from types for VLAs or for decls we do not yet have a DIE. Do not call dwarf2out_abstract_function late. (dwarf2out_early_global_decl): Make sure to create DIEs for abstract instances of a decl first. (dwarf2out_late_global_decl): Adjust comment. (output_macinfo_op): With multiple macro sections use macinfo_label_base to distinguish labels. (output_macinfo): Likewise. Update macinfo_label_base. Pass in the line info label. (note_variable_value_in_expr): When generating LTO resolve all variable values here by generating DIEs as needed. (init_sections_and_labels): Add early LTO debug flag parameter and generate different sections and names if set. Add generation counter for the labels so we can have multiple of them. (reset_dies): Helper to allow DIEs to be output multiple times. (dwarf2out_finish): When outputting DIEs to the fat part of an LTO object first reset DIEs. (dwarf2out_early_finish): Output early DIEs when generating LTO. (modified_type_die): Check for decl_ultimate_origin being self before recursing. (gen_type_die_with_usage): Likewise. (gen_typedef_die): Allow decl_ultimate_origin being self. (set_decl_abstract_flags): Remove. (set_block_abstract_flags): Likewise. (dwarf2out_abstract_function): Treat the early generated DIEs as the abstract copy and only add DW_AT_inline and DW_AT_artificial here and call set_decl_origin_self. If the DIE has an abstract origin don't do anything. * tree.c (free_lang_data): Build a dummy TRANSLATION_UNIT_DECL if we have none yet (Go fails to build one, PR78628). (variably_modified_type_p): Prevent endless recursion for Ada cyclic pointer types. * lto-streamer-in.c: Include debug.h. (dref_queue): New global. (lto_read_tree_1): Stream in DIE references. (lto_input_tree): Register DIE references. (input_function): Stream DECL_DEBUG_ARGS. * lto-streamer-out.c: Include debug.h. (lto_write_tree_1): Output DIE references. (DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN. Force a TRANSLATION_UNIT_DECL DECL_CONTEXT for file-scope decls. (output_function): Stream DECL_DEBUG_ARGS. * tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers): Stream DECL_ABSTRACT_ORIGIN. * tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise. (write_ts_decl_minimal_tree_pointers): Force a TRANSLATION_UNIT_DECL DECL_CONTEXT for file-scope decls. * lto-streamer.h (struct dref_entry): Declare. (dref_queue): Likewise. * cfgexpand.c (pass_expand::execute): Do not call the outlining_inline_function hook here. * lto-wrapper.c (debug_obj): New global. (tool_cleanup): Unlink it if required. (debug_objcopy): New function. (run_gcc): Handle early debug sections in the IL files by extracting them to separate files, partially linkin them and feeding the result back as result to the linker. * config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION, DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION, DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug sections into a separate segment. * config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO segments. (darwin_asm_dwarf_section): Likewise. (darwin_asm_output_dwarf_offset): Likewise. * config/i386/i386.c (make_resolver_func): Set DECL_IGNORED_P. lto/ * lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs. (lto_read_decls): Process TRANSLATION_UNIT_DECLs. Remove TYPE_DECL debug processing, register DIE references from prevailing SCCs with the debug machinery. (lto_section_with_id): Handle LTO debug sections. libstdc++/ * testsuite/libstdc++-prettyprinters/prettyprinters.exp: Run all tests with -flto as well if supported. testsuite/ * c-c++-common/asan/global-overflow-1.c: Adjust diagnostic location regex to handle the LTO case. * c-c++-common/asan/heap-overflow-1.c: Likewise. * c-c++-common/asan/misalign-1.c: Likewise. * c-c++-common/asan/misalign-2.c: Likewise. * c-c++-common/asan/null-deref-1.c: Likewise. * c-c++-common/asan/stack-overflow-1.c: Likewise. * c-c++-common/asan/strncpy-overflow-1.c: Likewise. * c-c++-common/asan/use-after-free-1.c: Likewise. * c-c++-common/asan/alloca_big_alignment.c: Likewise. * c-c++-common/asan/alloca_detect_custom_size.c: Likewise. * c-c++-common/asan/alloca_overflow_partial.c: Likewise. * c-c++-common/asan/alloca_overflow_right.c: Likewise. * c-c++-common/asan/alloca_underflow_left.c: Likewise. * g++.dg/asan/large-func-test-1.C: Likewise. * gfortran.dg/save_6.f90: Add -flto -g variant of save_5.f90. From-SVN: r251220
Diffstat (limited to 'libiberty')
-rw-r--r--libiberty/ChangeLog33
-rw-r--r--libiberty/simple-object-coff.c3
-rw-r--r--libiberty/simple-object-common.h6
-rw-r--r--libiberty/simple-object-elf.c482
-rw-r--r--libiberty/simple-object-mach-o.c3
-rw-r--r--libiberty/simple-object-xcoff.c3
-rw-r--r--libiberty/simple-object.c83
7 files changed, 592 insertions, 21 deletions
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 027aa56..48ee098 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,36 @@
+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * simple-object-common.h (struct simple_object_functions): Add
+ copy_lto_debug_sections hook.
+ * simple-object.c: Include fcntl.h.
+ (handle_lto_debug_sections): New helper function.
+ (simple_object_copy_lto_debug_sections): New function copying
+ early LTO debug sections to regular debug sections in a new file.
+ (simple_object_start_write): Handle NULL segment_name.
+ * simple-object-coff.c (simple_object_coff_functions): Adjust
+ for not implemented copy_lto_debug_sections hook.
+ * simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
+ * simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
+ * simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
+ SHT_GROUP): Add various sectopn header types.
+ (SHF_EXCLUDE): Add flag.
+ (Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
+ (ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
+ (STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
+ (STV_DEFAULT): Add symbol visibility.
+ (SHN_COMMON): Add special section index name.
+ (struct simple_object_elf_write): New.
+ (simple_object_elf_start_write): Adjust for new private data.
+ (simple_object_elf_write_shdr): Pass in values for all fields
+ we write.
+ (simple_object_elf_write_to_file): Adjust. Copy from recorded
+ section headers if requested.
+ (simple_object_elf_release_write): Release private data.
+ (simple_object_elf_copy_lto_debug_sections): Copy and rename sections
+ as denoted by PFN and all their dependences, symbols and relocations
+ to the empty destination file.
+ (simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
+
2017-07-02 Jan Kratochvil <jan.kratochvil@redhat.com>
* dwarfnames.c (DW_FIRST_IDX, DW_END_IDX, DW_IDX, DW_IDX_DUP): New.
diff --git a/libiberty/simple-object-coff.c b/libiberty/simple-object-coff.c
index 0283b15..54d430d 100644
--- a/libiberty/simple-object-coff.c
+++ b/libiberty/simple-object-coff.c
@@ -800,5 +800,6 @@ const struct simple_object_functions simple_object_coff_functions =
simple_object_coff_release_attributes,
simple_object_coff_start_write,
simple_object_coff_write_to_file,
- simple_object_coff_release_write
+ simple_object_coff_release_write,
+ NULL
};
diff --git a/libiberty/simple-object-common.h b/libiberty/simple-object-common.h
index cda4038..733bdd0 100644
--- a/libiberty/simple-object-common.h
+++ b/libiberty/simple-object-common.h
@@ -141,6 +141,12 @@ struct simple_object_functions
/* Release the private data for an simple_object_write. */
void (*release_write) (void *);
+
+ /* Copy LTO debug sections. */
+ const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
+ simple_object_write *dobj,
+ int (*pfn) (const char **),
+ int *err);
};
/* The known object file formats. */
diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c
index a733e4b..5633626 100644
--- a/libiberty/simple-object-elf.c
+++ b/libiberty/simple-object-elf.c
@@ -122,9 +122,12 @@ typedef struct {
/* Special section index values. */
+#define SHN_UNDEF 0 /* Undefined section */
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
+#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
+
/* 32-bit ELF program header. */
typedef struct {
@@ -183,8 +186,57 @@ typedef struct {
/* Values for sh_type field. */
+#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Link editing symbol table */
#define SHT_STRTAB 3 /* A string table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_GROUP 17 /* Section contains a section group */
+
+/* Values for sh_flags field. */
+
+#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude this
+ section from executable and
+ shared library that it builds
+ when those objects are not to be
+ further relocated. */
+/* Symbol table entry. */
+
+typedef struct
+{
+ unsigned char st_name[4]; /* Symbol name (string tbl index) */
+ unsigned char st_value[4]; /* Symbol value */
+ unsigned char st_size[4]; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ unsigned char st_shndx[2]; /* Section index */
+} Elf32_External_Sym;
+
+typedef struct
+{
+ unsigned char st_name[4]; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ unsigned char st_shndx[2]; /* Section index */
+ unsigned char st_value[8]; /* Symbol value */
+ unsigned char st_size[8]; /* Symbol size */
+} Elf64_External_Sym;
+
+#define ELF_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF_ST_TYPE(val) ((val) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_TLS 6 /* Thread local data object */
+#define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+
+#define STV_DEFAULT 0 /* Visibility is specified by binding type */
/* Functions to fetch and store different ELF types, depending on the
endianness and size. */
@@ -348,6 +400,14 @@ struct simple_object_elf_attributes
unsigned int flags;
};
+/* Private data for an simple_object_write. */
+
+struct simple_object_elf_write
+{
+ struct simple_object_elf_attributes attrs;
+ unsigned char *shdrs;
+};
+
/* See if we have an ELF file. */
static void *
@@ -675,12 +735,13 @@ simple_object_elf_start_write (void *attributes_data,
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) attributes_data;
- struct simple_object_elf_attributes *ret;
+ struct simple_object_elf_write *ret;
/* We're just going to record the attributes, but we need to make a
copy because the user may delete them. */
- ret = XNEW (struct simple_object_elf_attributes);
- *ret = *attrs;
+ ret = XNEW (struct simple_object_elf_write);
+ ret->attrs = *attrs;
+ ret->shdrs = NULL;
return ret;
}
@@ -766,8 +827,11 @@ static int
simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
off_t offset, unsigned int sh_name,
unsigned int sh_type, unsigned int sh_flags,
+ off_t sh_addr,
unsigned int sh_offset, unsigned int sh_size,
- unsigned int sh_link, unsigned int sh_addralign,
+ unsigned int sh_link, unsigned int sh_info,
+ unsigned int sh_addralign,
+ unsigned int sh_entsize,
const char **errmsg, int *err)
{
struct simple_object_elf_attributes *attrs =
@@ -788,12 +852,13 @@ simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
- /* sh_info left as zero. */
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
- /* sh_entsize left as zero. */
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
return simple_object_internal_write (descriptor, offset, buf, shdr_size,
errmsg, err);
@@ -811,8 +876,9 @@ static const char *
simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
int *err)
{
- struct simple_object_elf_attributes *attrs =
- (struct simple_object_elf_attributes *) sobj->data;
+ struct simple_object_elf_write *eow =
+ (struct simple_object_elf_write *) sobj->data;
+ struct simple_object_elf_attributes *attrs = &eow->attrs;
unsigned char cl;
size_t ehdr_size;
size_t shdr_size;
@@ -825,6 +891,7 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
unsigned int first_sh_link;
size_t sh_name;
unsigned char zero;
+ unsigned secnum;
if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
return errmsg;
@@ -862,21 +929,54 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
else
first_sh_link = shnum - 1;
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- 0, 0, 0, 0, first_sh_size, first_sh_link,
- 0, &errmsg, err))
+ 0, 0, 0, 0, 0, first_sh_size, first_sh_link,
+ 0, 0, 0, &errmsg, err))
return errmsg;
shdr_offset += shdr_size;
sh_name = 1;
+ secnum = 0;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t mask;
size_t new_sh_offset;
size_t sh_size;
struct simple_object_write_section_buffer *buffer;
+ unsigned int sh_type = SHT_PROGBITS;
+ unsigned int sh_flags = 0;
+ off_t sh_addr = 0;
+ unsigned int sh_link = 0;
+ unsigned int sh_info = 0;
+ unsigned int sh_addralign = 1U << section->align;
+ unsigned int sh_entsize = 0;
+ if (eow->shdrs)
+ {
+ sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_type, Elf_Word);
+ sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_flags, Elf_Addr);
+ sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_addr, Elf_Addr);
+ sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_link, Elf_Word);
+ sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_info, Elf_Word);
+ sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_addralign, Elf_Addr);
+ sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_entsize, Elf_Word);
+ secnum++;
+ }
- mask = (1U << section->align) - 1;
+ mask = sh_addralign - 1;
new_sh_offset = sh_offset + mask;
new_sh_offset &= ~ mask;
while (new_sh_offset > sh_offset)
@@ -906,8 +1006,10 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- sh_name, SHT_PROGBITS, 0, sh_offset,
- sh_size, 0, 1U << section->align,
+ sh_name, sh_type, sh_flags,
+ sh_addr, sh_offset,
+ sh_size, sh_link, sh_info,
+ sh_addralign, sh_entsize,
&errmsg, err))
return errmsg;
@@ -917,9 +1019,9 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- sh_name, SHT_STRTAB, 0, sh_offset,
- sh_name + strlen (".shstrtab") + 1, 0,
- 1, &errmsg, err))
+ sh_name, SHT_STRTAB, 0, 0, sh_offset,
+ sh_name + strlen (".shstrtab") + 1, 0, 0,
+ 1, 0, &errmsg, err))
return errmsg;
/* .shstrtab has a leading zero byte. */
@@ -954,9 +1056,354 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
static void
simple_object_elf_release_write (void *data)
{
+ struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+ if (eow->shdrs)
+ XDELETE (eow->shdrs);
XDELETE (data);
}
+/* Copy all sections in an ELF file. */
+
+static const char *
+simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+ simple_object_write *dobj,
+ int (*pfn) (const char **),
+ int *err)
+{
+ struct simple_object_elf_read *eor =
+ (struct simple_object_elf_read *) sobj->data;
+ const struct elf_type_functions *type_functions = eor->type_functions;
+ struct simple_object_elf_write *eow =
+ (struct simple_object_elf_write *) dobj->data;
+ unsigned char ei_class = eor->ei_class;
+ size_t shdr_size;
+ unsigned int shnum;
+ unsigned char *shdrs;
+ const char *errmsg;
+ unsigned char *shstrhdr;
+ size_t name_size;
+ off_t shstroff;
+ unsigned char *names;
+ unsigned int i;
+ int *pfnret;
+ const char **pfnname;
+
+ shdr_size = (ei_class == ELFCLASS32
+ ? sizeof (Elf32_External_Shdr)
+ : sizeof (Elf64_External_Shdr));
+
+ /* Read the section headers. We skip section 0, which is not a
+ useful section. */
+
+ shnum = eor->shnum;
+ shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + eor->shoff + shdr_size,
+ shdrs,
+ shdr_size * (shnum - 1),
+ &errmsg, err))
+ {
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* Read the section names. */
+
+ shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+ name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shstrhdr, sh_size, Elf_Addr);
+ shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shstrhdr, sh_offset, Elf_Addr);
+ names = XNEWVEC (unsigned char, name_size);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + shstroff,
+ names, name_size, &errmsg, err))
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+ pfnret = XNEWVEC (int, shnum);
+ pfnname = XNEWVEC (const char *, shnum);
+
+ /* First perform the callbacks to know which sections to preserve and
+ what name to use for those. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_name;
+ const char *name;
+ int ret;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_name, Elf_Word);
+ if (sh_name >= name_size)
+ {
+ *err = 0;
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return "ELF section name out of range";
+ }
+
+ name = (const char *) names + sh_name;
+
+ ret = (*pfn) (&name);
+ pfnret[i - 1] = ret == 1 ? 0 : -1;
+ pfnname[i - 1] = name;
+ }
+
+ /* Mark sections as preserved that are required by to be preserved
+ sections. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_type, sh_info, sh_link;
+ off_t offset;
+ off_t length;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+ sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_info, Elf_Word);
+ sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ if (sh_type == SHT_GROUP)
+ {
+ /* Mark groups containing copied sections. */
+ unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_entsize, Elf_Addr);
+ unsigned char *ent, *buf;
+ int keep = 0;
+ offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_offset, Elf_Addr);
+ length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_size, Elf_Addr);
+ buf = XNEWVEC (unsigned char, length);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + offset, buf,
+ (size_t) length, &errmsg, err))
+ {
+ XDELETEVEC (buf);
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+ for (ent = buf + entsize; ent < buf + length; ent += entsize)
+ {
+ unsigned sec = type_functions->fetch_Elf_Word (ent);
+ if (pfnret[sec - 1] == 0)
+ keep = 1;
+ }
+ if (keep)
+ {
+ pfnret[sh_link - 1] = 0;
+ pfnret[i - 1] = 0;
+ }
+ }
+ if (sh_type == SHT_RELA
+ || sh_type == SHT_REL)
+ {
+ /* Mark relocation sections and symtab of copied sections. */
+ if (pfnret[sh_info - 1] == 0)
+ {
+ pfnret[sh_link - 1] = 0;
+ pfnret[i - 1] = 0;
+ }
+ }
+ if (sh_type == SHT_SYMTAB)
+ {
+ /* Mark strings sections of copied symtabs. */
+ if (pfnret[i - 1] == 0)
+ pfnret[sh_link - 1] = 0;
+ }
+ }
+
+ /* Then perform the actual copying. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_name, sh_type;
+ const char *name;
+ off_t offset;
+ off_t length;
+ int ret;
+ const char *errmsg;
+ simple_object_write_section *dest;
+ off_t flags;
+ unsigned char *buf;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_name, Elf_Word);
+ if (sh_name >= name_size)
+ {
+ *err = 0;
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return "ELF section name out of range";
+ }
+
+ name = (const char *) names + sh_name;
+ offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_offset, Elf_Addr);
+ length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_size, Elf_Addr);
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+
+ ret = pfnret[i - 1];
+ name = ret == 0 ? pfnname[i - 1] : "";
+
+ dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
+ if (dest == NULL)
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* Record the SHDR of the source. */
+ memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
+ shdr = eow->shdrs + (i - 1) * shdr_size;
+
+ /* Copy the data.
+ ??? This is quite wasteful and ideally would be delayed until
+ write_to_file (). Thus it questions the interfacing
+ which eventually should contain destination creation plus
+ writing. */
+ /* Keep empty sections for sections we should discard. This avoids
+ the need to rewrite section indices in symtab and relocation
+ sections. */
+ if (ret == 0)
+ {
+ buf = XNEWVEC (unsigned char, length);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + offset, buf,
+ (size_t) length, &errmsg, err))
+ {
+ XDELETEVEC (buf);
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* If we are processing .symtab purge __gnu_lto_v1 and
+ __gnu_lto_slim symbols from it. */
+ if (sh_type == SHT_SYMTAB)
+ {
+ unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_entsize, Elf_Addr);
+ unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
+ off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ strshdr, sh_offset, Elf_Addr);
+ size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ strshdr, sh_size, Elf_Addr);
+ char *strings = XNEWVEC (char, strsz);
+ unsigned char *ent;
+ simple_object_internal_read (sobj->descriptor,
+ sobj->offset + stroff,
+ (unsigned char *)strings,
+ strsz, &errmsg, err);
+ for (ent = buf; ent < buf + length; ent += entsize)
+ {
+ unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+ Sym, ent,
+ st_shndx, Elf_Half);
+ unsigned char *st_info;
+ unsigned char *st_other;
+ int discard = 0;
+ if (ei_class == ELFCLASS32)
+ {
+ st_info = &((Elf32_External_Sym *)ent)->st_info;
+ st_other = &((Elf32_External_Sym *)ent)->st_other;
+ }
+ else
+ {
+ st_info = &((Elf64_External_Sym *)ent)->st_info;
+ st_other = &((Elf64_External_Sym *)ent)->st_other;
+ }
+ /* Eliminate all COMMONs - this includes __gnu_lto_v1
+ and __gnu_lto_slim which otherwise cause endless
+ LTO plugin invocation. */
+ if (st_shndx == SHN_COMMON)
+ /* Setting st_name to "" seems to work to purge
+ COMMON symbols (in addition to setting their
+ size to zero). */
+ discard = 1;
+ /* We also need to remove symbols refering to sections
+ we'll eventually remove as with fat LTO objects
+ we otherwise get duplicate symbols at final link
+ (with GNU ld, gold is fine and ignores symbols in
+ sections marked as EXCLUDE). ld/20513 */
+ else if (st_shndx != SHN_UNDEF
+ && st_shndx < shnum
+ && pfnret[st_shndx - 1] == -1)
+ discard = 1;
+
+ if (discard)
+ {
+ /* Make discarded symbols undefined and unnamed. */
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_name, Elf_Word, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_value, Elf_Addr, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_size, Elf_Word, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_shndx, Elf_Half, SHN_UNDEF);
+ *st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
+ STT_NOTYPE);
+ *st_other = STV_DEFAULT;
+ }
+ }
+ XDELETEVEC (strings);
+ }
+
+ errmsg = simple_object_write_add_data (dobj, dest,
+ buf, length, 1, err);
+ XDELETEVEC (buf);
+ if (errmsg)
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+ }
+ else
+ {
+ /* For deleted sections mark the section header table entry as
+ unused. That allows the link editor to remove it in a partial
+ link. */
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Addr, SHT_NULL);
+ }
+
+ flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_flags, Elf_Addr);
+ if (ret == 0)
+ flags &= ~SHF_EXCLUDE;
+ else if (ret == -1)
+ flags |= SHF_EXCLUDE;
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_flags, Elf_Addr, flags);
+ }
+
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (pfnret);
+ XDELETEVEC (pfnname);
+
+ return NULL;
+}
+
+
/* The ELF functions. */
const struct simple_object_functions simple_object_elf_functions =
@@ -969,5 +1416,6 @@ const struct simple_object_functions simple_object_elf_functions =
simple_object_elf_release_attributes,
simple_object_elf_start_write,
simple_object_elf_write_to_file,
- simple_object_elf_release_write
+ simple_object_elf_release_write,
+ simple_object_elf_copy_lto_debug_sections
};
diff --git a/libiberty/simple-object-mach-o.c b/libiberty/simple-object-mach-o.c
index bbadf5d..b90fca8 100644
--- a/libiberty/simple-object-mach-o.c
+++ b/libiberty/simple-object-mach-o.c
@@ -1374,5 +1374,6 @@ const struct simple_object_functions simple_object_mach_o_functions =
simple_object_mach_o_release_attributes,
simple_object_mach_o_start_write,
simple_object_mach_o_write_to_file,
- simple_object_mach_o_release_write
+ simple_object_mach_o_release_write,
+ NULL
};
diff --git a/libiberty/simple-object-xcoff.c b/libiberty/simple-object-xcoff.c
index 7be1bf3..2adebe3 100644
--- a/libiberty/simple-object-xcoff.c
+++ b/libiberty/simple-object-xcoff.c
@@ -1006,5 +1006,6 @@ const struct simple_object_functions simple_object_xcoff_functions =
simple_object_xcoff_release_attributes,
simple_object_xcoff_start_write,
simple_object_xcoff_write_to_file,
- simple_object_xcoff_release_write
+ simple_object_xcoff_release_write,
+ NULL
};
diff --git a/libiberty/simple-object.c b/libiberty/simple-object.c
index 8ea9cf1..553e90f 100644
--- a/libiberty/simple-object.c
+++ b/libiberty/simple-object.c
@@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA. */
#include "simple-object.h"
#include <errno.h>
+#include <fcntl.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -249,6 +250,86 @@ simple_object_find_section (simple_object_read *sobj, const char *name,
return 1;
}
+/* Callback to identify and rename LTO debug sections by name.
+ Returns 1 if NAME is a LTO debug section, 0 if not. */
+
+static int
+handle_lto_debug_sections (const char **name)
+{
+ /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler
+ complains about bogus section flags. Which means we need to arrange
+ for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
+ fat lto object tooling work for the fat part). */
+ /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
+ sections. */
+ /* Copy LTO debug sections and rename them to their non-LTO name. */
+ if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
+ {
+ *name = *name + sizeof (".gnu.debuglto_") - 1;
+ return 1;
+ }
+ else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
+ {
+ *name = *name + sizeof (".gnu.lto_") - 1;
+ return 1;
+ }
+ return 0;
+}
+
+/* Copy LTO debug sections. */
+
+const char *
+simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+ const char *dest, int *err)
+{
+ const char *errmsg;
+ simple_object_write *dest_sobj;
+ simple_object_attributes *attrs;
+ int outfd;
+
+ if (! sobj->functions->copy_lto_debug_sections)
+ {
+ *err = EINVAL;
+ return "simple_object_copy_lto_debug_sections not implemented";
+ }
+
+ attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
+ if (! attrs)
+ return errmsg;
+ dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
+ simple_object_release_attributes (attrs);
+ if (! dest_sobj)
+ return errmsg;
+
+ errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
+ handle_lto_debug_sections,
+ err);
+ if (errmsg)
+ {
+ simple_object_release_write (dest_sobj);
+ return errmsg;
+ }
+
+ outfd = creat (dest, 00777);
+ if (outfd == -1)
+ {
+ *err = errno;
+ simple_object_release_write (dest_sobj);
+ return "open failed";
+ }
+
+ errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
+ close (outfd);
+ if (errmsg)
+ {
+ simple_object_release_write (dest_sobj);
+ return errmsg;
+ }
+
+ simple_object_release_write (dest_sobj);
+ return NULL;
+}
+
/* Fetch attributes. */
simple_object_attributes *
@@ -315,7 +396,7 @@ simple_object_start_write (simple_object_attributes *attrs,
return NULL;
ret = XNEW (simple_object_write);
ret->functions = attrs->functions;
- ret->segment_name = xstrdup (segment_name);
+ ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
ret->sections = NULL;
ret->last_section = NULL;
ret->data = data;