1*c50c785cSJohn Marino /* simple-object-mach-o.c -- routines to manipulate Mach-O object files. 2*c50c785cSJohn Marino Copyright 2010 Free Software Foundation, Inc. 3*c50c785cSJohn Marino Written by Ian Lance Taylor, Google. 4*c50c785cSJohn Marino 5*c50c785cSJohn Marino This program is free software; you can redistribute it and/or modify it 6*c50c785cSJohn Marino under the terms of the GNU General Public License as published by the 7*c50c785cSJohn Marino Free Software Foundation; either version 2, or (at your option) any 8*c50c785cSJohn Marino later version. 9*c50c785cSJohn Marino 10*c50c785cSJohn Marino This program is distributed in the hope that it will be useful, 11*c50c785cSJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of 12*c50c785cSJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*c50c785cSJohn Marino GNU General Public License for more details. 14*c50c785cSJohn Marino 15*c50c785cSJohn Marino You should have received a copy of the GNU General Public License 16*c50c785cSJohn Marino along with this program; if not, write to the Free Software 17*c50c785cSJohn Marino Foundation, 51 Franklin Street - Fifth Floor, 18*c50c785cSJohn Marino Boston, MA 02110-1301, USA. */ 19*c50c785cSJohn Marino 20*c50c785cSJohn Marino #include "config.h" 21*c50c785cSJohn Marino #include "libiberty.h" 22*c50c785cSJohn Marino #include "simple-object.h" 23*c50c785cSJohn Marino 24*c50c785cSJohn Marino #include <stddef.h> 25*c50c785cSJohn Marino 26*c50c785cSJohn Marino #ifdef HAVE_STDLIB_H 27*c50c785cSJohn Marino #include <stdlib.h> 28*c50c785cSJohn Marino #endif 29*c50c785cSJohn Marino 30*c50c785cSJohn Marino #ifdef HAVE_STDINT_H 31*c50c785cSJohn Marino #include <stdint.h> 32*c50c785cSJohn Marino #endif 33*c50c785cSJohn Marino 34*c50c785cSJohn Marino #ifdef HAVE_STRING_H 35*c50c785cSJohn Marino #include <string.h> 36*c50c785cSJohn Marino #endif 37*c50c785cSJohn Marino 38*c50c785cSJohn Marino #ifdef HAVE_INTTYPES_H 39*c50c785cSJohn Marino #include <inttypes.h> 40*c50c785cSJohn Marino #endif 41*c50c785cSJohn Marino 42*c50c785cSJohn Marino #include "simple-object-common.h" 43*c50c785cSJohn Marino 44*c50c785cSJohn Marino /* Mach-O structures and constants. */ 45*c50c785cSJohn Marino 46*c50c785cSJohn Marino /* Mach-O header (32-bit version). */ 47*c50c785cSJohn Marino 48*c50c785cSJohn Marino struct mach_o_header_32 49*c50c785cSJohn Marino { 50*c50c785cSJohn Marino unsigned char magic[4]; /* Magic number. */ 51*c50c785cSJohn Marino unsigned char cputype[4]; /* CPU that this object is for. */ 52*c50c785cSJohn Marino unsigned char cpusubtype[4]; /* CPU subtype. */ 53*c50c785cSJohn Marino unsigned char filetype[4]; /* Type of file. */ 54*c50c785cSJohn Marino unsigned char ncmds[4]; /* Number of load commands. */ 55*c50c785cSJohn Marino unsigned char sizeofcmds[4]; /* Total size of load commands. */ 56*c50c785cSJohn Marino unsigned char flags[4]; /* Flags for special featues. */ 57*c50c785cSJohn Marino }; 58*c50c785cSJohn Marino 59*c50c785cSJohn Marino /* Mach-O header (64-bit version). */ 60*c50c785cSJohn Marino 61*c50c785cSJohn Marino struct mach_o_header_64 62*c50c785cSJohn Marino { 63*c50c785cSJohn Marino unsigned char magic[4]; /* Magic number. */ 64*c50c785cSJohn Marino unsigned char cputype[4]; /* CPU that this object is for. */ 65*c50c785cSJohn Marino unsigned char cpusubtype[4]; /* CPU subtype. */ 66*c50c785cSJohn Marino unsigned char filetype[4]; /* Type of file. */ 67*c50c785cSJohn Marino unsigned char ncmds[4]; /* Number of load commands. */ 68*c50c785cSJohn Marino unsigned char sizeofcmds[4]; /* Total size of load commands. */ 69*c50c785cSJohn Marino unsigned char flags[4]; /* Flags for special featues. */ 70*c50c785cSJohn Marino unsigned char reserved[4]; /* Reserved. Duh. */ 71*c50c785cSJohn Marino }; 72*c50c785cSJohn Marino 73*c50c785cSJohn Marino /* For magic field in header. */ 74*c50c785cSJohn Marino 75*c50c785cSJohn Marino #define MACH_O_MH_MAGIC 0xfeedface 76*c50c785cSJohn Marino #define MACH_O_MH_MAGIC_64 0xfeedfacf 77*c50c785cSJohn Marino 78*c50c785cSJohn Marino /* For filetype field in header. */ 79*c50c785cSJohn Marino 80*c50c785cSJohn Marino #define MACH_O_MH_OBJECT 0x01 81*c50c785cSJohn Marino 82*c50c785cSJohn Marino /* A Mach-O file is a list of load commands. This is the header of a 83*c50c785cSJohn Marino load command. */ 84*c50c785cSJohn Marino 85*c50c785cSJohn Marino struct mach_o_load_command 86*c50c785cSJohn Marino { 87*c50c785cSJohn Marino unsigned char cmd[4]; /* The type of load command. */ 88*c50c785cSJohn Marino unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 89*c50c785cSJohn Marino }; 90*c50c785cSJohn Marino 91*c50c785cSJohn Marino /* For cmd field in load command. */ 92*c50c785cSJohn Marino 93*c50c785cSJohn Marino #define MACH_O_LC_SEGMENT 0x01 94*c50c785cSJohn Marino #define MACH_O_LC_SEGMENT_64 0x19 95*c50c785cSJohn Marino 96*c50c785cSJohn Marino /* LC_SEGMENT load command. */ 97*c50c785cSJohn Marino 98*c50c785cSJohn Marino struct mach_o_segment_command_32 99*c50c785cSJohn Marino { 100*c50c785cSJohn Marino unsigned char cmd[4]; /* The type of load command (LC_SEGMENT). */ 101*c50c785cSJohn Marino unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 102*c50c785cSJohn Marino unsigned char segname[16]; /* Name of this segment. */ 103*c50c785cSJohn Marino unsigned char vmaddr[4]; /* Virtual memory address of this segment. */ 104*c50c785cSJohn Marino unsigned char vmsize[4]; /* Size there, in bytes. */ 105*c50c785cSJohn Marino unsigned char fileoff[4]; /* Offset in bytes of the data to be mapped. */ 106*c50c785cSJohn Marino unsigned char filesize[4]; /* Size in bytes on disk. */ 107*c50c785cSJohn Marino unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ 108*c50c785cSJohn Marino unsigned char initprot[4]; /* Initial vmem protection. */ 109*c50c785cSJohn Marino unsigned char nsects[4]; /* Number of sections in this segment. */ 110*c50c785cSJohn Marino unsigned char flags[4]; /* Flags that affect the loading. */ 111*c50c785cSJohn Marino }; 112*c50c785cSJohn Marino 113*c50c785cSJohn Marino /* LC_SEGMENT_64 load command. */ 114*c50c785cSJohn Marino 115*c50c785cSJohn Marino struct mach_o_segment_command_64 116*c50c785cSJohn Marino { 117*c50c785cSJohn Marino unsigned char cmd[4]; /* The type of load command (LC_SEGMENT_64). */ 118*c50c785cSJohn Marino unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 119*c50c785cSJohn Marino unsigned char segname[16]; /* Name of this segment. */ 120*c50c785cSJohn Marino unsigned char vmaddr[8]; /* Virtual memory address of this segment. */ 121*c50c785cSJohn Marino unsigned char vmsize[8]; /* Size there, in bytes. */ 122*c50c785cSJohn Marino unsigned char fileoff[8]; /* Offset in bytes of the data to be mapped. */ 123*c50c785cSJohn Marino unsigned char filesize[8]; /* Size in bytes on disk. */ 124*c50c785cSJohn Marino unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ 125*c50c785cSJohn Marino unsigned char initprot[4]; /* Initial vmem protection. */ 126*c50c785cSJohn Marino unsigned char nsects[4]; /* Number of sections in this segment. */ 127*c50c785cSJohn Marino unsigned char flags[4]; /* Flags that affect the loading. */ 128*c50c785cSJohn Marino }; 129*c50c785cSJohn Marino 130*c50c785cSJohn Marino /* 32-bit section header. */ 131*c50c785cSJohn Marino 132*c50c785cSJohn Marino struct mach_o_section_32 133*c50c785cSJohn Marino { 134*c50c785cSJohn Marino unsigned char sectname[16]; /* Section name. */ 135*c50c785cSJohn Marino unsigned char segname[16]; /* Segment that the section belongs to. */ 136*c50c785cSJohn Marino unsigned char addr[4]; /* Address of this section in memory. */ 137*c50c785cSJohn Marino unsigned char size[4]; /* Size in bytes of this section. */ 138*c50c785cSJohn Marino unsigned char offset[4]; /* File offset of this section. */ 139*c50c785cSJohn Marino unsigned char align[4]; /* log2 of this section's alignment. */ 140*c50c785cSJohn Marino unsigned char reloff[4]; /* File offset of this section's relocs. */ 141*c50c785cSJohn Marino unsigned char nreloc[4]; /* Number of relocs for this section. */ 142*c50c785cSJohn Marino unsigned char flags[4]; /* Section flags/attributes. */ 143*c50c785cSJohn Marino unsigned char reserved1[4]; 144*c50c785cSJohn Marino unsigned char reserved2[4]; 145*c50c785cSJohn Marino }; 146*c50c785cSJohn Marino 147*c50c785cSJohn Marino /* 64-bit section header. */ 148*c50c785cSJohn Marino 149*c50c785cSJohn Marino struct mach_o_section_64 150*c50c785cSJohn Marino { 151*c50c785cSJohn Marino unsigned char sectname[16]; /* Section name. */ 152*c50c785cSJohn Marino unsigned char segname[16]; /* Segment that the section belongs to. */ 153*c50c785cSJohn Marino unsigned char addr[8]; /* Address of this section in memory. */ 154*c50c785cSJohn Marino unsigned char size[8]; /* Size in bytes of this section. */ 155*c50c785cSJohn Marino unsigned char offset[4]; /* File offset of this section. */ 156*c50c785cSJohn Marino unsigned char align[4]; /* log2 of this section's alignment. */ 157*c50c785cSJohn Marino unsigned char reloff[4]; /* File offset of this section's relocs. */ 158*c50c785cSJohn Marino unsigned char nreloc[4]; /* Number of relocs for this section. */ 159*c50c785cSJohn Marino unsigned char flags[4]; /* Section flags/attributes. */ 160*c50c785cSJohn Marino unsigned char reserved1[4]; 161*c50c785cSJohn Marino unsigned char reserved2[4]; 162*c50c785cSJohn Marino unsigned char reserved3[4]; 163*c50c785cSJohn Marino }; 164*c50c785cSJohn Marino 165*c50c785cSJohn Marino /* Flags for Mach-O sections. */ 166*c50c785cSJohn Marino 167*c50c785cSJohn Marino #define MACH_O_S_ATTR_DEBUG 0x02000000 168*c50c785cSJohn Marino 169*c50c785cSJohn Marino /* The length of a segment or section name. */ 170*c50c785cSJohn Marino 171*c50c785cSJohn Marino #define MACH_O_NAME_LEN (16) 172*c50c785cSJohn Marino 173*c50c785cSJohn Marino /* A GNU specific extension for long section names. */ 174*c50c785cSJohn Marino 175*c50c785cSJohn Marino #define GNU_SECTION_NAMES "__section_names" 176*c50c785cSJohn Marino 177*c50c785cSJohn Marino /* Private data for an simple_object_read. */ 178*c50c785cSJohn Marino 179*c50c785cSJohn Marino struct simple_object_mach_o_read 180*c50c785cSJohn Marino { 181*c50c785cSJohn Marino /* User specified segment name. */ 182*c50c785cSJohn Marino char *segment_name; 183*c50c785cSJohn Marino /* Magic number. */ 184*c50c785cSJohn Marino unsigned int magic; 185*c50c785cSJohn Marino /* Whether this file is big-endian. */ 186*c50c785cSJohn Marino int is_big_endian; 187*c50c785cSJohn Marino /* CPU type from header. */ 188*c50c785cSJohn Marino unsigned int cputype; 189*c50c785cSJohn Marino /* CPU subtype from header. */ 190*c50c785cSJohn Marino unsigned int cpusubtype; 191*c50c785cSJohn Marino /* Number of commands, from header. */ 192*c50c785cSJohn Marino unsigned int ncmds; 193*c50c785cSJohn Marino /* Flags from header. */ 194*c50c785cSJohn Marino unsigned int flags; 195*c50c785cSJohn Marino /* Reserved field from header, only used on 64-bit. */ 196*c50c785cSJohn Marino unsigned int reserved; 197*c50c785cSJohn Marino }; 198*c50c785cSJohn Marino 199*c50c785cSJohn Marino /* Private data for an simple_object_attributes. */ 200*c50c785cSJohn Marino 201*c50c785cSJohn Marino struct simple_object_mach_o_attributes 202*c50c785cSJohn Marino { 203*c50c785cSJohn Marino /* Magic number. */ 204*c50c785cSJohn Marino unsigned int magic; 205*c50c785cSJohn Marino /* Whether this file is big-endian. */ 206*c50c785cSJohn Marino int is_big_endian; 207*c50c785cSJohn Marino /* CPU type from header. */ 208*c50c785cSJohn Marino unsigned int cputype; 209*c50c785cSJohn Marino /* CPU subtype from header. */ 210*c50c785cSJohn Marino unsigned int cpusubtype; 211*c50c785cSJohn Marino /* Flags from header. */ 212*c50c785cSJohn Marino unsigned int flags; 213*c50c785cSJohn Marino /* Reserved field from header, only used on 64-bit. */ 214*c50c785cSJohn Marino unsigned int reserved; 215*c50c785cSJohn Marino }; 216*c50c785cSJohn Marino 217*c50c785cSJohn Marino /* See if we have a Mach-O file. */ 218*c50c785cSJohn Marino 219*c50c785cSJohn Marino static void * 220*c50c785cSJohn Marino simple_object_mach_o_match ( 221*c50c785cSJohn Marino unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], 222*c50c785cSJohn Marino int descriptor, 223*c50c785cSJohn Marino off_t offset, 224*c50c785cSJohn Marino const char *segment_name, 225*c50c785cSJohn Marino const char **errmsg, 226*c50c785cSJohn Marino int *err) 227*c50c785cSJohn Marino { 228*c50c785cSJohn Marino unsigned int magic; 229*c50c785cSJohn Marino int is_big_endian; 230*c50c785cSJohn Marino unsigned int (*fetch_32) (const unsigned char *); 231*c50c785cSJohn Marino unsigned int filetype; 232*c50c785cSJohn Marino struct simple_object_mach_o_read *omr; 233*c50c785cSJohn Marino unsigned char buf[sizeof (struct mach_o_header_64)]; 234*c50c785cSJohn Marino unsigned char *b; 235*c50c785cSJohn Marino 236*c50c785cSJohn Marino magic = simple_object_fetch_big_32 (header); 237*c50c785cSJohn Marino if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) 238*c50c785cSJohn Marino is_big_endian = 1; 239*c50c785cSJohn Marino else 240*c50c785cSJohn Marino { 241*c50c785cSJohn Marino magic = simple_object_fetch_little_32 (header); 242*c50c785cSJohn Marino if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) 243*c50c785cSJohn Marino is_big_endian = 0; 244*c50c785cSJohn Marino else 245*c50c785cSJohn Marino { 246*c50c785cSJohn Marino *errmsg = NULL; 247*c50c785cSJohn Marino *err = 0; 248*c50c785cSJohn Marino return NULL; 249*c50c785cSJohn Marino } 250*c50c785cSJohn Marino } 251*c50c785cSJohn Marino 252*c50c785cSJohn Marino #ifndef UNSIGNED_64BIT_TYPE 253*c50c785cSJohn Marino if (magic == MACH_O_MH_MAGIC_64) 254*c50c785cSJohn Marino { 255*c50c785cSJohn Marino *errmsg = "64-bit Mach-O objects not supported"; 256*c50c785cSJohn Marino *err = 0; 257*c50c785cSJohn Marino return NULL; 258*c50c785cSJohn Marino } 259*c50c785cSJohn Marino #endif 260*c50c785cSJohn Marino 261*c50c785cSJohn Marino /* We require the user to provide a segment name. This is 262*c50c785cSJohn Marino unfortunate but I don't see any good choices here. */ 263*c50c785cSJohn Marino 264*c50c785cSJohn Marino if (segment_name == NULL) 265*c50c785cSJohn Marino { 266*c50c785cSJohn Marino *errmsg = "Mach-O file found but no segment name specified"; 267*c50c785cSJohn Marino *err = 0; 268*c50c785cSJohn Marino return NULL; 269*c50c785cSJohn Marino } 270*c50c785cSJohn Marino 271*c50c785cSJohn Marino if (strlen (segment_name) > MACH_O_NAME_LEN) 272*c50c785cSJohn Marino { 273*c50c785cSJohn Marino *errmsg = "Mach-O segment name too long"; 274*c50c785cSJohn Marino *err = 0; 275*c50c785cSJohn Marino return NULL; 276*c50c785cSJohn Marino } 277*c50c785cSJohn Marino 278*c50c785cSJohn Marino /* The 32-bit and 64-bit headers are similar enough that we can use 279*c50c785cSJohn Marino the same code. */ 280*c50c785cSJohn Marino 281*c50c785cSJohn Marino fetch_32 = (is_big_endian 282*c50c785cSJohn Marino ? simple_object_fetch_big_32 283*c50c785cSJohn Marino : simple_object_fetch_little_32); 284*c50c785cSJohn Marino 285*c50c785cSJohn Marino if (!simple_object_internal_read (descriptor, offset, buf, 286*c50c785cSJohn Marino (magic == MACH_O_MH_MAGIC 287*c50c785cSJohn Marino ? sizeof (struct mach_o_header_32) 288*c50c785cSJohn Marino : sizeof (struct mach_o_header_64)), 289*c50c785cSJohn Marino errmsg, err)) 290*c50c785cSJohn Marino return NULL; 291*c50c785cSJohn Marino 292*c50c785cSJohn Marino b = &buf[0]; 293*c50c785cSJohn Marino 294*c50c785cSJohn Marino filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype)); 295*c50c785cSJohn Marino if (filetype != MACH_O_MH_OBJECT) 296*c50c785cSJohn Marino { 297*c50c785cSJohn Marino *errmsg = "Mach-O file is not object file"; 298*c50c785cSJohn Marino *err = 0; 299*c50c785cSJohn Marino return NULL; 300*c50c785cSJohn Marino } 301*c50c785cSJohn Marino 302*c50c785cSJohn Marino omr = XNEW (struct simple_object_mach_o_read); 303*c50c785cSJohn Marino omr->segment_name = xstrdup (segment_name); 304*c50c785cSJohn Marino omr->magic = magic; 305*c50c785cSJohn Marino omr->is_big_endian = is_big_endian; 306*c50c785cSJohn Marino omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype)); 307*c50c785cSJohn Marino omr->cpusubtype = (*fetch_32) (b 308*c50c785cSJohn Marino + offsetof (struct mach_o_header_32, 309*c50c785cSJohn Marino cpusubtype)); 310*c50c785cSJohn Marino omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds)); 311*c50c785cSJohn Marino omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags)); 312*c50c785cSJohn Marino if (magic == MACH_O_MH_MAGIC) 313*c50c785cSJohn Marino omr->reserved = 0; 314*c50c785cSJohn Marino else 315*c50c785cSJohn Marino omr->reserved = (*fetch_32) (b 316*c50c785cSJohn Marino + offsetof (struct mach_o_header_64, 317*c50c785cSJohn Marino reserved)); 318*c50c785cSJohn Marino 319*c50c785cSJohn Marino return (void *) omr; 320*c50c785cSJohn Marino } 321*c50c785cSJohn Marino 322*c50c785cSJohn Marino /* Get the file offset and size from a section header. */ 323*c50c785cSJohn Marino 324*c50c785cSJohn Marino static void 325*c50c785cSJohn Marino simple_object_mach_o_section_info (int is_big_endian, int is_32, 326*c50c785cSJohn Marino const unsigned char *sechdr, off_t *offset, 327*c50c785cSJohn Marino size_t *size) 328*c50c785cSJohn Marino { 329*c50c785cSJohn Marino unsigned int (*fetch_32) (const unsigned char *); 330*c50c785cSJohn Marino ulong_type (*fetch_64) (const unsigned char *); 331*c50c785cSJohn Marino 332*c50c785cSJohn Marino fetch_32 = (is_big_endian 333*c50c785cSJohn Marino ? simple_object_fetch_big_32 334*c50c785cSJohn Marino : simple_object_fetch_little_32); 335*c50c785cSJohn Marino 336*c50c785cSJohn Marino fetch_64 = NULL; 337*c50c785cSJohn Marino #ifdef UNSIGNED_64BIT_TYPE 338*c50c785cSJohn Marino fetch_64 = (is_big_endian 339*c50c785cSJohn Marino ? simple_object_fetch_big_64 340*c50c785cSJohn Marino : simple_object_fetch_little_64); 341*c50c785cSJohn Marino #endif 342*c50c785cSJohn Marino 343*c50c785cSJohn Marino if (is_32) 344*c50c785cSJohn Marino { 345*c50c785cSJohn Marino *offset = fetch_32 (sechdr 346*c50c785cSJohn Marino + offsetof (struct mach_o_section_32, offset)); 347*c50c785cSJohn Marino *size = fetch_32 (sechdr 348*c50c785cSJohn Marino + offsetof (struct mach_o_section_32, size)); 349*c50c785cSJohn Marino } 350*c50c785cSJohn Marino else 351*c50c785cSJohn Marino { 352*c50c785cSJohn Marino *offset = fetch_32 (sechdr 353*c50c785cSJohn Marino + offsetof (struct mach_o_section_64, offset)); 354*c50c785cSJohn Marino *size = fetch_64 (sechdr 355*c50c785cSJohn Marino + offsetof (struct mach_o_section_64, size)); 356*c50c785cSJohn Marino } 357*c50c785cSJohn Marino } 358*c50c785cSJohn Marino 359*c50c785cSJohn Marino /* Handle a segment in a Mach-O file. Return 1 if we should continue, 360*c50c785cSJohn Marino 0 if the caller should return. */ 361*c50c785cSJohn Marino 362*c50c785cSJohn Marino static int 363*c50c785cSJohn Marino simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, 364*c50c785cSJohn Marino const unsigned char *segbuf, 365*c50c785cSJohn Marino int (*pfn) (void *, const char *, off_t offset, 366*c50c785cSJohn Marino off_t length), 367*c50c785cSJohn Marino void *data, 368*c50c785cSJohn Marino const char **errmsg, int *err) 369*c50c785cSJohn Marino { 370*c50c785cSJohn Marino struct simple_object_mach_o_read *omr = 371*c50c785cSJohn Marino (struct simple_object_mach_o_read *) sobj->data; 372*c50c785cSJohn Marino unsigned int (*fetch_32) (const unsigned char *); 373*c50c785cSJohn Marino int is_32; 374*c50c785cSJohn Marino size_t seghdrsize; 375*c50c785cSJohn Marino size_t sechdrsize; 376*c50c785cSJohn Marino size_t segname_offset; 377*c50c785cSJohn Marino size_t sectname_offset; 378*c50c785cSJohn Marino unsigned int nsects; 379*c50c785cSJohn Marino unsigned char *secdata; 380*c50c785cSJohn Marino unsigned int i; 381*c50c785cSJohn Marino unsigned int strtab_index; 382*c50c785cSJohn Marino char *strtab; 383*c50c785cSJohn Marino size_t strtab_size; 384*c50c785cSJohn Marino 385*c50c785cSJohn Marino fetch_32 = (omr->is_big_endian 386*c50c785cSJohn Marino ? simple_object_fetch_big_32 387*c50c785cSJohn Marino : simple_object_fetch_little_32); 388*c50c785cSJohn Marino 389*c50c785cSJohn Marino is_32 = omr->magic == MACH_O_MH_MAGIC; 390*c50c785cSJohn Marino 391*c50c785cSJohn Marino if (is_32) 392*c50c785cSJohn Marino { 393*c50c785cSJohn Marino seghdrsize = sizeof (struct mach_o_segment_command_32); 394*c50c785cSJohn Marino sechdrsize = sizeof (struct mach_o_section_32); 395*c50c785cSJohn Marino segname_offset = offsetof (struct mach_o_section_32, segname); 396*c50c785cSJohn Marino sectname_offset = offsetof (struct mach_o_section_32, sectname); 397*c50c785cSJohn Marino nsects = (*fetch_32) (segbuf 398*c50c785cSJohn Marino + offsetof (struct mach_o_segment_command_32, 399*c50c785cSJohn Marino nsects)); 400*c50c785cSJohn Marino } 401*c50c785cSJohn Marino else 402*c50c785cSJohn Marino { 403*c50c785cSJohn Marino seghdrsize = sizeof (struct mach_o_segment_command_64); 404*c50c785cSJohn Marino sechdrsize = sizeof (struct mach_o_section_64); 405*c50c785cSJohn Marino segname_offset = offsetof (struct mach_o_section_64, segname); 406*c50c785cSJohn Marino sectname_offset = offsetof (struct mach_o_section_64, sectname); 407*c50c785cSJohn Marino nsects = (*fetch_32) (segbuf 408*c50c785cSJohn Marino + offsetof (struct mach_o_segment_command_64, 409*c50c785cSJohn Marino nsects)); 410*c50c785cSJohn Marino } 411*c50c785cSJohn Marino 412*c50c785cSJohn Marino secdata = XNEWVEC (unsigned char, nsects * sechdrsize); 413*c50c785cSJohn Marino if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, 414*c50c785cSJohn Marino secdata, nsects * sechdrsize, errmsg, err)) 415*c50c785cSJohn Marino { 416*c50c785cSJohn Marino XDELETEVEC (secdata); 417*c50c785cSJohn Marino return 0; 418*c50c785cSJohn Marino } 419*c50c785cSJohn Marino 420*c50c785cSJohn Marino /* Scan for a __section_names section. This is in effect a GNU 421*c50c785cSJohn Marino extension that permits section names longer than 16 chars. */ 422*c50c785cSJohn Marino 423*c50c785cSJohn Marino for (i = 0; i < nsects; ++i) 424*c50c785cSJohn Marino { 425*c50c785cSJohn Marino size_t nameoff; 426*c50c785cSJohn Marino 427*c50c785cSJohn Marino nameoff = i * sechdrsize + segname_offset; 428*c50c785cSJohn Marino if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) 429*c50c785cSJohn Marino continue; 430*c50c785cSJohn Marino nameoff = i * sechdrsize + sectname_offset; 431*c50c785cSJohn Marino if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) 432*c50c785cSJohn Marino break; 433*c50c785cSJohn Marino } 434*c50c785cSJohn Marino 435*c50c785cSJohn Marino strtab_index = i; 436*c50c785cSJohn Marino if (strtab_index >= nsects) 437*c50c785cSJohn Marino { 438*c50c785cSJohn Marino strtab = NULL; 439*c50c785cSJohn Marino strtab_size = 0; 440*c50c785cSJohn Marino } 441*c50c785cSJohn Marino else 442*c50c785cSJohn Marino { 443*c50c785cSJohn Marino off_t strtab_offset; 444*c50c785cSJohn Marino 445*c50c785cSJohn Marino simple_object_mach_o_section_info (omr->is_big_endian, is_32, 446*c50c785cSJohn Marino secdata + strtab_index * sechdrsize, 447*c50c785cSJohn Marino &strtab_offset, &strtab_size); 448*c50c785cSJohn Marino strtab = XNEWVEC (char, strtab_size); 449*c50c785cSJohn Marino if (!simple_object_internal_read (sobj->descriptor, 450*c50c785cSJohn Marino sobj->offset + strtab_offset, 451*c50c785cSJohn Marino (unsigned char *) strtab, strtab_size, 452*c50c785cSJohn Marino errmsg, err)) 453*c50c785cSJohn Marino { 454*c50c785cSJohn Marino XDELETEVEC (strtab); 455*c50c785cSJohn Marino XDELETEVEC (secdata); 456*c50c785cSJohn Marino return 0; 457*c50c785cSJohn Marino } 458*c50c785cSJohn Marino } 459*c50c785cSJohn Marino 460*c50c785cSJohn Marino /* Process the sections. */ 461*c50c785cSJohn Marino 462*c50c785cSJohn Marino for (i = 0; i < nsects; ++i) 463*c50c785cSJohn Marino { 464*c50c785cSJohn Marino const unsigned char *sechdr; 465*c50c785cSJohn Marino char namebuf[MACH_O_NAME_LEN + 1]; 466*c50c785cSJohn Marino char *name; 467*c50c785cSJohn Marino off_t secoffset; 468*c50c785cSJohn Marino size_t secsize; 469*c50c785cSJohn Marino 470*c50c785cSJohn Marino if (i == strtab_index) 471*c50c785cSJohn Marino continue; 472*c50c785cSJohn Marino 473*c50c785cSJohn Marino sechdr = secdata + i * sechdrsize; 474*c50c785cSJohn Marino 475*c50c785cSJohn Marino if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) 476*c50c785cSJohn Marino continue; 477*c50c785cSJohn Marino 478*c50c785cSJohn Marino memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); 479*c50c785cSJohn Marino namebuf[MACH_O_NAME_LEN] = '\0'; 480*c50c785cSJohn Marino 481*c50c785cSJohn Marino name = &namebuf[0]; 482*c50c785cSJohn Marino if (strtab != NULL && name[0] == '_' && name[1] == '_') 483*c50c785cSJohn Marino { 484*c50c785cSJohn Marino unsigned long stringoffset; 485*c50c785cSJohn Marino 486*c50c785cSJohn Marino if (sscanf (name + 2, "%08lX", &stringoffset) == 1) 487*c50c785cSJohn Marino { 488*c50c785cSJohn Marino if (stringoffset >= strtab_size) 489*c50c785cSJohn Marino { 490*c50c785cSJohn Marino *errmsg = "section name offset out of range"; 491*c50c785cSJohn Marino *err = 0; 492*c50c785cSJohn Marino XDELETEVEC (strtab); 493*c50c785cSJohn Marino XDELETEVEC (secdata); 494*c50c785cSJohn Marino return 0; 495*c50c785cSJohn Marino } 496*c50c785cSJohn Marino 497*c50c785cSJohn Marino name = strtab + stringoffset; 498*c50c785cSJohn Marino } 499*c50c785cSJohn Marino } 500*c50c785cSJohn Marino 501*c50c785cSJohn Marino simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, 502*c50c785cSJohn Marino &secoffset, &secsize); 503*c50c785cSJohn Marino 504*c50c785cSJohn Marino if (!(*pfn) (data, name, secoffset, secsize)) 505*c50c785cSJohn Marino { 506*c50c785cSJohn Marino *errmsg = NULL; 507*c50c785cSJohn Marino *err = 0; 508*c50c785cSJohn Marino XDELETEVEC (strtab); 509*c50c785cSJohn Marino XDELETEVEC (secdata); 510*c50c785cSJohn Marino return 0; 511*c50c785cSJohn Marino } 512*c50c785cSJohn Marino } 513*c50c785cSJohn Marino 514*c50c785cSJohn Marino XDELETEVEC (strtab); 515*c50c785cSJohn Marino XDELETEVEC (secdata); 516*c50c785cSJohn Marino 517*c50c785cSJohn Marino return 1; 518*c50c785cSJohn Marino } 519*c50c785cSJohn Marino 520*c50c785cSJohn Marino /* Find all sections in a Mach-O file. */ 521*c50c785cSJohn Marino 522*c50c785cSJohn Marino static const char * 523*c50c785cSJohn Marino simple_object_mach_o_find_sections (simple_object_read *sobj, 524*c50c785cSJohn Marino int (*pfn) (void *, const char *, 525*c50c785cSJohn Marino off_t offset, off_t length), 526*c50c785cSJohn Marino void *data, 527*c50c785cSJohn Marino int *err) 528*c50c785cSJohn Marino { 529*c50c785cSJohn Marino struct simple_object_mach_o_read *omr = 530*c50c785cSJohn Marino (struct simple_object_mach_o_read *) sobj->data; 531*c50c785cSJohn Marino off_t offset; 532*c50c785cSJohn Marino size_t seghdrsize; 533*c50c785cSJohn Marino unsigned int (*fetch_32) (const unsigned char *); 534*c50c785cSJohn Marino const char *errmsg; 535*c50c785cSJohn Marino unsigned int i; 536*c50c785cSJohn Marino 537*c50c785cSJohn Marino if (omr->magic == MACH_O_MH_MAGIC) 538*c50c785cSJohn Marino { 539*c50c785cSJohn Marino offset = sizeof (struct mach_o_header_32); 540*c50c785cSJohn Marino seghdrsize = sizeof (struct mach_o_segment_command_32); 541*c50c785cSJohn Marino } 542*c50c785cSJohn Marino else 543*c50c785cSJohn Marino { 544*c50c785cSJohn Marino offset = sizeof (struct mach_o_header_64); 545*c50c785cSJohn Marino seghdrsize = sizeof (struct mach_o_segment_command_64); 546*c50c785cSJohn Marino } 547*c50c785cSJohn Marino 548*c50c785cSJohn Marino fetch_32 = (omr->is_big_endian 549*c50c785cSJohn Marino ? simple_object_fetch_big_32 550*c50c785cSJohn Marino : simple_object_fetch_little_32); 551*c50c785cSJohn Marino 552*c50c785cSJohn Marino for (i = 0; i < omr->ncmds; ++i) 553*c50c785cSJohn Marino { 554*c50c785cSJohn Marino unsigned char loadbuf[sizeof (struct mach_o_load_command)]; 555*c50c785cSJohn Marino unsigned int cmd; 556*c50c785cSJohn Marino unsigned int cmdsize; 557*c50c785cSJohn Marino 558*c50c785cSJohn Marino if (!simple_object_internal_read (sobj->descriptor, 559*c50c785cSJohn Marino sobj->offset + offset, 560*c50c785cSJohn Marino loadbuf, 561*c50c785cSJohn Marino sizeof (struct mach_o_load_command), 562*c50c785cSJohn Marino &errmsg, err)) 563*c50c785cSJohn Marino return errmsg; 564*c50c785cSJohn Marino 565*c50c785cSJohn Marino cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd)); 566*c50c785cSJohn Marino cmdsize = (*fetch_32) (loadbuf 567*c50c785cSJohn Marino + offsetof (struct mach_o_load_command, cmdsize)); 568*c50c785cSJohn Marino 569*c50c785cSJohn Marino if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64) 570*c50c785cSJohn Marino { 571*c50c785cSJohn Marino unsigned char segbuf[sizeof (struct mach_o_segment_command_64)]; 572*c50c785cSJohn Marino int r; 573*c50c785cSJohn Marino 574*c50c785cSJohn Marino if (!simple_object_internal_read (sobj->descriptor, 575*c50c785cSJohn Marino sobj->offset + offset, 576*c50c785cSJohn Marino segbuf, seghdrsize, &errmsg, err)) 577*c50c785cSJohn Marino return errmsg; 578*c50c785cSJohn Marino 579*c50c785cSJohn Marino r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn, 580*c50c785cSJohn Marino data, &errmsg, err); 581*c50c785cSJohn Marino if (!r) 582*c50c785cSJohn Marino return errmsg; 583*c50c785cSJohn Marino } 584*c50c785cSJohn Marino 585*c50c785cSJohn Marino offset += cmdsize; 586*c50c785cSJohn Marino } 587*c50c785cSJohn Marino 588*c50c785cSJohn Marino return NULL; 589*c50c785cSJohn Marino } 590*c50c785cSJohn Marino 591*c50c785cSJohn Marino /* Fetch the attributes for an simple_object_read. */ 592*c50c785cSJohn Marino 593*c50c785cSJohn Marino static void * 594*c50c785cSJohn Marino simple_object_mach_o_fetch_attributes (simple_object_read *sobj, 595*c50c785cSJohn Marino const char **errmsg ATTRIBUTE_UNUSED, 596*c50c785cSJohn Marino int *err ATTRIBUTE_UNUSED) 597*c50c785cSJohn Marino { 598*c50c785cSJohn Marino struct simple_object_mach_o_read *omr = 599*c50c785cSJohn Marino (struct simple_object_mach_o_read *) sobj->data; 600*c50c785cSJohn Marino struct simple_object_mach_o_attributes *ret; 601*c50c785cSJohn Marino 602*c50c785cSJohn Marino ret = XNEW (struct simple_object_mach_o_attributes); 603*c50c785cSJohn Marino ret->magic = omr->magic; 604*c50c785cSJohn Marino ret->is_big_endian = omr->is_big_endian; 605*c50c785cSJohn Marino ret->cputype = omr->cputype; 606*c50c785cSJohn Marino ret->cpusubtype = omr->cpusubtype; 607*c50c785cSJohn Marino ret->flags = omr->flags; 608*c50c785cSJohn Marino ret->reserved = omr->reserved; 609*c50c785cSJohn Marino return ret; 610*c50c785cSJohn Marino } 611*c50c785cSJohn Marino 612*c50c785cSJohn Marino /* Release the private data for an simple_object_read. */ 613*c50c785cSJohn Marino 614*c50c785cSJohn Marino static void 615*c50c785cSJohn Marino simple_object_mach_o_release_read (void *data) 616*c50c785cSJohn Marino { 617*c50c785cSJohn Marino struct simple_object_mach_o_read *omr = 618*c50c785cSJohn Marino (struct simple_object_mach_o_read *) data; 619*c50c785cSJohn Marino 620*c50c785cSJohn Marino free (omr->segment_name); 621*c50c785cSJohn Marino XDELETE (omr); 622*c50c785cSJohn Marino } 623*c50c785cSJohn Marino 624*c50c785cSJohn Marino /* Compare two attributes structures. */ 625*c50c785cSJohn Marino 626*c50c785cSJohn Marino static const char * 627*c50c785cSJohn Marino simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err) 628*c50c785cSJohn Marino { 629*c50c785cSJohn Marino struct simple_object_mach_o_attributes *to = 630*c50c785cSJohn Marino (struct simple_object_mach_o_attributes *) todata; 631*c50c785cSJohn Marino struct simple_object_mach_o_attributes *from = 632*c50c785cSJohn Marino (struct simple_object_mach_o_attributes *) fromdata; 633*c50c785cSJohn Marino 634*c50c785cSJohn Marino if (to->magic != from->magic 635*c50c785cSJohn Marino || to->is_big_endian != from->is_big_endian 636*c50c785cSJohn Marino || to->cputype != from->cputype) 637*c50c785cSJohn Marino { 638*c50c785cSJohn Marino *err = 0; 639*c50c785cSJohn Marino return "Mach-O object format mismatch"; 640*c50c785cSJohn Marino } 641*c50c785cSJohn Marino return NULL; 642*c50c785cSJohn Marino } 643*c50c785cSJohn Marino 644*c50c785cSJohn Marino /* Release the private data for an attributes structure. */ 645*c50c785cSJohn Marino 646*c50c785cSJohn Marino static void 647*c50c785cSJohn Marino simple_object_mach_o_release_attributes (void *data) 648*c50c785cSJohn Marino { 649*c50c785cSJohn Marino XDELETE (data); 650*c50c785cSJohn Marino } 651*c50c785cSJohn Marino 652*c50c785cSJohn Marino /* Prepare to write out a file. */ 653*c50c785cSJohn Marino 654*c50c785cSJohn Marino static void * 655*c50c785cSJohn Marino simple_object_mach_o_start_write (void *attributes_data, 656*c50c785cSJohn Marino const char **errmsg ATTRIBUTE_UNUSED, 657*c50c785cSJohn Marino int *err ATTRIBUTE_UNUSED) 658*c50c785cSJohn Marino { 659*c50c785cSJohn Marino struct simple_object_mach_o_attributes *attrs = 660*c50c785cSJohn Marino (struct simple_object_mach_o_attributes *) attributes_data; 661*c50c785cSJohn Marino struct simple_object_mach_o_attributes *ret; 662*c50c785cSJohn Marino 663*c50c785cSJohn Marino /* We're just going to record the attributes, but we need to make a 664*c50c785cSJohn Marino copy because the user may delete them. */ 665*c50c785cSJohn Marino ret = XNEW (struct simple_object_mach_o_attributes); 666*c50c785cSJohn Marino *ret = *attrs; 667*c50c785cSJohn Marino return ret; 668*c50c785cSJohn Marino } 669*c50c785cSJohn Marino 670*c50c785cSJohn Marino /* Write out the header of a Mach-O file. */ 671*c50c785cSJohn Marino 672*c50c785cSJohn Marino static int 673*c50c785cSJohn Marino simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor, 674*c50c785cSJohn Marino size_t nsects, const char **errmsg, 675*c50c785cSJohn Marino int *err) 676*c50c785cSJohn Marino { 677*c50c785cSJohn Marino struct simple_object_mach_o_attributes *attrs = 678*c50c785cSJohn Marino (struct simple_object_mach_o_attributes *) sobj->data; 679*c50c785cSJohn Marino void (*set_32) (unsigned char *, unsigned int); 680*c50c785cSJohn Marino unsigned char hdrbuf[sizeof (struct mach_o_header_64)]; 681*c50c785cSJohn Marino unsigned char *hdr; 682*c50c785cSJohn Marino size_t wrsize; 683*c50c785cSJohn Marino 684*c50c785cSJohn Marino set_32 = (attrs->is_big_endian 685*c50c785cSJohn Marino ? simple_object_set_big_32 686*c50c785cSJohn Marino : simple_object_set_little_32); 687*c50c785cSJohn Marino 688*c50c785cSJohn Marino memset (hdrbuf, 0, sizeof hdrbuf); 689*c50c785cSJohn Marino 690*c50c785cSJohn Marino /* The 32-bit and 64-bit headers start out the same. */ 691*c50c785cSJohn Marino 692*c50c785cSJohn Marino hdr = &hdrbuf[0]; 693*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic); 694*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype); 695*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype), 696*c50c785cSJohn Marino attrs->cpusubtype); 697*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT); 698*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1); 699*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags); 700*c50c785cSJohn Marino if (attrs->magic == MACH_O_MH_MAGIC) 701*c50c785cSJohn Marino { 702*c50c785cSJohn Marino wrsize = sizeof (struct mach_o_header_32); 703*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds), 704*c50c785cSJohn Marino (sizeof (struct mach_o_segment_command_32) 705*c50c785cSJohn Marino + nsects * sizeof (struct mach_o_section_32))); 706*c50c785cSJohn Marino } 707*c50c785cSJohn Marino else 708*c50c785cSJohn Marino { 709*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds), 710*c50c785cSJohn Marino (sizeof (struct mach_o_segment_command_64) 711*c50c785cSJohn Marino + nsects * sizeof (struct mach_o_section_64))); 712*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_header_64, reserved), 713*c50c785cSJohn Marino attrs->reserved); 714*c50c785cSJohn Marino wrsize = sizeof (struct mach_o_header_64); 715*c50c785cSJohn Marino } 716*c50c785cSJohn Marino 717*c50c785cSJohn Marino return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize, 718*c50c785cSJohn Marino errmsg, err); 719*c50c785cSJohn Marino } 720*c50c785cSJohn Marino 721*c50c785cSJohn Marino /* Write a Mach-O section header. */ 722*c50c785cSJohn Marino 723*c50c785cSJohn Marino static int 724*c50c785cSJohn Marino simple_object_mach_o_write_section_header (simple_object_write *sobj, 725*c50c785cSJohn Marino int descriptor, 726*c50c785cSJohn Marino size_t sechdr_offset, 727*c50c785cSJohn Marino const char *name, size_t secaddr, 728*c50c785cSJohn Marino size_t secsize, size_t offset, 729*c50c785cSJohn Marino unsigned int align, 730*c50c785cSJohn Marino const char **errmsg, int *err) 731*c50c785cSJohn Marino { 732*c50c785cSJohn Marino struct simple_object_mach_o_attributes *attrs = 733*c50c785cSJohn Marino (struct simple_object_mach_o_attributes *) sobj->data; 734*c50c785cSJohn Marino void (*set_32) (unsigned char *, unsigned int); 735*c50c785cSJohn Marino unsigned char hdrbuf[sizeof (struct mach_o_section_64)]; 736*c50c785cSJohn Marino unsigned char *hdr; 737*c50c785cSJohn Marino size_t sechdrsize; 738*c50c785cSJohn Marino 739*c50c785cSJohn Marino set_32 = (attrs->is_big_endian 740*c50c785cSJohn Marino ? simple_object_set_big_32 741*c50c785cSJohn Marino : simple_object_set_little_32); 742*c50c785cSJohn Marino 743*c50c785cSJohn Marino memset (hdrbuf, 0, sizeof hdrbuf); 744*c50c785cSJohn Marino 745*c50c785cSJohn Marino hdr = &hdrbuf[0]; 746*c50c785cSJohn Marino if (attrs->magic == MACH_O_MH_MAGIC) 747*c50c785cSJohn Marino { 748*c50c785cSJohn Marino strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), 749*c50c785cSJohn Marino name, MACH_O_NAME_LEN); 750*c50c785cSJohn Marino strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), 751*c50c785cSJohn Marino sobj->segment_name, MACH_O_NAME_LEN); 752*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); 753*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); 754*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); 755*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_32, align), align); 756*c50c785cSJohn Marino /* reloff left as zero. */ 757*c50c785cSJohn Marino /* nreloc left as zero. */ 758*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_32, flags), 759*c50c785cSJohn Marino MACH_O_S_ATTR_DEBUG); 760*c50c785cSJohn Marino /* reserved1 left as zero. */ 761*c50c785cSJohn Marino /* reserved2 left as zero. */ 762*c50c785cSJohn Marino sechdrsize = sizeof (struct mach_o_section_32); 763*c50c785cSJohn Marino } 764*c50c785cSJohn Marino else 765*c50c785cSJohn Marino { 766*c50c785cSJohn Marino #ifdef UNSIGNED_64BIT_TYPE 767*c50c785cSJohn Marino void (*set_64) (unsigned char *, ulong_type); 768*c50c785cSJohn Marino 769*c50c785cSJohn Marino set_64 = (attrs->is_big_endian 770*c50c785cSJohn Marino ? simple_object_set_big_64 771*c50c785cSJohn Marino : simple_object_set_little_64); 772*c50c785cSJohn Marino 773*c50c785cSJohn Marino strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), 774*c50c785cSJohn Marino name, MACH_O_NAME_LEN); 775*c50c785cSJohn Marino strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), 776*c50c785cSJohn Marino sobj->segment_name, MACH_O_NAME_LEN); 777*c50c785cSJohn Marino set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); 778*c50c785cSJohn Marino set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); 779*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); 780*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_64, align), align); 781*c50c785cSJohn Marino /* reloff left as zero. */ 782*c50c785cSJohn Marino /* nreloc left as zero. */ 783*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_section_64, flags), 784*c50c785cSJohn Marino MACH_O_S_ATTR_DEBUG); 785*c50c785cSJohn Marino /* reserved1 left as zero. */ 786*c50c785cSJohn Marino /* reserved2 left as zero. */ 787*c50c785cSJohn Marino /* reserved3 left as zero. */ 788*c50c785cSJohn Marino #endif 789*c50c785cSJohn Marino sechdrsize = sizeof (struct mach_o_section_64); 790*c50c785cSJohn Marino } 791*c50c785cSJohn Marino 792*c50c785cSJohn Marino return simple_object_internal_write (descriptor, sechdr_offset, hdr, 793*c50c785cSJohn Marino sechdrsize, errmsg, err); 794*c50c785cSJohn Marino } 795*c50c785cSJohn Marino 796*c50c785cSJohn Marino /* Write out the single segment and the sections of a Mach-O file. */ 797*c50c785cSJohn Marino 798*c50c785cSJohn Marino static int 799*c50c785cSJohn Marino simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, 800*c50c785cSJohn Marino size_t nsects, const char **errmsg, 801*c50c785cSJohn Marino int *err) 802*c50c785cSJohn Marino { 803*c50c785cSJohn Marino struct simple_object_mach_o_attributes *attrs = 804*c50c785cSJohn Marino (struct simple_object_mach_o_attributes *) sobj->data; 805*c50c785cSJohn Marino void (*set_32) (unsigned char *, unsigned int); 806*c50c785cSJohn Marino size_t hdrsize; 807*c50c785cSJohn Marino size_t seghdrsize; 808*c50c785cSJohn Marino size_t sechdrsize; 809*c50c785cSJohn Marino size_t cmdsize; 810*c50c785cSJohn Marino size_t offset; 811*c50c785cSJohn Marino size_t sechdr_offset; 812*c50c785cSJohn Marino size_t secaddr; 813*c50c785cSJohn Marino unsigned int name_offset; 814*c50c785cSJohn Marino simple_object_write_section *section; 815*c50c785cSJohn Marino unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; 816*c50c785cSJohn Marino unsigned char *hdr; 817*c50c785cSJohn Marino 818*c50c785cSJohn Marino set_32 = (attrs->is_big_endian 819*c50c785cSJohn Marino ? simple_object_set_big_32 820*c50c785cSJohn Marino : simple_object_set_little_32); 821*c50c785cSJohn Marino 822*c50c785cSJohn Marino /* Write out the sections first. */ 823*c50c785cSJohn Marino 824*c50c785cSJohn Marino if (attrs->magic == MACH_O_MH_MAGIC) 825*c50c785cSJohn Marino { 826*c50c785cSJohn Marino hdrsize = sizeof (struct mach_o_header_32); 827*c50c785cSJohn Marino seghdrsize = sizeof (struct mach_o_segment_command_32); 828*c50c785cSJohn Marino sechdrsize = sizeof (struct mach_o_section_32); 829*c50c785cSJohn Marino } 830*c50c785cSJohn Marino else 831*c50c785cSJohn Marino { 832*c50c785cSJohn Marino hdrsize = sizeof (struct mach_o_header_64); 833*c50c785cSJohn Marino seghdrsize = sizeof (struct mach_o_segment_command_64); 834*c50c785cSJohn Marino sechdrsize = sizeof (struct mach_o_section_64); 835*c50c785cSJohn Marino } 836*c50c785cSJohn Marino 837*c50c785cSJohn Marino sechdr_offset = hdrsize + seghdrsize; 838*c50c785cSJohn Marino cmdsize = seghdrsize + nsects * sechdrsize; 839*c50c785cSJohn Marino offset = hdrsize + cmdsize; 840*c50c785cSJohn Marino name_offset = 0; 841*c50c785cSJohn Marino secaddr = 0; 842*c50c785cSJohn Marino 843*c50c785cSJohn Marino for (section = sobj->sections; section != NULL; section = section->next) 844*c50c785cSJohn Marino { 845*c50c785cSJohn Marino size_t mask; 846*c50c785cSJohn Marino size_t new_offset; 847*c50c785cSJohn Marino size_t secsize; 848*c50c785cSJohn Marino struct simple_object_write_section_buffer *buffer; 849*c50c785cSJohn Marino char namebuf[MACH_O_NAME_LEN + 1]; 850*c50c785cSJohn Marino 851*c50c785cSJohn Marino mask = (1U << section->align) - 1; 852*c50c785cSJohn Marino new_offset = offset + mask; 853*c50c785cSJohn Marino new_offset &= ~ mask; 854*c50c785cSJohn Marino while (new_offset > offset) 855*c50c785cSJohn Marino { 856*c50c785cSJohn Marino unsigned char zeroes[16]; 857*c50c785cSJohn Marino size_t write; 858*c50c785cSJohn Marino 859*c50c785cSJohn Marino memset (zeroes, 0, sizeof zeroes); 860*c50c785cSJohn Marino write = new_offset - offset; 861*c50c785cSJohn Marino if (write > sizeof zeroes) 862*c50c785cSJohn Marino write = sizeof zeroes; 863*c50c785cSJohn Marino if (!simple_object_internal_write (descriptor, offset, zeroes, write, 864*c50c785cSJohn Marino errmsg, err)) 865*c50c785cSJohn Marino return 0; 866*c50c785cSJohn Marino offset += write; 867*c50c785cSJohn Marino } 868*c50c785cSJohn Marino 869*c50c785cSJohn Marino secsize = 0; 870*c50c785cSJohn Marino for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 871*c50c785cSJohn Marino { 872*c50c785cSJohn Marino if (!simple_object_internal_write (descriptor, offset + secsize, 873*c50c785cSJohn Marino ((const unsigned char *) 874*c50c785cSJohn Marino buffer->buffer), 875*c50c785cSJohn Marino buffer->size, errmsg, err)) 876*c50c785cSJohn Marino return 0; 877*c50c785cSJohn Marino secsize += buffer->size; 878*c50c785cSJohn Marino } 879*c50c785cSJohn Marino 880*c50c785cSJohn Marino snprintf (namebuf, sizeof namebuf, "__%08X", name_offset); 881*c50c785cSJohn Marino if (!simple_object_mach_o_write_section_header (sobj, descriptor, 882*c50c785cSJohn Marino sechdr_offset, namebuf, 883*c50c785cSJohn Marino secaddr, secsize, offset, 884*c50c785cSJohn Marino section->align, 885*c50c785cSJohn Marino errmsg, err)) 886*c50c785cSJohn Marino return 0; 887*c50c785cSJohn Marino 888*c50c785cSJohn Marino sechdr_offset += sechdrsize; 889*c50c785cSJohn Marino offset += secsize; 890*c50c785cSJohn Marino name_offset += strlen (section->name) + 1; 891*c50c785cSJohn Marino secaddr += secsize; 892*c50c785cSJohn Marino } 893*c50c785cSJohn Marino 894*c50c785cSJohn Marino /* Write out the section names. */ 895*c50c785cSJohn Marino 896*c50c785cSJohn Marino if (!simple_object_mach_o_write_section_header (sobj, descriptor, 897*c50c785cSJohn Marino sechdr_offset, 898*c50c785cSJohn Marino GNU_SECTION_NAMES, secaddr, 899*c50c785cSJohn Marino name_offset, offset, 0, 900*c50c785cSJohn Marino errmsg, err)) 901*c50c785cSJohn Marino return 0; 902*c50c785cSJohn Marino 903*c50c785cSJohn Marino for (section = sobj->sections; section != NULL; section = section->next) 904*c50c785cSJohn Marino { 905*c50c785cSJohn Marino size_t namelen; 906*c50c785cSJohn Marino 907*c50c785cSJohn Marino namelen = strlen (section->name) + 1; 908*c50c785cSJohn Marino if (!simple_object_internal_write (descriptor, offset, 909*c50c785cSJohn Marino (const unsigned char *) section->name, 910*c50c785cSJohn Marino namelen, errmsg, err)) 911*c50c785cSJohn Marino return 0; 912*c50c785cSJohn Marino offset += namelen; 913*c50c785cSJohn Marino } 914*c50c785cSJohn Marino 915*c50c785cSJohn Marino /* Write out the segment header. */ 916*c50c785cSJohn Marino 917*c50c785cSJohn Marino memset (hdrbuf, 0, sizeof hdrbuf); 918*c50c785cSJohn Marino 919*c50c785cSJohn Marino hdr = &hdrbuf[0]; 920*c50c785cSJohn Marino if (attrs->magic == MACH_O_MH_MAGIC) 921*c50c785cSJohn Marino { 922*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd), 923*c50c785cSJohn Marino MACH_O_LC_SEGMENT); 924*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), 925*c50c785cSJohn Marino cmdsize); 926*c50c785cSJohn Marino strncpy (((char *) hdr 927*c50c785cSJohn Marino + offsetof (struct mach_o_segment_command_32, segname)), 928*c50c785cSJohn Marino sobj->segment_name, MACH_O_NAME_LEN); 929*c50c785cSJohn Marino /* vmaddr left as zero. */ 930*c50c785cSJohn Marino /* vmsize left as zero. */ 931*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), 932*c50c785cSJohn Marino hdrsize + cmdsize); 933*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize), 934*c50c785cSJohn Marino offset - (hdrsize + cmdsize)); 935*c50c785cSJohn Marino /* maxprot left as zero. */ 936*c50c785cSJohn Marino /* initprot left as zero. */ 937*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), 938*c50c785cSJohn Marino nsects); 939*c50c785cSJohn Marino /* flags left as zero. */ 940*c50c785cSJohn Marino } 941*c50c785cSJohn Marino else 942*c50c785cSJohn Marino { 943*c50c785cSJohn Marino #ifdef UNSIGNED_64BIT_TYPE 944*c50c785cSJohn Marino void (*set_64) (unsigned char *, ulong_type); 945*c50c785cSJohn Marino 946*c50c785cSJohn Marino set_64 = (attrs->is_big_endian 947*c50c785cSJohn Marino ? simple_object_set_big_64 948*c50c785cSJohn Marino : simple_object_set_little_64); 949*c50c785cSJohn Marino 950*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd), 951*c50c785cSJohn Marino MACH_O_LC_SEGMENT); 952*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), 953*c50c785cSJohn Marino cmdsize); 954*c50c785cSJohn Marino strncpy (((char *) hdr 955*c50c785cSJohn Marino + offsetof (struct mach_o_segment_command_64, segname)), 956*c50c785cSJohn Marino sobj->segment_name, MACH_O_NAME_LEN); 957*c50c785cSJohn Marino /* vmaddr left as zero. */ 958*c50c785cSJohn Marino /* vmsize left as zero. */ 959*c50c785cSJohn Marino set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), 960*c50c785cSJohn Marino hdrsize + cmdsize); 961*c50c785cSJohn Marino set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize), 962*c50c785cSJohn Marino offset - (hdrsize + cmdsize)); 963*c50c785cSJohn Marino /* maxprot left as zero. */ 964*c50c785cSJohn Marino /* initprot left as zero. */ 965*c50c785cSJohn Marino set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), 966*c50c785cSJohn Marino nsects); 967*c50c785cSJohn Marino /* flags left as zero. */ 968*c50c785cSJohn Marino #endif 969*c50c785cSJohn Marino } 970*c50c785cSJohn Marino 971*c50c785cSJohn Marino return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, 972*c50c785cSJohn Marino errmsg, err); 973*c50c785cSJohn Marino } 974*c50c785cSJohn Marino 975*c50c785cSJohn Marino /* Write out a complete Mach-O file. */ 976*c50c785cSJohn Marino 977*c50c785cSJohn Marino static const char * 978*c50c785cSJohn Marino simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, 979*c50c785cSJohn Marino int *err) 980*c50c785cSJohn Marino { 981*c50c785cSJohn Marino size_t nsects; 982*c50c785cSJohn Marino simple_object_write_section *section; 983*c50c785cSJohn Marino const char *errmsg; 984*c50c785cSJohn Marino 985*c50c785cSJohn Marino /* Start at 1 for symbol_names section. */ 986*c50c785cSJohn Marino nsects = 1; 987*c50c785cSJohn Marino for (section = sobj->sections; section != NULL; section = section->next) 988*c50c785cSJohn Marino ++nsects; 989*c50c785cSJohn Marino 990*c50c785cSJohn Marino if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, 991*c50c785cSJohn Marino &errmsg, err)) 992*c50c785cSJohn Marino return errmsg; 993*c50c785cSJohn Marino 994*c50c785cSJohn Marino if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects, 995*c50c785cSJohn Marino &errmsg, err)) 996*c50c785cSJohn Marino return errmsg; 997*c50c785cSJohn Marino 998*c50c785cSJohn Marino return NULL; 999*c50c785cSJohn Marino } 1000*c50c785cSJohn Marino 1001*c50c785cSJohn Marino /* Release the private data for an simple_object_write structure. */ 1002*c50c785cSJohn Marino 1003*c50c785cSJohn Marino static void 1004*c50c785cSJohn Marino simple_object_mach_o_release_write (void *data) 1005*c50c785cSJohn Marino { 1006*c50c785cSJohn Marino XDELETE (data); 1007*c50c785cSJohn Marino } 1008*c50c785cSJohn Marino 1009*c50c785cSJohn Marino /* The Mach-O functions. */ 1010*c50c785cSJohn Marino 1011*c50c785cSJohn Marino const struct simple_object_functions simple_object_mach_o_functions = 1012*c50c785cSJohn Marino { 1013*c50c785cSJohn Marino simple_object_mach_o_match, 1014*c50c785cSJohn Marino simple_object_mach_o_find_sections, 1015*c50c785cSJohn Marino simple_object_mach_o_fetch_attributes, 1016*c50c785cSJohn Marino simple_object_mach_o_release_read, 1017*c50c785cSJohn Marino simple_object_mach_o_attributes_merge, 1018*c50c785cSJohn Marino simple_object_mach_o_release_attributes, 1019*c50c785cSJohn Marino simple_object_mach_o_start_write, 1020*c50c785cSJohn Marino simple_object_mach_o_write_to_file, 1021*c50c785cSJohn Marino simple_object_mach_o_release_write 1022*c50c785cSJohn Marino }; 1023