/* simple-object.c -- simple routines to read and write object files.
- Copyright 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
This program is free software; you can redistribute it and/or modify it
#include "simple-object.h"
#include <errno.h>
+#include <fcntl.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#define SEEK_SET 0
#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
#include "simple-object-common.h"
/* The known object file formats. */
{
&simple_object_elf_functions,
&simple_object_mach_o_functions,
- &simple_object_coff_functions
+ &simple_object_coff_functions,
+ &simple_object_xcoff_functions
};
/* Read data from a file using the simple_object error reporting
unsigned char *buffer, size_t size,
const char **errmsg, int *err)
{
- ssize_t got;
-
if (lseek (descriptor, offset, SEEK_SET) < 0)
{
*errmsg = "lseek";
return 0;
}
- got = read (descriptor, buffer, size);
- if (got < 0)
+ do
{
- *errmsg = "read";
- *err = errno;
- return 0;
+ ssize_t got = read (descriptor, buffer, size);
+ if (got == 0)
+ break;
+ else if (got > 0)
+ {
+ buffer += got;
+ size -= got;
+ }
+ else if (errno != EINTR)
+ {
+ *errmsg = "read";
+ *err = errno;
+ return 0;
+ }
}
+ while (size > 0);
- if ((size_t) got < size)
+ if (size > 0)
{
*errmsg = "file too short";
*err = 0;
const unsigned char *buffer, size_t size,
const char **errmsg, int *err)
{
- ssize_t wrote;
-
if (lseek (descriptor, offset, SEEK_SET) < 0)
{
*errmsg = "lseek";
return 0;
}
- wrote = write (descriptor, buffer, size);
- if (wrote < 0)
+ do
{
- *errmsg = "write";
- *err = errno;
- return 0;
+ ssize_t wrote = write (descriptor, buffer, size);
+ if (wrote == 0)
+ break;
+ else if (wrote > 0)
+ {
+ buffer += wrote;
+ size -= wrote;
+ }
+ else if (errno != EINTR)
+ {
+ *errmsg = "write";
+ *err = errno;
+ return 0;
+ }
}
+ while (size > 0);
- if ((size_t) wrote < size)
+ if (size > 0)
{
*errmsg = "short write";
*err = 0;
return 1;
}
+/* Callback to identify and rename LTO debug sections by name.
+ Returns non-NULL if NAME is a LTO debug section, NULL if not.
+ If RENAME is true it will rename LTO debug sections to non-LTO
+ ones. */
+
+static char *
+handle_lto_debug_sections (const char *name, int rename)
+{
+ char *newname = rename ? XCNEWVEC (char, strlen (name) + 1)
+ : xstrdup (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). */
+ /* Also include corresponding reloc sections. */
+ if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0)
+ {
+ if (rename)
+ strncpy (newname, name, sizeof (".rela") - 1);
+ name += sizeof (".rela") - 1;
+ }
+ else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0)
+ {
+ if (rename)
+ strncpy (newname, name, sizeof (".rel") - 1);
+ name += sizeof (".rel") - 1;
+ }
+ /* ??? 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)
+ return rename ? strcat (newname, name + sizeof (".gnu.debuglto_") - 1) : newname;
+ else if (strncmp (name, ".gnu.lto_.debug_",
+ sizeof (".gnu.lto_.debug_") -1) == 0)
+ return rename ? strcat (newname, name + sizeof (".gnu.lto_") - 1) : newname;
+ /* Copy over .note.GNU-stack section under the same name if present. */
+ else if (strcmp (name, ".note.GNU-stack") == 0)
+ return strcpy (newname, name);
+ /* Copy over .comment section under the same name if present. Solaris
+ ld uses them to relax its checking of ELF gABI access rules for
+ COMDAT sections in objects produced by GCC. */
+ else if (strcmp (name, ".comment") == 0)
+ return strcpy (newname, name);
+ free (newname);
+ return NULL;
+}
+
+/* Wrapper for handle_lto_debug_sections. */
+
+static char *
+handle_lto_debug_sections_rename (const char *name)
+{
+ return handle_lto_debug_sections (name, 1);
+}
+
+/* Wrapper for handle_lto_debug_sections. */
+
+static char *
+handle_lto_debug_sections_norename (const char *name)
+{
+ return handle_lto_debug_sections (name, 0);
+}
+
+/* Copy LTO debug sections. */
+
+const char *
+simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+ const char *dest, int *err, int rename)
+{
+ 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,
+ rename ? handle_lto_debug_sections_rename
+ : handle_lto_debug_sections_norename, err);
+ if (errmsg)
+ {
+ simple_object_release_write (dest_sobj);
+ return errmsg;
+ }
+
+ outfd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 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 *
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;