aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.7/libiberty/simple-object-mach-o.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.7/libiberty/simple-object-mach-o.c')
-rw-r--r--gcc-4.7/libiberty/simple-object-mach-o.c1377
1 files changed, 0 insertions, 1377 deletions
diff --git a/gcc-4.7/libiberty/simple-object-mach-o.c b/gcc-4.7/libiberty/simple-object-mach-o.c
deleted file mode 100644
index af5e4f9ca..000000000
--- a/gcc-4.7/libiberty/simple-object-mach-o.c
+++ /dev/null
@@ -1,1377 +0,0 @@
-/* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
- Copyright 2010, 2011 Free Software Foundation, Inc.
- Written by Ian Lance Taylor, Google.
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 51 Franklin Street - Fifth Floor,
-Boston, MA 02110-1301, USA. */
-
-#include "config.h"
-#include "libiberty.h"
-#include "simple-object.h"
-
-#include <stddef.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
-#include "simple-object-common.h"
-
-/* Mach-O structures and constants. */
-
-/* Mach-O header (32-bit version). */
-
-struct mach_o_header_32
-{
- unsigned char magic[4]; /* Magic number. */
- unsigned char cputype[4]; /* CPU that this object is for. */
- unsigned char cpusubtype[4]; /* CPU subtype. */
- unsigned char filetype[4]; /* Type of file. */
- unsigned char ncmds[4]; /* Number of load commands. */
- unsigned char sizeofcmds[4]; /* Total size of load commands. */
- unsigned char flags[4]; /* Flags for special featues. */
-};
-
-/* Mach-O header (64-bit version). */
-
-struct mach_o_header_64
-{
- unsigned char magic[4]; /* Magic number. */
- unsigned char cputype[4]; /* CPU that this object is for. */
- unsigned char cpusubtype[4]; /* CPU subtype. */
- unsigned char filetype[4]; /* Type of file. */
- unsigned char ncmds[4]; /* Number of load commands. */
- unsigned char sizeofcmds[4]; /* Total size of load commands. */
- unsigned char flags[4]; /* Flags for special featues. */
- unsigned char reserved[4]; /* Reserved. Duh. */
-};
-
-/* For magic field in header. */
-
-#define MACH_O_MH_MAGIC 0xfeedface
-#define MACH_O_MH_MAGIC_64 0xfeedfacf
-
-/* For filetype field in header. */
-
-#define MACH_O_MH_OBJECT 0x01
-
-/* A Mach-O file is a list of load commands. This is the header of a
- load command. */
-
-struct mach_o_load_command
-{
- unsigned char cmd[4]; /* The type of load command. */
- unsigned char cmdsize[4]; /* Size in bytes of entire command. */
-};
-
-/* For cmd field in load command. */
-
-#define MACH_O_LC_SEGMENT 0x01
-#define MACH_O_LC_SEGMENT_64 0x19
-
-/* LC_SEGMENT load command. */
-
-struct mach_o_segment_command_32
-{
- unsigned char cmd[4]; /* The type of load command (LC_SEGMENT). */
- unsigned char cmdsize[4]; /* Size in bytes of entire command. */
- unsigned char segname[16]; /* Name of this segment. */
- unsigned char vmaddr[4]; /* Virtual memory address of this segment. */
- unsigned char vmsize[4]; /* Size there, in bytes. */
- unsigned char fileoff[4]; /* Offset in bytes of the data to be mapped. */
- unsigned char filesize[4]; /* Size in bytes on disk. */
- unsigned char maxprot[4]; /* Maximum permitted vmem protection. */
- unsigned char initprot[4]; /* Initial vmem protection. */
- unsigned char nsects[4]; /* Number of sections in this segment. */
- unsigned char flags[4]; /* Flags that affect the loading. */
-};
-
-/* LC_SEGMENT_64 load command. */
-
-struct mach_o_segment_command_64
-{
- unsigned char cmd[4]; /* The type of load command (LC_SEGMENT_64). */
- unsigned char cmdsize[4]; /* Size in bytes of entire command. */
- unsigned char segname[16]; /* Name of this segment. */
- unsigned char vmaddr[8]; /* Virtual memory address of this segment. */
- unsigned char vmsize[8]; /* Size there, in bytes. */
- unsigned char fileoff[8]; /* Offset in bytes of the data to be mapped. */
- unsigned char filesize[8]; /* Size in bytes on disk. */
- unsigned char maxprot[4]; /* Maximum permitted vmem protection. */
- unsigned char initprot[4]; /* Initial vmem protection. */
- unsigned char nsects[4]; /* Number of sections in this segment. */
- unsigned char flags[4]; /* Flags that affect the loading. */
-};
-
-/* 32-bit section header. */
-
-struct mach_o_section_32
-{
- unsigned char sectname[16]; /* Section name. */
- unsigned char segname[16]; /* Segment that the section belongs to. */
- unsigned char addr[4]; /* Address of this section in memory. */
- unsigned char size[4]; /* Size in bytes of this section. */
- unsigned char offset[4]; /* File offset of this section. */
- unsigned char align[4]; /* log2 of this section's alignment. */
- unsigned char reloff[4]; /* File offset of this section's relocs. */
- unsigned char nreloc[4]; /* Number of relocs for this section. */
- unsigned char flags[4]; /* Section flags/attributes. */
- unsigned char reserved1[4];
- unsigned char reserved2[4];
-};
-
-/* 64-bit section header. */
-
-struct mach_o_section_64
-{
- unsigned char sectname[16]; /* Section name. */
- unsigned char segname[16]; /* Segment that the section belongs to. */
- unsigned char addr[8]; /* Address of this section in memory. */
- unsigned char size[8]; /* Size in bytes of this section. */
- unsigned char offset[4]; /* File offset of this section. */
- unsigned char align[4]; /* log2 of this section's alignment. */
- unsigned char reloff[4]; /* File offset of this section's relocs. */
- unsigned char nreloc[4]; /* Number of relocs for this section. */
- unsigned char flags[4]; /* Section flags/attributes. */
- unsigned char reserved1[4];
- unsigned char reserved2[4];
- unsigned char reserved3[4];
-};
-
-/* Flags for Mach-O sections. */
-
-#define MACH_O_S_ATTR_DEBUG 0x02000000
-
-/* The length of a segment or section name. */
-
-#define MACH_O_NAME_LEN (16)
-
-/* A GNU specific extension for long section names. */
-
-#define GNU_SECTION_NAMES "__section_names"
-
-/* A GNU-specific extension to wrap multiple sections using three
- mach-o sections within a given segment. The section '__wrapper_sects'
- is subdivided according to the index '__wrapper_index' and each sub
- sect is named according to the names supplied in '__wrapper_names'. */
-
-#define GNU_WRAPPER_SECTS "__wrapper_sects"
-#define GNU_WRAPPER_INDEX "__wrapper_index"
-#define GNU_WRAPPER_NAMES "__wrapper_names"
-
-/* Private data for an simple_object_read. */
-
-struct simple_object_mach_o_read
-{
- /* User specified segment name. */
- char *segment_name;
- /* Magic number. */
- unsigned int magic;
- /* Whether this file is big-endian. */
- int is_big_endian;
- /* CPU type from header. */
- unsigned int cputype;
- /* CPU subtype from header. */
- unsigned int cpusubtype;
- /* Number of commands, from header. */
- unsigned int ncmds;
- /* Flags from header. */
- unsigned int flags;
- /* Reserved field from header, only used on 64-bit. */
- unsigned int reserved;
-};
-
-/* Private data for an simple_object_attributes. */
-
-struct simple_object_mach_o_attributes
-{
- /* Magic number. */
- unsigned int magic;
- /* Whether this file is big-endian. */
- int is_big_endian;
- /* CPU type from header. */
- unsigned int cputype;
- /* CPU subtype from header. */
- unsigned int cpusubtype;
- /* Flags from header. */
- unsigned int flags;
- /* Reserved field from header, only used on 64-bit. */
- unsigned int reserved;
-};
-
-/* See if we have a Mach-O MH_OBJECT file:
-
- A standard MH_OBJECT (from as) will have three load commands:
- 0 - LC_SEGMENT/LC_SEGMENT64
- 1 - LC_SYMTAB
- 2 - LC_DYSYMTAB
-
- The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment
- containing all the sections.
-
- Files written by simple-object will have only the segment command
- (no symbol tables). */
-
-static void *
-simple_object_mach_o_match (
- unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
- int descriptor,
- off_t offset,
- const char *segment_name,
- const char **errmsg,
- int *err)
-{
- unsigned int magic;
- int is_big_endian;
- unsigned int (*fetch_32) (const unsigned char *);
- unsigned int filetype;
- struct simple_object_mach_o_read *omr;
- unsigned char buf[sizeof (struct mach_o_header_64)];
- unsigned char *b;
-
- magic = simple_object_fetch_big_32 (header);
- if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
- is_big_endian = 1;
- else
- {
- magic = simple_object_fetch_little_32 (header);
- if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
- is_big_endian = 0;
- else
- {
- *errmsg = NULL;
- *err = 0;
- return NULL;
- }
- }
-
-#ifndef UNSIGNED_64BIT_TYPE
- if (magic == MACH_O_MH_MAGIC_64)
- {
- *errmsg = "64-bit Mach-O objects not supported";
- *err = 0;
- return NULL;
- }
-#endif
-
- /* We require the user to provide a segment name. This is
- unfortunate but I don't see any good choices here. */
-
- if (segment_name == NULL)
- {
- *errmsg = "Mach-O file found but no segment name specified";
- *err = 0;
- return NULL;
- }
-
- if (strlen (segment_name) > MACH_O_NAME_LEN)
- {
- *errmsg = "Mach-O segment name too long";
- *err = 0;
- return NULL;
- }
-
- /* The 32-bit and 64-bit headers are similar enough that we can use
- the same code. */
-
- fetch_32 = (is_big_endian
- ? simple_object_fetch_big_32
- : simple_object_fetch_little_32);
-
- if (!simple_object_internal_read (descriptor, offset, buf,
- (magic == MACH_O_MH_MAGIC
- ? sizeof (struct mach_o_header_32)
- : sizeof (struct mach_o_header_64)),
- errmsg, err))
- return NULL;
-
- b = &buf[0];
-
- filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
- if (filetype != MACH_O_MH_OBJECT)
- {
- *errmsg = "Mach-O file is not object file";
- *err = 0;
- return NULL;
- }
-
- omr = XNEW (struct simple_object_mach_o_read);
- omr->segment_name = xstrdup (segment_name);
- omr->magic = magic;
- omr->is_big_endian = is_big_endian;
- omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
- omr->cpusubtype = (*fetch_32) (b
- + offsetof (struct mach_o_header_32,
- cpusubtype));
- omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
- omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
- if (magic == MACH_O_MH_MAGIC)
- omr->reserved = 0;
- else
- omr->reserved = (*fetch_32) (b
- + offsetof (struct mach_o_header_64,
- reserved));
-
- return (void *) omr;
-}
-
-/* Get the file offset and size from a section header. */
-
-static void
-simple_object_mach_o_section_info (int is_big_endian, int is_32,
- const unsigned char *sechdr, off_t *offset,
- size_t *size)
-{
- unsigned int (*fetch_32) (const unsigned char *);
- ulong_type (*fetch_64) (const unsigned char *);
-
- fetch_32 = (is_big_endian
- ? simple_object_fetch_big_32
- : simple_object_fetch_little_32);
-
- fetch_64 = NULL;
-#ifdef UNSIGNED_64BIT_TYPE
- fetch_64 = (is_big_endian
- ? simple_object_fetch_big_64
- : simple_object_fetch_little_64);
-#endif
-
- if (is_32)
- {
- *offset = fetch_32 (sechdr
- + offsetof (struct mach_o_section_32, offset));
- *size = fetch_32 (sechdr
- + offsetof (struct mach_o_section_32, size));
- }
- else
- {
- *offset = fetch_32 (sechdr
- + offsetof (struct mach_o_section_64, offset));
- *size = fetch_64 (sechdr
- + offsetof (struct mach_o_section_64, size));
- }
-}
-
-/* Handle a segment in a Mach-O Object file.
-
- This will callback to the function pfn for each "section found" the meaning
- of which depends on gnu extensions to mach-o:
-
- If we find mach-o sections (with the segment name as specified) which also
- contain: a 'sects' wrapper, an index, and a name table, we expand this into
- as many sections as are specified in the index. In this case, there will
- be a callback for each of these.
-
- We will also allow an extension that permits long names (more than 16
- characters) to be used with mach-o. In this case, the section name has
- a specific format embedding an index into a name table, and the file must
- contain such name table.
-
- Return 1 if we should continue, 0 if the caller should return. */
-
-#define SOMO_SECTS_PRESENT 0x01
-#define SOMO_INDEX_PRESENT 0x02
-#define SOMO_NAMES_PRESENT 0x04
-#define SOMO_LONGN_PRESENT 0x08
-#define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \
- | SOMO_NAMES_PRESENT)
-
-static int
-simple_object_mach_o_segment (simple_object_read *sobj, off_t offset,
- const unsigned char *segbuf,
- int (*pfn) (void *, const char *, off_t offset,
- off_t length),
- void *data,
- const char **errmsg, int *err)
-{
- struct simple_object_mach_o_read *omr =
- (struct simple_object_mach_o_read *) sobj->data;
- unsigned int (*fetch_32) (const unsigned char *);
- int is_32;
- size_t seghdrsize;
- size_t sechdrsize;
- size_t segname_offset;
- size_t sectname_offset;
- unsigned int nsects;
- unsigned char *secdata;
- unsigned int i;
- unsigned int gnu_sections_found;
- unsigned int strtab_index;
- unsigned int index_index;
- unsigned int nametab_index;
- unsigned int sections_index;
- char *strtab;
- char *nametab;
- unsigned char *index;
- size_t strtab_size;
- size_t nametab_size;
- size_t index_size;
- unsigned int n_wrapped_sects;
- size_t wrapper_sect_size;
- off_t wrapper_sect_offset;
-
- fetch_32 = (omr->is_big_endian
- ? simple_object_fetch_big_32
- : simple_object_fetch_little_32);
-
- is_32 = omr->magic == MACH_O_MH_MAGIC;
-
- if (is_32)
- {
- seghdrsize = sizeof (struct mach_o_segment_command_32);
- sechdrsize = sizeof (struct mach_o_section_32);
- segname_offset = offsetof (struct mach_o_section_32, segname);
- sectname_offset = offsetof (struct mach_o_section_32, sectname);
- nsects = (*fetch_32) (segbuf
- + offsetof (struct mach_o_segment_command_32,
- nsects));
- }
- else
- {
- seghdrsize = sizeof (struct mach_o_segment_command_64);
- sechdrsize = sizeof (struct mach_o_section_64);
- segname_offset = offsetof (struct mach_o_section_64, segname);
- sectname_offset = offsetof (struct mach_o_section_64, sectname);
- nsects = (*fetch_32) (segbuf
- + offsetof (struct mach_o_segment_command_64,
- nsects));
- }
-
- /* Fetch the section headers from the segment command. */
-
- secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
- if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
- secdata, nsects * sechdrsize, errmsg, err))
- {
- XDELETEVEC (secdata);
- return 0;
- }
-
- /* Scan for special sections that signal GNU extensions to the format. */
-
- gnu_sections_found = 0;
- index_index = nsects;
- sections_index = nsects;
- strtab_index = nsects;
- nametab_index = nsects;
- for (i = 0; i < nsects; ++i)
- {
- size_t nameoff;
-
- nameoff = i * sechdrsize + segname_offset;
- if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
- continue;
-
- nameoff = i * sechdrsize + sectname_offset;
- if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0)
- {
- nametab_index = i;
- gnu_sections_found |= SOMO_NAMES_PRESENT;
- }
- else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0)
- {
- index_index = i;
- gnu_sections_found |= SOMO_INDEX_PRESENT;
- }
- else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0)
- {
- sections_index = i;
- gnu_sections_found |= SOMO_SECTS_PRESENT;
- }
- else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
- {
- strtab_index = i;
- gnu_sections_found |= SOMO_LONGN_PRESENT;
- }
- }
-
- /* If any of the special wrapper section components is present, then
- they all should be. */
-
- if ((gnu_sections_found & SOMO_WRAPPING) != 0)
- {
- off_t nametab_offset;
- off_t index_offset;
-
- if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING)
- {
- *errmsg = "GNU Mach-o section wrapper: required section missing";
- *err = 0; /* No useful errno. */
- XDELETEVEC (secdata);
- return 0;
- }
-
- /* Fetch the name table. */
-
- simple_object_mach_o_section_info (omr->is_big_endian, is_32,
- secdata + nametab_index * sechdrsize,
- &nametab_offset, &nametab_size);
- nametab = XNEWVEC (char, nametab_size);
- if (!simple_object_internal_read (sobj->descriptor,
- sobj->offset + nametab_offset,
- (unsigned char *) nametab, nametab_size,
- errmsg, err))
- {
- XDELETEVEC (nametab);
- XDELETEVEC (secdata);
- return 0;
- }
-
- /* Fetch the index. */
-
- simple_object_mach_o_section_info (omr->is_big_endian, is_32,
- secdata + index_index * sechdrsize,
- &index_offset, &index_size);
- index = XNEWVEC (unsigned char, index_size);
- if (!simple_object_internal_read (sobj->descriptor,
- sobj->offset + index_offset,
- index, index_size,
- errmsg, err))
- {
- XDELETEVEC (index);
- XDELETEVEC (nametab);
- XDELETEVEC (secdata);
- return 0;
- }
-
- /* The index contains 4 unsigned ints per sub-section:
- sub-section offset/length, sub-section name/length.
- We fix this for both 32 and 64 bit mach-o for now, since
- other fields limit the maximum size of an object to 4G. */
- n_wrapped_sects = index_size / 16;
-
- /* Get the parameters for the wrapper too. */
- simple_object_mach_o_section_info (omr->is_big_endian, is_32,
- secdata + sections_index * sechdrsize,
- &wrapper_sect_offset,
- &wrapper_sect_size);
- }
- else
- {
- index = NULL;
- index_size = 0;
- nametab = NULL;
- nametab_size = 0;
- n_wrapped_sects = 0;
- }
-
- /* If we have a long names section, fetch it. */
-
- if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
- {
- off_t strtab_offset;
-
- simple_object_mach_o_section_info (omr->is_big_endian, is_32,
- secdata + strtab_index * sechdrsize,
- &strtab_offset, &strtab_size);
- strtab = XNEWVEC (char, strtab_size);
- if (!simple_object_internal_read (sobj->descriptor,
- sobj->offset + strtab_offset,
- (unsigned char *) strtab, strtab_size,
- errmsg, err))
- {
- XDELETEVEC (strtab);
- XDELETEVEC (index);
- XDELETEVEC (nametab);
- XDELETEVEC (secdata);
- return 0;
- }
- }
- else
- {
- strtab = NULL;
- strtab_size = 0;
- strtab_index = nsects;
- }
-
- /* Process the sections. */
-
- for (i = 0; i < nsects; ++i)
- {
- const unsigned char *sechdr;
- char namebuf[MACH_O_NAME_LEN * 2 + 2];
- char *name;
- off_t secoffset;
- size_t secsize;
- int l;
-
- sechdr = secdata + i * sechdrsize;
-
- /* We've already processed the long section names. */
-
- if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0
- && i == strtab_index)
- continue;
-
- /* We only act on the segment named. */
-
- if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
- continue;
-
- /* Process sections associated with the wrapper. */
-
- if ((gnu_sections_found & SOMO_WRAPPING) != 0)
- {
- if (i == nametab_index || i == index_index)
- continue;
-
- if (i == sections_index)
- {
- unsigned int j;
- for (j = 0; j < n_wrapped_sects; ++j)
- {
- unsigned int subsect_offset, subsect_length, name_offset;
- subsect_offset = (*fetch_32) (index + 16 * j);
- subsect_length = (*fetch_32) (index + 16 * j + 4);
- name_offset = (*fetch_32) (index + 16 * j + 8);
- /* We don't need the name_length yet. */
-
- secoffset = wrapper_sect_offset + subsect_offset;
- secsize = subsect_length;
- name = nametab + name_offset;
-
- if (!(*pfn) (data, name, secoffset, secsize))
- {
- *errmsg = NULL;
- *err = 0;
- XDELETEVEC (index);
- XDELETEVEC (nametab);
- XDELETEVEC (strtab);
- XDELETEVEC (secdata);
- return 0;
- }
- }
- continue;
- }
- }
-
- if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
- {
- memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
- namebuf[MACH_O_NAME_LEN] = '\0';
-
- name = &namebuf[0];
- if (strtab != NULL && name[0] == '_' && name[1] == '_')
- {
- unsigned long stringoffset;
-
- if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
- {
- if (stringoffset >= strtab_size)
- {
- *errmsg = "section name offset out of range";
- *err = 0;
- XDELETEVEC (index);
- XDELETEVEC (nametab);
- XDELETEVEC (strtab);
- XDELETEVEC (secdata);
- return 0;
- }
-
- name = strtab + stringoffset;
- }
- }
- }
- else
- {
- /* Otherwise, make a name like __segment,__section as per the
- convention in mach-o asm. */
- name = &namebuf[0];
- memset (namebuf, 0, MACH_O_NAME_LEN * 2 + 2);
- memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
- l = strlen (namebuf);
- namebuf[l] = ',';
- memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
- MACH_O_NAME_LEN);
- }
-
- simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
- &secoffset, &secsize);
-
- if (!(*pfn) (data, name, secoffset, secsize))
- {
- *errmsg = NULL;
- *err = 0;
- XDELETEVEC (index);
- XDELETEVEC (nametab);
- XDELETEVEC (strtab);
- XDELETEVEC (secdata);
- return 0;
- }
- }
-
- XDELETEVEC (index);
- XDELETEVEC (nametab);
- XDELETEVEC (strtab);
- XDELETEVEC (secdata);
-
- return 1;
-}
-
-/* Find all sections in a Mach-O file. */
-
-static const char *
-simple_object_mach_o_find_sections (simple_object_read *sobj,
- int (*pfn) (void *, const char *,
- off_t offset, off_t length),
- void *data,
- int *err)
-{
- struct simple_object_mach_o_read *omr =
- (struct simple_object_mach_o_read *) sobj->data;
- off_t offset;
- size_t seghdrsize;
- unsigned int (*fetch_32) (const unsigned char *);
- const char *errmsg;
- unsigned int i;
-
- if (omr->magic == MACH_O_MH_MAGIC)
- {
- offset = sizeof (struct mach_o_header_32);
- seghdrsize = sizeof (struct mach_o_segment_command_32);
- }
- else
- {
- offset = sizeof (struct mach_o_header_64);
- seghdrsize = sizeof (struct mach_o_segment_command_64);
- }
-
- fetch_32 = (omr->is_big_endian
- ? simple_object_fetch_big_32
- : simple_object_fetch_little_32);
-
- for (i = 0; i < omr->ncmds; ++i)
- {
- unsigned char loadbuf[sizeof (struct mach_o_load_command)];
- unsigned int cmd;
- unsigned int cmdsize;
-
- if (!simple_object_internal_read (sobj->descriptor,
- sobj->offset + offset,
- loadbuf,
- sizeof (struct mach_o_load_command),
- &errmsg, err))
- return errmsg;
-
- cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
- cmdsize = (*fetch_32) (loadbuf
- + offsetof (struct mach_o_load_command, cmdsize));
-
- if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
- {
- unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
- int r;
-
- if (!simple_object_internal_read (sobj->descriptor,
- sobj->offset + offset,
- segbuf, seghdrsize, &errmsg, err))
- return errmsg;
-
- r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
- data, &errmsg, err);
- if (!r)
- return errmsg;
- }
-
- offset += cmdsize;
- }
-
- return NULL;
-}
-
-/* Fetch the attributes for an simple_object_read. */
-
-static void *
-simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
- const char **errmsg ATTRIBUTE_UNUSED,
- int *err ATTRIBUTE_UNUSED)
-{
- struct simple_object_mach_o_read *omr =
- (struct simple_object_mach_o_read *) sobj->data;
- struct simple_object_mach_o_attributes *ret;
-
- ret = XNEW (struct simple_object_mach_o_attributes);
- ret->magic = omr->magic;
- ret->is_big_endian = omr->is_big_endian;
- ret->cputype = omr->cputype;
- ret->cpusubtype = omr->cpusubtype;
- ret->flags = omr->flags;
- ret->reserved = omr->reserved;
- return ret;
-}
-
-/* Release the private data for an simple_object_read. */
-
-static void
-simple_object_mach_o_release_read (void *data)
-{
- struct simple_object_mach_o_read *omr =
- (struct simple_object_mach_o_read *) data;
-
- free (omr->segment_name);
- XDELETE (omr);
-}
-
-/* Compare two attributes structures. */
-
-static const char *
-simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
-{
- struct simple_object_mach_o_attributes *to =
- (struct simple_object_mach_o_attributes *) todata;
- struct simple_object_mach_o_attributes *from =
- (struct simple_object_mach_o_attributes *) fromdata;
-
- if (to->magic != from->magic
- || to->is_big_endian != from->is_big_endian
- || to->cputype != from->cputype)
- {
- *err = 0;
- return "Mach-O object format mismatch";
- }
- return NULL;
-}
-
-/* Release the private data for an attributes structure. */
-
-static void
-simple_object_mach_o_release_attributes (void *data)
-{
- XDELETE (data);
-}
-
-/* Prepare to write out a file. */
-
-static void *
-simple_object_mach_o_start_write (void *attributes_data,
- const char **errmsg ATTRIBUTE_UNUSED,
- int *err ATTRIBUTE_UNUSED)
-{
- struct simple_object_mach_o_attributes *attrs =
- (struct simple_object_mach_o_attributes *) attributes_data;
- struct simple_object_mach_o_attributes *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_mach_o_attributes);
- *ret = *attrs;
- return ret;
-}
-
-/* Write out the header of a Mach-O file. */
-
-static int
-simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
- size_t nsects, const char **errmsg,
- int *err)
-{
- struct simple_object_mach_o_attributes *attrs =
- (struct simple_object_mach_o_attributes *) sobj->data;
- void (*set_32) (unsigned char *, unsigned int);
- unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
- unsigned char *hdr;
- size_t wrsize;
-
- set_32 = (attrs->is_big_endian
- ? simple_object_set_big_32
- : simple_object_set_little_32);
-
- memset (hdrbuf, 0, sizeof hdrbuf);
-
- /* The 32-bit and 64-bit headers start out the same. */
-
- hdr = &hdrbuf[0];
- set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
- set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
- set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
- attrs->cpusubtype);
- set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
- set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
- set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
- if (attrs->magic == MACH_O_MH_MAGIC)
- {
- wrsize = sizeof (struct mach_o_header_32);
- set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
- (sizeof (struct mach_o_segment_command_32)
- + nsects * sizeof (struct mach_o_section_32)));
- }
- else
- {
- set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
- (sizeof (struct mach_o_segment_command_64)
- + nsects * sizeof (struct mach_o_section_64)));
- set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
- attrs->reserved);
- wrsize = sizeof (struct mach_o_header_64);
- }
-
- return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
- errmsg, err);
-}
-
-/* Write a Mach-O section header. */
-
-static int
-simple_object_mach_o_write_section_header (simple_object_write *sobj,
- int descriptor,
- size_t sechdr_offset,
- const char *name, const char *segn,
- size_t secaddr, size_t secsize,
- size_t offset, unsigned int align,
- const char **errmsg, int *err)
-{
- struct simple_object_mach_o_attributes *attrs =
- (struct simple_object_mach_o_attributes *) sobj->data;
- void (*set_32) (unsigned char *, unsigned int);
- unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
- unsigned char *hdr;
- size_t sechdrsize;
-
- set_32 = (attrs->is_big_endian
- ? simple_object_set_big_32
- : simple_object_set_little_32);
-
- memset (hdrbuf, 0, sizeof hdrbuf);
-
- hdr = &hdrbuf[0];
- if (attrs->magic == MACH_O_MH_MAGIC)
- {
- strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
- name, MACH_O_NAME_LEN);
- strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
- segn, MACH_O_NAME_LEN);
- set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
- set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
- set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
- set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
- /* reloff left as zero. */
- /* nreloc left as zero. */
- set_32 (hdr + offsetof (struct mach_o_section_32, flags),
- MACH_O_S_ATTR_DEBUG);
- /* reserved1 left as zero. */
- /* reserved2 left as zero. */
- sechdrsize = sizeof (struct mach_o_section_32);
- }
- else
- {
-#ifdef UNSIGNED_64BIT_TYPE
- void (*set_64) (unsigned char *, ulong_type);
-
- set_64 = (attrs->is_big_endian
- ? simple_object_set_big_64
- : simple_object_set_little_64);
-
- strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
- name, MACH_O_NAME_LEN);
- strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
- segn, MACH_O_NAME_LEN);
- set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
- set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
- set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
- set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
- /* reloff left as zero. */
- /* nreloc left as zero. */
- set_32 (hdr + offsetof (struct mach_o_section_64, flags),
- MACH_O_S_ATTR_DEBUG);
- /* reserved1 left as zero. */
- /* reserved2 left as zero. */
- /* reserved3 left as zero. */
-#endif
- sechdrsize = sizeof (struct mach_o_section_64);
- }
-
- return simple_object_internal_write (descriptor, sechdr_offset, hdr,
- sechdrsize, errmsg, err);
-}
-
-/* Write out the single (anonymous) segment containing the sections of a Mach-O
- Object file.
-
- As a GNU extension to mach-o, when the caller specifies a segment name in
- sobj->segment_name, all the sections passed will be output under a single
- mach-o section header. The caller's sections are indexed within this
- 'wrapper' section by a table stored in a second mach-o section. Finally,
- arbitrary length section names are permitted by the extension and these are
- stored in a table in a third mach-o section.
-
- Note that this is only likely to make any sense for the __GNU_LTO segment
- at present.
-
- If the wrapper extension is not in force, we assume that the section name
- is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */
-
-static int
-simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
- size_t *nsects, const char **errmsg,
- int *err)
-{
- struct simple_object_mach_o_attributes *attrs =
- (struct simple_object_mach_o_attributes *) sobj->data;
- void (*set_32) (unsigned char *, unsigned int);
- size_t hdrsize;
- size_t seghdrsize;
- size_t sechdrsize;
- size_t cmdsize;
- size_t offset;
- size_t sechdr_offset;
- size_t secaddr;
- unsigned int name_offset;
- simple_object_write_section *section;
- unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
- unsigned char *hdr;
- size_t nsects_in;
- unsigned int *index;
- char *snames;
- unsigned int sect;
-
- set_32 = (attrs->is_big_endian
- ? simple_object_set_big_32
- : simple_object_set_little_32);
-
- /* Write out the sections first. */
-
- if (attrs->magic == MACH_O_MH_MAGIC)
- {
- hdrsize = sizeof (struct mach_o_header_32);
- seghdrsize = sizeof (struct mach_o_segment_command_32);
- sechdrsize = sizeof (struct mach_o_section_32);
- }
- else
- {
- hdrsize = sizeof (struct mach_o_header_64);
- seghdrsize = sizeof (struct mach_o_segment_command_64);
- sechdrsize = sizeof (struct mach_o_section_64);
- }
-
- name_offset = 0;
- *nsects = nsects_in = 0;
-
- /* Count the number of sections we start with. */
-
- for (section = sobj->sections; section != NULL; section = section->next)
- nsects_in++;
-
- if (sobj->segment_name != NULL)
- {
- /* We will only write 3 sections: wrapped data, index and names. */
-
- *nsects = 3;
-
- /* The index has four entries per wrapped section:
- Section Offset, length, Name offset, length.
- Where the offsets are based at the start of the wrapper and name
- sections respectively.
- The values are stored as 32 bit int for both 32 and 64 bit mach-o
- since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
- other constraints. */
-
- index = XNEWVEC (unsigned int, nsects_in * 4);
-
- /* We now need to figure out the size of the names section. This just
- stores the names as null-terminated c strings, packed without any
- alignment padding. */
-
- for (section = sobj->sections, sect = 0; section != NULL;
- section = section->next, sect++)
- {
- index[sect*4+2] = name_offset;
- index[sect*4+3] = strlen (section->name) + 1;
- name_offset += strlen (section->name) + 1;
- }
- snames = XNEWVEC (char, name_offset);
- }
- else
- {
- *nsects = nsects_in;
- index = NULL;
- snames = NULL;
- }
-
- sechdr_offset = hdrsize + seghdrsize;
- cmdsize = seghdrsize + *nsects * sechdrsize;
- offset = hdrsize + cmdsize;
- secaddr = 0;
-
- for (section = sobj->sections, sect = 0;
- section != NULL; section = section->next, sect++)
- {
- size_t mask;
- size_t new_offset;
- size_t secsize;
- struct simple_object_write_section_buffer *buffer;
-
- mask = (1U << section->align) - 1;
- new_offset = offset + mask;
- new_offset &= ~ mask;
- while (new_offset > offset)
- {
- unsigned char zeroes[16];
- size_t write;
-
- memset (zeroes, 0, sizeof zeroes);
- write = new_offset - offset;
- if (write > sizeof zeroes)
- write = sizeof zeroes;
- if (!simple_object_internal_write (descriptor, offset, zeroes, write,
- errmsg, err))
- return 0;
- offset += write;
- }
-
- secsize = 0;
- for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
- {
- if (!simple_object_internal_write (descriptor, offset + secsize,
- ((const unsigned char *)
- buffer->buffer),
- buffer->size, errmsg, err))
- return 0;
- secsize += buffer->size;
- }
-
- if (sobj->segment_name != NULL)
- {
- index[sect*4+0] = (unsigned int) offset;
- index[sect*4+1] = secsize;
- /* Stash the section name in our table. */
- memcpy (snames + index[sect * 4 + 2], section->name,
- index[sect * 4 + 3]);
- }
- else
- {
- char namebuf[MACH_O_NAME_LEN + 1];
- char segnbuf[MACH_O_NAME_LEN + 1];
- char *comma;
-
- /* Try to extract segment,section from the input name. */
-
- memset (namebuf, 0, sizeof namebuf);
- memset (segnbuf, 0, sizeof segnbuf);
- comma = strchr (section->name, ',');
- if (comma != NULL)
- {
- int len = comma - section->name;
- len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
- strncpy (namebuf, section->name, len);
- strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
- }
- else /* just try to copy the name, leave segment blank. */
- strncpy (namebuf, section->name, MACH_O_NAME_LEN);
-
- if (!simple_object_mach_o_write_section_header (sobj, descriptor,
- sechdr_offset,
- namebuf, segnbuf,
- secaddr, secsize,
- offset,
- section->align,
- errmsg, err))
- return 0;
- sechdr_offset += sechdrsize;
- }
-
- offset += secsize;
- secaddr += secsize;
- }
-
- if (sobj->segment_name != NULL)
- {
- size_t secsize;
- unsigned int i;
-
- /* Write the section header for the wrapper. */
- /* Account for any initial aligment - which becomes the alignment for this
- created section. */
-
- secsize = (offset - index[0]);
- if (!simple_object_mach_o_write_section_header (sobj, descriptor,
- sechdr_offset,
- GNU_WRAPPER_SECTS,
- sobj->segment_name,
- 0 /*secaddr*/,
- secsize, index[0],
- sobj->sections->align,
- errmsg, err))
- return 0;
-
- /* Subtract the wrapper section start from the begining of each sub
- section. */
-
- for (i = 1; i < nsects_in; ++i)
- index[4 * i] -= index[0];
- index[0] = 0;
-
- sechdr_offset += sechdrsize;
-
- /* Write out the section names.
- ... the header ...
- name_offset contains the length of the section. It is not aligned. */
-
- if (!simple_object_mach_o_write_section_header (sobj, descriptor,
- sechdr_offset,
- GNU_WRAPPER_NAMES,
- sobj->segment_name,
- 0 /*secaddr*/,
- name_offset,
- offset,
- 0, errmsg, err))
- return 0;
-
- /* ... and the content.. */
- if (!simple_object_internal_write (descriptor, offset,
- (const unsigned char *) snames,
- name_offset, errmsg, err))
- return 0;
-
- sechdr_offset += sechdrsize;
- secaddr += name_offset;
- offset += name_offset;
-
- /* Now do the index, we'll align this to 4 bytes although the read code
- will handle unaligned. */
-
- offset += 3;
- offset &= ~0x03;
- if (!simple_object_mach_o_write_section_header (sobj, descriptor,
- sechdr_offset,
- GNU_WRAPPER_INDEX,
- sobj->segment_name,
- 0 /*secaddr*/,
- nsects_in * 16,
- offset,
- 2, errmsg, err))
- return 0;
-
- /* ... and the content.. */
- if (!simple_object_internal_write (descriptor, offset,
- (const unsigned char *) index,
- nsects_in*16, errmsg, err))
- return 0;
-
- XDELETEVEC (index);
- XDELETEVEC (snames);
- }
-
- /* Write out the segment header. */
-
- memset (hdrbuf, 0, sizeof hdrbuf);
-
- hdr = &hdrbuf[0];
- if (attrs->magic == MACH_O_MH_MAGIC)
- {
- set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
- MACH_O_LC_SEGMENT);
- set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
- cmdsize);
- /* MH_OBJECTS have a single, anonymous, segment - so the segment name
- is left empty. */
- /* vmaddr left as zero. */
- /* vmsize left as zero. */
- set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
- hdrsize + cmdsize);
- set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
- offset - (hdrsize + cmdsize));
- /* maxprot left as zero. */
- /* initprot left as zero. */
- set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
- *nsects);
- /* flags left as zero. */
- }
- else
- {
-#ifdef UNSIGNED_64BIT_TYPE
- void (*set_64) (unsigned char *, ulong_type);
-
- set_64 = (attrs->is_big_endian
- ? simple_object_set_big_64
- : simple_object_set_little_64);
-
- set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
- MACH_O_LC_SEGMENT);
- set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
- cmdsize);
- /* MH_OBJECTS have a single, anonymous, segment - so the segment name
- is left empty. */
- /* vmaddr left as zero. */
- /* vmsize left as zero. */
- set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
- hdrsize + cmdsize);
- set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
- offset - (hdrsize + cmdsize));
- /* maxprot left as zero. */
- /* initprot left as zero. */
- set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
- *nsects);
- /* flags left as zero. */
-#endif
- }
-
- return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
- errmsg, err);
-}
-
-/* Write out a complete Mach-O file. */
-
-static const char *
-simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
- int *err)
-{
- size_t nsects = 0;
- const char *errmsg;
-
- if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
- &errmsg, err))
- return errmsg;
-
- if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
- &errmsg, err))
- return errmsg;
-
- return NULL;
-}
-
-/* Release the private data for an simple_object_write structure. */
-
-static void
-simple_object_mach_o_release_write (void *data)
-{
- XDELETE (data);
-}
-
-/* The Mach-O functions. */
-
-const struct simple_object_functions simple_object_mach_o_functions =
-{
- simple_object_mach_o_match,
- simple_object_mach_o_find_sections,
- simple_object_mach_o_fetch_attributes,
- simple_object_mach_o_release_read,
- simple_object_mach_o_attributes_merge,
- 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
-};