diff options
Diffstat (limited to 'gcc-4.7/libiberty/simple-object-mach-o.c')
-rw-r--r-- | gcc-4.7/libiberty/simple-object-mach-o.c | 1377 |
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 -}; |