xref: /dflybsd-src/contrib/gcc-4.7/libiberty/simple-object-mach-o.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1*e4b17023SJohn Marino /* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2*e4b17023SJohn Marino    Copyright 2010, 2011 Free Software Foundation, Inc.
3*e4b17023SJohn Marino    Written by Ian Lance Taylor, Google.
4*e4b17023SJohn Marino 
5*e4b17023SJohn Marino This program is free software; you can redistribute it and/or modify it
6*e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
7*e4b17023SJohn Marino Free Software Foundation; either version 2, or (at your option) any
8*e4b17023SJohn Marino later version.
9*e4b17023SJohn Marino 
10*e4b17023SJohn Marino This program is distributed in the hope that it will be useful,
11*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
12*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*e4b17023SJohn Marino GNU General Public License for more details.
14*e4b17023SJohn Marino 
15*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
16*e4b17023SJohn Marino along with this program; if not, write to the Free Software
17*e4b17023SJohn Marino Foundation, 51 Franklin Street - Fifth Floor,
18*e4b17023SJohn Marino Boston, MA 02110-1301, USA.  */
19*e4b17023SJohn Marino 
20*e4b17023SJohn Marino #include "config.h"
21*e4b17023SJohn Marino #include "libiberty.h"
22*e4b17023SJohn Marino #include "simple-object.h"
23*e4b17023SJohn Marino 
24*e4b17023SJohn Marino #include <stddef.h>
25*e4b17023SJohn Marino 
26*e4b17023SJohn Marino #ifdef HAVE_STDLIB_H
27*e4b17023SJohn Marino #include <stdlib.h>
28*e4b17023SJohn Marino #endif
29*e4b17023SJohn Marino 
30*e4b17023SJohn Marino #ifdef HAVE_STDINT_H
31*e4b17023SJohn Marino #include <stdint.h>
32*e4b17023SJohn Marino #endif
33*e4b17023SJohn Marino 
34*e4b17023SJohn Marino #ifdef HAVE_STRING_H
35*e4b17023SJohn Marino #include <string.h>
36*e4b17023SJohn Marino #endif
37*e4b17023SJohn Marino 
38*e4b17023SJohn Marino #ifdef HAVE_INTTYPES_H
39*e4b17023SJohn Marino #include <inttypes.h>
40*e4b17023SJohn Marino #endif
41*e4b17023SJohn Marino 
42*e4b17023SJohn Marino #include "simple-object-common.h"
43*e4b17023SJohn Marino 
44*e4b17023SJohn Marino /* Mach-O structures and constants.  */
45*e4b17023SJohn Marino 
46*e4b17023SJohn Marino /* Mach-O header (32-bit version).  */
47*e4b17023SJohn Marino 
48*e4b17023SJohn Marino struct mach_o_header_32
49*e4b17023SJohn Marino {
50*e4b17023SJohn Marino   unsigned char magic[4];	/* Magic number.  */
51*e4b17023SJohn Marino   unsigned char cputype[4];	/* CPU that this object is for.  */
52*e4b17023SJohn Marino   unsigned char cpusubtype[4];	/* CPU subtype.  */
53*e4b17023SJohn Marino   unsigned char filetype[4];	/* Type of file.  */
54*e4b17023SJohn Marino   unsigned char ncmds[4];	/* Number of load commands.  */
55*e4b17023SJohn Marino   unsigned char sizeofcmds[4];	/* Total size of load commands.  */
56*e4b17023SJohn Marino   unsigned char flags[4];	/* Flags for special featues.  */
57*e4b17023SJohn Marino };
58*e4b17023SJohn Marino 
59*e4b17023SJohn Marino /* Mach-O header (64-bit version).  */
60*e4b17023SJohn Marino 
61*e4b17023SJohn Marino struct mach_o_header_64
62*e4b17023SJohn Marino {
63*e4b17023SJohn Marino   unsigned char magic[4];	/* Magic number.  */
64*e4b17023SJohn Marino   unsigned char cputype[4];	/* CPU that this object is for.  */
65*e4b17023SJohn Marino   unsigned char cpusubtype[4];	/* CPU subtype.  */
66*e4b17023SJohn Marino   unsigned char filetype[4];	/* Type of file.  */
67*e4b17023SJohn Marino   unsigned char ncmds[4];	/* Number of load commands.  */
68*e4b17023SJohn Marino   unsigned char sizeofcmds[4];	/* Total size of load commands.  */
69*e4b17023SJohn Marino   unsigned char flags[4];	/* Flags for special featues.  */
70*e4b17023SJohn Marino   unsigned char reserved[4];	/* Reserved.  Duh.  */
71*e4b17023SJohn Marino };
72*e4b17023SJohn Marino 
73*e4b17023SJohn Marino /* For magic field in header.  */
74*e4b17023SJohn Marino 
75*e4b17023SJohn Marino #define MACH_O_MH_MAGIC			0xfeedface
76*e4b17023SJohn Marino #define MACH_O_MH_MAGIC_64		0xfeedfacf
77*e4b17023SJohn Marino 
78*e4b17023SJohn Marino /* For filetype field in header.  */
79*e4b17023SJohn Marino 
80*e4b17023SJohn Marino #define MACH_O_MH_OBJECT		0x01
81*e4b17023SJohn Marino 
82*e4b17023SJohn Marino /* A Mach-O file is a list of load commands.  This is the header of a
83*e4b17023SJohn Marino    load command.  */
84*e4b17023SJohn Marino 
85*e4b17023SJohn Marino struct mach_o_load_command
86*e4b17023SJohn Marino {
87*e4b17023SJohn Marino   unsigned char cmd[4];		/* The type of load command.  */
88*e4b17023SJohn Marino   unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
89*e4b17023SJohn Marino };
90*e4b17023SJohn Marino 
91*e4b17023SJohn Marino /* For cmd field in load command.   */
92*e4b17023SJohn Marino 
93*e4b17023SJohn Marino #define MACH_O_LC_SEGMENT		0x01
94*e4b17023SJohn Marino #define MACH_O_LC_SEGMENT_64		0x19
95*e4b17023SJohn Marino 
96*e4b17023SJohn Marino /* LC_SEGMENT load command.  */
97*e4b17023SJohn Marino 
98*e4b17023SJohn Marino struct mach_o_segment_command_32
99*e4b17023SJohn Marino {
100*e4b17023SJohn Marino   unsigned char cmd[4];		/* The type of load command (LC_SEGMENT).  */
101*e4b17023SJohn Marino   unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
102*e4b17023SJohn Marino   unsigned char segname[16];	/* Name of this segment.  */
103*e4b17023SJohn Marino   unsigned char vmaddr[4];	/* Virtual memory address of this segment.  */
104*e4b17023SJohn Marino   unsigned char vmsize[4];	/* Size there, in bytes.  */
105*e4b17023SJohn Marino   unsigned char fileoff[4];	/* Offset in bytes of the data to be mapped.  */
106*e4b17023SJohn Marino   unsigned char filesize[4];	/* Size in bytes on disk.  */
107*e4b17023SJohn Marino   unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
108*e4b17023SJohn Marino   unsigned char initprot[4];	/* Initial vmem protection.  */
109*e4b17023SJohn Marino   unsigned char nsects[4];	/* Number of sections in this segment.  */
110*e4b17023SJohn Marino   unsigned char flags[4];	/* Flags that affect the loading.  */
111*e4b17023SJohn Marino };
112*e4b17023SJohn Marino 
113*e4b17023SJohn Marino /* LC_SEGMENT_64 load command.  */
114*e4b17023SJohn Marino 
115*e4b17023SJohn Marino struct mach_o_segment_command_64
116*e4b17023SJohn Marino {
117*e4b17023SJohn Marino   unsigned char cmd[4];		/* The type of load command (LC_SEGMENT_64).  */
118*e4b17023SJohn Marino   unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
119*e4b17023SJohn Marino   unsigned char segname[16];	/* Name of this segment.  */
120*e4b17023SJohn Marino   unsigned char vmaddr[8];	/* Virtual memory address of this segment.  */
121*e4b17023SJohn Marino   unsigned char vmsize[8];	/* Size there, in bytes.  */
122*e4b17023SJohn Marino   unsigned char fileoff[8];	/* Offset in bytes of the data to be mapped.  */
123*e4b17023SJohn Marino   unsigned char filesize[8];	/* Size in bytes on disk.  */
124*e4b17023SJohn Marino   unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
125*e4b17023SJohn Marino   unsigned char initprot[4];	/* Initial vmem protection.  */
126*e4b17023SJohn Marino   unsigned char nsects[4];	/* Number of sections in this segment.  */
127*e4b17023SJohn Marino   unsigned char flags[4];	/* Flags that affect the loading.  */
128*e4b17023SJohn Marino };
129*e4b17023SJohn Marino 
130*e4b17023SJohn Marino /* 32-bit section header.  */
131*e4b17023SJohn Marino 
132*e4b17023SJohn Marino struct mach_o_section_32
133*e4b17023SJohn Marino {
134*e4b17023SJohn Marino   unsigned char sectname[16];	/* Section name.  */
135*e4b17023SJohn Marino   unsigned char segname[16];	/* Segment that the section belongs to.  */
136*e4b17023SJohn Marino   unsigned char addr[4];	/* Address of this section in memory.  */
137*e4b17023SJohn Marino   unsigned char size[4];	/* Size in bytes of this section.  */
138*e4b17023SJohn Marino   unsigned char offset[4];	/* File offset of this section.  */
139*e4b17023SJohn Marino   unsigned char align[4];	/* log2 of this section's alignment.  */
140*e4b17023SJohn Marino   unsigned char reloff[4];	/* File offset of this section's relocs.  */
141*e4b17023SJohn Marino   unsigned char nreloc[4];	/* Number of relocs for this section.  */
142*e4b17023SJohn Marino   unsigned char flags[4];	/* Section flags/attributes.  */
143*e4b17023SJohn Marino   unsigned char reserved1[4];
144*e4b17023SJohn Marino   unsigned char reserved2[4];
145*e4b17023SJohn Marino };
146*e4b17023SJohn Marino 
147*e4b17023SJohn Marino /* 64-bit section header.  */
148*e4b17023SJohn Marino 
149*e4b17023SJohn Marino struct mach_o_section_64
150*e4b17023SJohn Marino {
151*e4b17023SJohn Marino   unsigned char sectname[16];	/* Section name.  */
152*e4b17023SJohn Marino   unsigned char segname[16];	/* Segment that the section belongs to.  */
153*e4b17023SJohn Marino   unsigned char addr[8];	/* Address of this section in memory.  */
154*e4b17023SJohn Marino   unsigned char size[8];	/* Size in bytes of this section.  */
155*e4b17023SJohn Marino   unsigned char offset[4];	/* File offset of this section.  */
156*e4b17023SJohn Marino   unsigned char align[4];	/* log2 of this section's alignment.  */
157*e4b17023SJohn Marino   unsigned char reloff[4];	/* File offset of this section's relocs.  */
158*e4b17023SJohn Marino   unsigned char nreloc[4];	/* Number of relocs for this section.  */
159*e4b17023SJohn Marino   unsigned char flags[4];	/* Section flags/attributes.  */
160*e4b17023SJohn Marino   unsigned char reserved1[4];
161*e4b17023SJohn Marino   unsigned char reserved2[4];
162*e4b17023SJohn Marino   unsigned char reserved3[4];
163*e4b17023SJohn Marino };
164*e4b17023SJohn Marino 
165*e4b17023SJohn Marino /* Flags for Mach-O sections.  */
166*e4b17023SJohn Marino 
167*e4b17023SJohn Marino #define MACH_O_S_ATTR_DEBUG			0x02000000
168*e4b17023SJohn Marino 
169*e4b17023SJohn Marino /* The length of a segment or section name.  */
170*e4b17023SJohn Marino 
171*e4b17023SJohn Marino #define MACH_O_NAME_LEN (16)
172*e4b17023SJohn Marino 
173*e4b17023SJohn Marino /* A GNU specific extension for long section names.  */
174*e4b17023SJohn Marino 
175*e4b17023SJohn Marino #define GNU_SECTION_NAMES "__section_names"
176*e4b17023SJohn Marino 
177*e4b17023SJohn Marino /* A GNU-specific extension to wrap multiple sections using three
178*e4b17023SJohn Marino    mach-o sections within a given segment.  The section '__wrapper_sects'
179*e4b17023SJohn Marino    is subdivided according to the index '__wrapper_index' and each sub
180*e4b17023SJohn Marino    sect is named according to the names supplied in '__wrapper_names'.  */
181*e4b17023SJohn Marino 
182*e4b17023SJohn Marino #define GNU_WRAPPER_SECTS "__wrapper_sects"
183*e4b17023SJohn Marino #define GNU_WRAPPER_INDEX "__wrapper_index"
184*e4b17023SJohn Marino #define GNU_WRAPPER_NAMES "__wrapper_names"
185*e4b17023SJohn Marino 
186*e4b17023SJohn Marino /* Private data for an simple_object_read.  */
187*e4b17023SJohn Marino 
188*e4b17023SJohn Marino struct simple_object_mach_o_read
189*e4b17023SJohn Marino {
190*e4b17023SJohn Marino   /* User specified segment name.  */
191*e4b17023SJohn Marino   char *segment_name;
192*e4b17023SJohn Marino   /* Magic number.  */
193*e4b17023SJohn Marino   unsigned int magic;
194*e4b17023SJohn Marino   /* Whether this file is big-endian.  */
195*e4b17023SJohn Marino   int is_big_endian;
196*e4b17023SJohn Marino   /* CPU type from header.  */
197*e4b17023SJohn Marino   unsigned int cputype;
198*e4b17023SJohn Marino   /* CPU subtype from header.  */
199*e4b17023SJohn Marino   unsigned int cpusubtype;
200*e4b17023SJohn Marino   /* Number of commands, from header.  */
201*e4b17023SJohn Marino   unsigned int ncmds;
202*e4b17023SJohn Marino   /* Flags from header.  */
203*e4b17023SJohn Marino   unsigned int flags;
204*e4b17023SJohn Marino   /* Reserved field from header, only used on 64-bit.  */
205*e4b17023SJohn Marino   unsigned int reserved;
206*e4b17023SJohn Marino };
207*e4b17023SJohn Marino 
208*e4b17023SJohn Marino /* Private data for an simple_object_attributes.  */
209*e4b17023SJohn Marino 
210*e4b17023SJohn Marino struct simple_object_mach_o_attributes
211*e4b17023SJohn Marino {
212*e4b17023SJohn Marino   /* Magic number.  */
213*e4b17023SJohn Marino   unsigned int magic;
214*e4b17023SJohn Marino   /* Whether this file is big-endian.  */
215*e4b17023SJohn Marino   int is_big_endian;
216*e4b17023SJohn Marino   /* CPU type from header.  */
217*e4b17023SJohn Marino   unsigned int cputype;
218*e4b17023SJohn Marino   /* CPU subtype from header.  */
219*e4b17023SJohn Marino   unsigned int cpusubtype;
220*e4b17023SJohn Marino   /* Flags from header.  */
221*e4b17023SJohn Marino   unsigned int flags;
222*e4b17023SJohn Marino   /* Reserved field from header, only used on 64-bit.  */
223*e4b17023SJohn Marino   unsigned int reserved;
224*e4b17023SJohn Marino };
225*e4b17023SJohn Marino 
226*e4b17023SJohn Marino /* See if we have a Mach-O MH_OBJECT file:
227*e4b17023SJohn Marino 
228*e4b17023SJohn Marino    A standard MH_OBJECT (from as) will have three load commands:
229*e4b17023SJohn Marino    0 - LC_SEGMENT/LC_SEGMENT64
230*e4b17023SJohn Marino    1 - LC_SYMTAB
231*e4b17023SJohn Marino    2 - LC_DYSYMTAB
232*e4b17023SJohn Marino 
233*e4b17023SJohn Marino    The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment
234*e4b17023SJohn Marino    containing all the sections.
235*e4b17023SJohn Marino 
236*e4b17023SJohn Marino    Files written by simple-object will have only the segment command
237*e4b17023SJohn Marino    (no symbol tables).  */
238*e4b17023SJohn Marino 
239*e4b17023SJohn Marino 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)240*e4b17023SJohn Marino simple_object_mach_o_match (
241*e4b17023SJohn Marino     unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
242*e4b17023SJohn Marino     int descriptor,
243*e4b17023SJohn Marino     off_t offset,
244*e4b17023SJohn Marino     const char *segment_name,
245*e4b17023SJohn Marino     const char **errmsg,
246*e4b17023SJohn Marino     int *err)
247*e4b17023SJohn Marino {
248*e4b17023SJohn Marino   unsigned int magic;
249*e4b17023SJohn Marino   int is_big_endian;
250*e4b17023SJohn Marino   unsigned int (*fetch_32) (const unsigned char *);
251*e4b17023SJohn Marino   unsigned int filetype;
252*e4b17023SJohn Marino   struct simple_object_mach_o_read *omr;
253*e4b17023SJohn Marino   unsigned char buf[sizeof (struct mach_o_header_64)];
254*e4b17023SJohn Marino   unsigned char *b;
255*e4b17023SJohn Marino 
256*e4b17023SJohn Marino   magic = simple_object_fetch_big_32 (header);
257*e4b17023SJohn Marino   if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
258*e4b17023SJohn Marino     is_big_endian = 1;
259*e4b17023SJohn Marino   else
260*e4b17023SJohn Marino     {
261*e4b17023SJohn Marino       magic = simple_object_fetch_little_32 (header);
262*e4b17023SJohn Marino       if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
263*e4b17023SJohn Marino 	is_big_endian = 0;
264*e4b17023SJohn Marino       else
265*e4b17023SJohn Marino 	{
266*e4b17023SJohn Marino 	  *errmsg = NULL;
267*e4b17023SJohn Marino 	  *err = 0;
268*e4b17023SJohn Marino 	  return NULL;
269*e4b17023SJohn Marino 	}
270*e4b17023SJohn Marino     }
271*e4b17023SJohn Marino 
272*e4b17023SJohn Marino #ifndef UNSIGNED_64BIT_TYPE
273*e4b17023SJohn Marino   if (magic == MACH_O_MH_MAGIC_64)
274*e4b17023SJohn Marino     {
275*e4b17023SJohn Marino       *errmsg = "64-bit Mach-O objects not supported";
276*e4b17023SJohn Marino       *err = 0;
277*e4b17023SJohn Marino       return NULL;
278*e4b17023SJohn Marino     }
279*e4b17023SJohn Marino #endif
280*e4b17023SJohn Marino 
281*e4b17023SJohn Marino   /* We require the user to provide a segment name.  This is
282*e4b17023SJohn Marino      unfortunate but I don't see any good choices here.  */
283*e4b17023SJohn Marino 
284*e4b17023SJohn Marino   if (segment_name == NULL)
285*e4b17023SJohn Marino     {
286*e4b17023SJohn Marino       *errmsg = "Mach-O file found but no segment name specified";
287*e4b17023SJohn Marino       *err = 0;
288*e4b17023SJohn Marino       return NULL;
289*e4b17023SJohn Marino     }
290*e4b17023SJohn Marino 
291*e4b17023SJohn Marino   if (strlen (segment_name) > MACH_O_NAME_LEN)
292*e4b17023SJohn Marino     {
293*e4b17023SJohn Marino       *errmsg = "Mach-O segment name too long";
294*e4b17023SJohn Marino       *err = 0;
295*e4b17023SJohn Marino       return NULL;
296*e4b17023SJohn Marino     }
297*e4b17023SJohn Marino 
298*e4b17023SJohn Marino   /* The 32-bit and 64-bit headers are similar enough that we can use
299*e4b17023SJohn Marino      the same code.  */
300*e4b17023SJohn Marino 
301*e4b17023SJohn Marino   fetch_32 = (is_big_endian
302*e4b17023SJohn Marino 	      ? simple_object_fetch_big_32
303*e4b17023SJohn Marino 	      : simple_object_fetch_little_32);
304*e4b17023SJohn Marino 
305*e4b17023SJohn Marino   if (!simple_object_internal_read (descriptor, offset, buf,
306*e4b17023SJohn Marino 				    (magic == MACH_O_MH_MAGIC
307*e4b17023SJohn Marino 				     ? sizeof (struct mach_o_header_32)
308*e4b17023SJohn Marino 				     : sizeof (struct mach_o_header_64)),
309*e4b17023SJohn Marino 				    errmsg, err))
310*e4b17023SJohn Marino     return NULL;
311*e4b17023SJohn Marino 
312*e4b17023SJohn Marino   b = &buf[0];
313*e4b17023SJohn Marino 
314*e4b17023SJohn Marino   filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
315*e4b17023SJohn Marino   if (filetype != MACH_O_MH_OBJECT)
316*e4b17023SJohn Marino     {
317*e4b17023SJohn Marino       *errmsg = "Mach-O file is not object file";
318*e4b17023SJohn Marino       *err = 0;
319*e4b17023SJohn Marino       return NULL;
320*e4b17023SJohn Marino     }
321*e4b17023SJohn Marino 
322*e4b17023SJohn Marino   omr = XNEW (struct simple_object_mach_o_read);
323*e4b17023SJohn Marino   omr->segment_name = xstrdup (segment_name);
324*e4b17023SJohn Marino   omr->magic = magic;
325*e4b17023SJohn Marino   omr->is_big_endian = is_big_endian;
326*e4b17023SJohn Marino   omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
327*e4b17023SJohn Marino   omr->cpusubtype = (*fetch_32) (b
328*e4b17023SJohn Marino 				 + offsetof (struct mach_o_header_32,
329*e4b17023SJohn Marino 					     cpusubtype));
330*e4b17023SJohn Marino   omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
331*e4b17023SJohn Marino   omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
332*e4b17023SJohn Marino   if (magic == MACH_O_MH_MAGIC)
333*e4b17023SJohn Marino     omr->reserved = 0;
334*e4b17023SJohn Marino   else
335*e4b17023SJohn Marino     omr->reserved = (*fetch_32) (b
336*e4b17023SJohn Marino 				 + offsetof (struct mach_o_header_64,
337*e4b17023SJohn Marino 					     reserved));
338*e4b17023SJohn Marino 
339*e4b17023SJohn Marino   return (void *) omr;
340*e4b17023SJohn Marino }
341*e4b17023SJohn Marino 
342*e4b17023SJohn Marino /* Get the file offset and size from a section header.  */
343*e4b17023SJohn Marino 
344*e4b17023SJohn Marino 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)345*e4b17023SJohn Marino simple_object_mach_o_section_info (int is_big_endian, int is_32,
346*e4b17023SJohn Marino 				   const unsigned char *sechdr, off_t *offset,
347*e4b17023SJohn Marino 				   size_t *size)
348*e4b17023SJohn Marino {
349*e4b17023SJohn Marino   unsigned int (*fetch_32) (const unsigned char *);
350*e4b17023SJohn Marino   ulong_type (*fetch_64) (const unsigned char *);
351*e4b17023SJohn Marino 
352*e4b17023SJohn Marino   fetch_32 = (is_big_endian
353*e4b17023SJohn Marino 	      ? simple_object_fetch_big_32
354*e4b17023SJohn Marino 	      : simple_object_fetch_little_32);
355*e4b17023SJohn Marino 
356*e4b17023SJohn Marino   fetch_64 = NULL;
357*e4b17023SJohn Marino #ifdef UNSIGNED_64BIT_TYPE
358*e4b17023SJohn Marino   fetch_64 = (is_big_endian
359*e4b17023SJohn Marino 	      ? simple_object_fetch_big_64
360*e4b17023SJohn Marino 	      : simple_object_fetch_little_64);
361*e4b17023SJohn Marino #endif
362*e4b17023SJohn Marino 
363*e4b17023SJohn Marino   if (is_32)
364*e4b17023SJohn Marino     {
365*e4b17023SJohn Marino       *offset = fetch_32 (sechdr
366*e4b17023SJohn Marino 			  + offsetof (struct mach_o_section_32, offset));
367*e4b17023SJohn Marino       *size = fetch_32 (sechdr
368*e4b17023SJohn Marino 			+ offsetof (struct mach_o_section_32, size));
369*e4b17023SJohn Marino     }
370*e4b17023SJohn Marino   else
371*e4b17023SJohn Marino     {
372*e4b17023SJohn Marino       *offset = fetch_32 (sechdr
373*e4b17023SJohn Marino 			  + offsetof (struct mach_o_section_64, offset));
374*e4b17023SJohn Marino       *size = fetch_64 (sechdr
375*e4b17023SJohn Marino 			+ offsetof (struct mach_o_section_64, size));
376*e4b17023SJohn Marino     }
377*e4b17023SJohn Marino }
378*e4b17023SJohn Marino 
379*e4b17023SJohn Marino /* Handle a segment in a Mach-O Object file.
380*e4b17023SJohn Marino 
381*e4b17023SJohn Marino    This will callback to the function pfn for each "section found" the meaning
382*e4b17023SJohn Marino    of which depends on gnu extensions to mach-o:
383*e4b17023SJohn Marino 
384*e4b17023SJohn Marino    If we find mach-o sections (with the segment name as specified) which also
385*e4b17023SJohn Marino    contain: a 'sects' wrapper, an index, and a  name table, we expand this into
386*e4b17023SJohn Marino    as many sections as are specified in the index.  In this case, there will
387*e4b17023SJohn Marino    be a callback for each of these.
388*e4b17023SJohn Marino 
389*e4b17023SJohn Marino    We will also allow an extension that permits long names (more than 16
390*e4b17023SJohn Marino    characters) to be used with mach-o.  In this case, the section name has
391*e4b17023SJohn Marino    a specific format embedding an index into a name table, and the file must
392*e4b17023SJohn Marino    contain such name table.
393*e4b17023SJohn Marino 
394*e4b17023SJohn Marino    Return 1 if we should continue, 0 if the caller should return.  */
395*e4b17023SJohn Marino 
396*e4b17023SJohn Marino #define SOMO_SECTS_PRESENT 0x01
397*e4b17023SJohn Marino #define SOMO_INDEX_PRESENT 0x02
398*e4b17023SJohn Marino #define SOMO_NAMES_PRESENT 0x04
399*e4b17023SJohn Marino #define SOMO_LONGN_PRESENT 0x08
400*e4b17023SJohn Marino #define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \
401*e4b17023SJohn Marino 		       | SOMO_NAMES_PRESENT)
402*e4b17023SJohn Marino 
403*e4b17023SJohn Marino 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)404*e4b17023SJohn Marino simple_object_mach_o_segment (simple_object_read *sobj, off_t offset,
405*e4b17023SJohn Marino 			      const unsigned char *segbuf,
406*e4b17023SJohn Marino 			      int (*pfn) (void *, const char *, off_t offset,
407*e4b17023SJohn Marino 					  off_t length),
408*e4b17023SJohn Marino 			      void *data,
409*e4b17023SJohn Marino 			      const char **errmsg, int *err)
410*e4b17023SJohn Marino {
411*e4b17023SJohn Marino   struct simple_object_mach_o_read *omr =
412*e4b17023SJohn Marino     (struct simple_object_mach_o_read *) sobj->data;
413*e4b17023SJohn Marino   unsigned int (*fetch_32) (const unsigned char *);
414*e4b17023SJohn Marino   int is_32;
415*e4b17023SJohn Marino   size_t seghdrsize;
416*e4b17023SJohn Marino   size_t sechdrsize;
417*e4b17023SJohn Marino   size_t segname_offset;
418*e4b17023SJohn Marino   size_t sectname_offset;
419*e4b17023SJohn Marino   unsigned int nsects;
420*e4b17023SJohn Marino   unsigned char *secdata;
421*e4b17023SJohn Marino   unsigned int i;
422*e4b17023SJohn Marino   unsigned int gnu_sections_found;
423*e4b17023SJohn Marino   unsigned int strtab_index;
424*e4b17023SJohn Marino   unsigned int index_index;
425*e4b17023SJohn Marino   unsigned int nametab_index;
426*e4b17023SJohn Marino   unsigned int sections_index;
427*e4b17023SJohn Marino   char *strtab;
428*e4b17023SJohn Marino   char *nametab;
429*e4b17023SJohn Marino   unsigned char *index;
430*e4b17023SJohn Marino   size_t strtab_size;
431*e4b17023SJohn Marino   size_t nametab_size;
432*e4b17023SJohn Marino   size_t index_size;
433*e4b17023SJohn Marino   unsigned int n_wrapped_sects;
434*e4b17023SJohn Marino   size_t wrapper_sect_size;
435*e4b17023SJohn Marino   off_t wrapper_sect_offset;
436*e4b17023SJohn Marino 
437*e4b17023SJohn Marino   fetch_32 = (omr->is_big_endian
438*e4b17023SJohn Marino 	      ? simple_object_fetch_big_32
439*e4b17023SJohn Marino 	      : simple_object_fetch_little_32);
440*e4b17023SJohn Marino 
441*e4b17023SJohn Marino   is_32 = omr->magic == MACH_O_MH_MAGIC;
442*e4b17023SJohn Marino 
443*e4b17023SJohn Marino   if (is_32)
444*e4b17023SJohn Marino     {
445*e4b17023SJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_32);
446*e4b17023SJohn Marino       sechdrsize = sizeof (struct mach_o_section_32);
447*e4b17023SJohn Marino       segname_offset = offsetof (struct mach_o_section_32, segname);
448*e4b17023SJohn Marino       sectname_offset = offsetof (struct mach_o_section_32, sectname);
449*e4b17023SJohn Marino       nsects = (*fetch_32) (segbuf
450*e4b17023SJohn Marino 			    + offsetof (struct mach_o_segment_command_32,
451*e4b17023SJohn Marino 					nsects));
452*e4b17023SJohn Marino     }
453*e4b17023SJohn Marino   else
454*e4b17023SJohn Marino     {
455*e4b17023SJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_64);
456*e4b17023SJohn Marino       sechdrsize = sizeof (struct mach_o_section_64);
457*e4b17023SJohn Marino       segname_offset = offsetof (struct mach_o_section_64, segname);
458*e4b17023SJohn Marino       sectname_offset = offsetof (struct mach_o_section_64, sectname);
459*e4b17023SJohn Marino       nsects = (*fetch_32) (segbuf
460*e4b17023SJohn Marino 			    + offsetof (struct mach_o_segment_command_64,
461*e4b17023SJohn Marino 					nsects));
462*e4b17023SJohn Marino     }
463*e4b17023SJohn Marino 
464*e4b17023SJohn Marino   /* Fetch the section headers from the segment command.  */
465*e4b17023SJohn Marino 
466*e4b17023SJohn Marino   secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
467*e4b17023SJohn Marino   if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
468*e4b17023SJohn Marino 				    secdata, nsects * sechdrsize, errmsg, err))
469*e4b17023SJohn Marino     {
470*e4b17023SJohn Marino       XDELETEVEC (secdata);
471*e4b17023SJohn Marino       return 0;
472*e4b17023SJohn Marino     }
473*e4b17023SJohn Marino 
474*e4b17023SJohn Marino   /* Scan for special sections that signal GNU extensions to the format.  */
475*e4b17023SJohn Marino 
476*e4b17023SJohn Marino   gnu_sections_found = 0;
477*e4b17023SJohn Marino   index_index = nsects;
478*e4b17023SJohn Marino   sections_index = nsects;
479*e4b17023SJohn Marino   strtab_index = nsects;
480*e4b17023SJohn Marino   nametab_index = nsects;
481*e4b17023SJohn Marino   for (i = 0; i < nsects; ++i)
482*e4b17023SJohn Marino     {
483*e4b17023SJohn Marino       size_t nameoff;
484*e4b17023SJohn Marino 
485*e4b17023SJohn Marino       nameoff = i * sechdrsize + segname_offset;
486*e4b17023SJohn Marino       if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
487*e4b17023SJohn Marino 	continue;
488*e4b17023SJohn Marino 
489*e4b17023SJohn Marino       nameoff = i * sechdrsize + sectname_offset;
490*e4b17023SJohn Marino       if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0)
491*e4b17023SJohn Marino 	{
492*e4b17023SJohn Marino 	  nametab_index = i;
493*e4b17023SJohn Marino 	  gnu_sections_found |= SOMO_NAMES_PRESENT;
494*e4b17023SJohn Marino 	}
495*e4b17023SJohn Marino       else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0)
496*e4b17023SJohn Marino 	{
497*e4b17023SJohn Marino 	  index_index = i;
498*e4b17023SJohn Marino 	  gnu_sections_found |= SOMO_INDEX_PRESENT;
499*e4b17023SJohn Marino 	}
500*e4b17023SJohn Marino       else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0)
501*e4b17023SJohn Marino 	{
502*e4b17023SJohn Marino 	  sections_index = i;
503*e4b17023SJohn Marino 	  gnu_sections_found |= SOMO_SECTS_PRESENT;
504*e4b17023SJohn Marino 	}
505*e4b17023SJohn Marino       else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
506*e4b17023SJohn Marino 	{
507*e4b17023SJohn Marino 	  strtab_index = i;
508*e4b17023SJohn Marino 	  gnu_sections_found |= SOMO_LONGN_PRESENT;
509*e4b17023SJohn Marino 	}
510*e4b17023SJohn Marino     }
511*e4b17023SJohn Marino 
512*e4b17023SJohn Marino   /* If any of the special wrapper section components is present, then
513*e4b17023SJohn Marino      they all should be.  */
514*e4b17023SJohn Marino 
515*e4b17023SJohn Marino   if ((gnu_sections_found & SOMO_WRAPPING) != 0)
516*e4b17023SJohn Marino     {
517*e4b17023SJohn Marino       off_t nametab_offset;
518*e4b17023SJohn Marino       off_t index_offset;
519*e4b17023SJohn Marino 
520*e4b17023SJohn Marino       if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING)
521*e4b17023SJohn Marino 	{
522*e4b17023SJohn Marino 	  *errmsg = "GNU Mach-o section wrapper: required section missing";
523*e4b17023SJohn Marino 	  *err = 0; /* No useful errno.  */
524*e4b17023SJohn Marino 	  XDELETEVEC (secdata);
525*e4b17023SJohn Marino 	  return 0;
526*e4b17023SJohn Marino 	}
527*e4b17023SJohn Marino 
528*e4b17023SJohn Marino       /* Fetch the name table.  */
529*e4b17023SJohn Marino 
530*e4b17023SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
531*e4b17023SJohn Marino 					 secdata + nametab_index * sechdrsize,
532*e4b17023SJohn Marino 					 &nametab_offset, &nametab_size);
533*e4b17023SJohn Marino       nametab = XNEWVEC (char, nametab_size);
534*e4b17023SJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
535*e4b17023SJohn Marino 					sobj->offset + nametab_offset,
536*e4b17023SJohn Marino 					(unsigned char *) nametab, nametab_size,
537*e4b17023SJohn Marino 					errmsg, err))
538*e4b17023SJohn Marino 	{
539*e4b17023SJohn Marino 	  XDELETEVEC (nametab);
540*e4b17023SJohn Marino 	  XDELETEVEC (secdata);
541*e4b17023SJohn Marino 	  return 0;
542*e4b17023SJohn Marino 	}
543*e4b17023SJohn Marino 
544*e4b17023SJohn Marino       /* Fetch the index.  */
545*e4b17023SJohn Marino 
546*e4b17023SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
547*e4b17023SJohn Marino 					 secdata + index_index * sechdrsize,
548*e4b17023SJohn Marino 					 &index_offset, &index_size);
549*e4b17023SJohn Marino       index = XNEWVEC (unsigned char, index_size);
550*e4b17023SJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
551*e4b17023SJohn Marino 					sobj->offset + index_offset,
552*e4b17023SJohn Marino 					index, index_size,
553*e4b17023SJohn Marino 					errmsg, err))
554*e4b17023SJohn Marino 	{
555*e4b17023SJohn Marino 	  XDELETEVEC (index);
556*e4b17023SJohn Marino 	  XDELETEVEC (nametab);
557*e4b17023SJohn Marino 	  XDELETEVEC (secdata);
558*e4b17023SJohn Marino 	  return 0;
559*e4b17023SJohn Marino 	}
560*e4b17023SJohn Marino 
561*e4b17023SJohn Marino       /* The index contains 4 unsigned ints per sub-section:
562*e4b17023SJohn Marino 	 sub-section offset/length, sub-section name/length.
563*e4b17023SJohn Marino 	 We fix this for both 32 and 64 bit mach-o for now, since
564*e4b17023SJohn Marino 	 other fields limit the maximum size of an object to 4G.  */
565*e4b17023SJohn Marino       n_wrapped_sects = index_size / 16;
566*e4b17023SJohn Marino 
567*e4b17023SJohn Marino       /* Get the parameters for the wrapper too.  */
568*e4b17023SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
569*e4b17023SJohn Marino 					 secdata + sections_index * sechdrsize,
570*e4b17023SJohn Marino 					 &wrapper_sect_offset,
571*e4b17023SJohn Marino 					 &wrapper_sect_size);
572*e4b17023SJohn Marino     }
573*e4b17023SJohn Marino   else
574*e4b17023SJohn Marino     {
575*e4b17023SJohn Marino       index = NULL;
576*e4b17023SJohn Marino       index_size = 0;
577*e4b17023SJohn Marino       nametab = NULL;
578*e4b17023SJohn Marino       nametab_size = 0;
579*e4b17023SJohn Marino       n_wrapped_sects = 0;
580*e4b17023SJohn Marino     }
581*e4b17023SJohn Marino 
582*e4b17023SJohn Marino   /* If we have a long names section, fetch it.  */
583*e4b17023SJohn Marino 
584*e4b17023SJohn Marino   if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
585*e4b17023SJohn Marino     {
586*e4b17023SJohn Marino       off_t strtab_offset;
587*e4b17023SJohn Marino 
588*e4b17023SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
589*e4b17023SJohn Marino 					 secdata + strtab_index * sechdrsize,
590*e4b17023SJohn Marino 					 &strtab_offset, &strtab_size);
591*e4b17023SJohn Marino       strtab = XNEWVEC (char, strtab_size);
592*e4b17023SJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
593*e4b17023SJohn Marino 					sobj->offset + strtab_offset,
594*e4b17023SJohn Marino 					(unsigned char *) strtab, strtab_size,
595*e4b17023SJohn Marino 					errmsg, err))
596*e4b17023SJohn Marino 	{
597*e4b17023SJohn Marino 	  XDELETEVEC (strtab);
598*e4b17023SJohn Marino 	  XDELETEVEC (index);
599*e4b17023SJohn Marino 	  XDELETEVEC (nametab);
600*e4b17023SJohn Marino 	  XDELETEVEC (secdata);
601*e4b17023SJohn Marino 	  return 0;
602*e4b17023SJohn Marino 	}
603*e4b17023SJohn Marino     }
604*e4b17023SJohn Marino   else
605*e4b17023SJohn Marino     {
606*e4b17023SJohn Marino       strtab = NULL;
607*e4b17023SJohn Marino       strtab_size = 0;
608*e4b17023SJohn Marino       strtab_index = nsects;
609*e4b17023SJohn Marino     }
610*e4b17023SJohn Marino 
611*e4b17023SJohn Marino   /* Process the sections.  */
612*e4b17023SJohn Marino 
613*e4b17023SJohn Marino   for (i = 0; i < nsects; ++i)
614*e4b17023SJohn Marino     {
615*e4b17023SJohn Marino       const unsigned char *sechdr;
616*e4b17023SJohn Marino       char namebuf[MACH_O_NAME_LEN * 2 + 2];
617*e4b17023SJohn Marino       char *name;
618*e4b17023SJohn Marino       off_t secoffset;
619*e4b17023SJohn Marino       size_t secsize;
620*e4b17023SJohn Marino       int l;
621*e4b17023SJohn Marino 
622*e4b17023SJohn Marino       sechdr = secdata + i * sechdrsize;
623*e4b17023SJohn Marino 
624*e4b17023SJohn Marino       /* We've already processed the long section names.  */
625*e4b17023SJohn Marino 
626*e4b17023SJohn Marino       if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0
627*e4b17023SJohn Marino 	  && i == strtab_index)
628*e4b17023SJohn Marino 	continue;
629*e4b17023SJohn Marino 
630*e4b17023SJohn Marino       /* We only act on the segment named.  */
631*e4b17023SJohn Marino 
632*e4b17023SJohn Marino       if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
633*e4b17023SJohn Marino 	continue;
634*e4b17023SJohn Marino 
635*e4b17023SJohn Marino       /* Process sections associated with the wrapper.  */
636*e4b17023SJohn Marino 
637*e4b17023SJohn Marino       if ((gnu_sections_found & SOMO_WRAPPING) != 0)
638*e4b17023SJohn Marino 	{
639*e4b17023SJohn Marino 	  if (i == nametab_index || i == index_index)
640*e4b17023SJohn Marino 	    continue;
641*e4b17023SJohn Marino 
642*e4b17023SJohn Marino 	  if (i == sections_index)
643*e4b17023SJohn Marino 	    {
644*e4b17023SJohn Marino 	      unsigned int j;
645*e4b17023SJohn Marino 	      for (j = 0; j < n_wrapped_sects; ++j)
646*e4b17023SJohn Marino 		{
647*e4b17023SJohn Marino 		  unsigned int subsect_offset, subsect_length, name_offset;
648*e4b17023SJohn Marino 		  subsect_offset = (*fetch_32) (index + 16 * j);
649*e4b17023SJohn Marino 		  subsect_length = (*fetch_32) (index + 16 * j + 4);
650*e4b17023SJohn Marino 		  name_offset = (*fetch_32) (index + 16 * j + 8);
651*e4b17023SJohn Marino 		  /* We don't need the name_length yet.  */
652*e4b17023SJohn Marino 
653*e4b17023SJohn Marino 		  secoffset = wrapper_sect_offset + subsect_offset;
654*e4b17023SJohn Marino 		  secsize = subsect_length;
655*e4b17023SJohn Marino 		  name = nametab + name_offset;
656*e4b17023SJohn Marino 
657*e4b17023SJohn Marino 		  if (!(*pfn) (data, name, secoffset, secsize))
658*e4b17023SJohn Marino 		    {
659*e4b17023SJohn Marino 		      *errmsg = NULL;
660*e4b17023SJohn Marino 		      *err = 0;
661*e4b17023SJohn Marino 		      XDELETEVEC (index);
662*e4b17023SJohn Marino 		      XDELETEVEC (nametab);
663*e4b17023SJohn Marino 		      XDELETEVEC (strtab);
664*e4b17023SJohn Marino 		      XDELETEVEC (secdata);
665*e4b17023SJohn Marino 		      return 0;
666*e4b17023SJohn Marino 		    }
667*e4b17023SJohn Marino 		}
668*e4b17023SJohn Marino 	      continue;
669*e4b17023SJohn Marino 	    }
670*e4b17023SJohn Marino 	}
671*e4b17023SJohn Marino 
672*e4b17023SJohn Marino       if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
673*e4b17023SJohn Marino 	{
674*e4b17023SJohn Marino 	  memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
675*e4b17023SJohn Marino 	  namebuf[MACH_O_NAME_LEN] = '\0';
676*e4b17023SJohn Marino 
677*e4b17023SJohn Marino 	  name = &namebuf[0];
678*e4b17023SJohn Marino 	  if (strtab != NULL && name[0] == '_' && name[1] == '_')
679*e4b17023SJohn Marino 	    {
680*e4b17023SJohn Marino 	      unsigned long stringoffset;
681*e4b17023SJohn Marino 
682*e4b17023SJohn Marino 	      if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
683*e4b17023SJohn Marino 		{
684*e4b17023SJohn Marino 		  if (stringoffset >= strtab_size)
685*e4b17023SJohn Marino 		    {
686*e4b17023SJohn Marino 		      *errmsg = "section name offset out of range";
687*e4b17023SJohn Marino 		      *err = 0;
688*e4b17023SJohn Marino 		      XDELETEVEC (index);
689*e4b17023SJohn Marino 		      XDELETEVEC (nametab);
690*e4b17023SJohn Marino 		      XDELETEVEC (strtab);
691*e4b17023SJohn Marino 		      XDELETEVEC (secdata);
692*e4b17023SJohn Marino 		      return 0;
693*e4b17023SJohn Marino 		    }
694*e4b17023SJohn Marino 
695*e4b17023SJohn Marino 		  name = strtab + stringoffset;
696*e4b17023SJohn Marino 		}
697*e4b17023SJohn Marino 	  }
698*e4b17023SJohn Marino 	}
699*e4b17023SJohn Marino       else
700*e4b17023SJohn Marino 	{
701*e4b17023SJohn Marino 	   /* Otherwise, make a name like __segment,__section as per the
702*e4b17023SJohn Marino 	      convention in mach-o asm.  */
703*e4b17023SJohn Marino 	  name = &namebuf[0];
704*e4b17023SJohn Marino 	  memset (namebuf, 0, MACH_O_NAME_LEN * 2 + 2);
705*e4b17023SJohn Marino 	  memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
706*e4b17023SJohn Marino 	  l = strlen (namebuf);
707*e4b17023SJohn Marino 	  namebuf[l] = ',';
708*e4b17023SJohn Marino 	  memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
709*e4b17023SJohn Marino 		  MACH_O_NAME_LEN);
710*e4b17023SJohn Marino 	}
711*e4b17023SJohn Marino 
712*e4b17023SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
713*e4b17023SJohn Marino 					 &secoffset, &secsize);
714*e4b17023SJohn Marino 
715*e4b17023SJohn Marino       if (!(*pfn) (data, name, secoffset, secsize))
716*e4b17023SJohn Marino 	{
717*e4b17023SJohn Marino 	  *errmsg = NULL;
718*e4b17023SJohn Marino 	  *err = 0;
719*e4b17023SJohn Marino 	  XDELETEVEC (index);
720*e4b17023SJohn Marino 	  XDELETEVEC (nametab);
721*e4b17023SJohn Marino 	  XDELETEVEC (strtab);
722*e4b17023SJohn Marino 	  XDELETEVEC (secdata);
723*e4b17023SJohn Marino 	  return 0;
724*e4b17023SJohn Marino 	}
725*e4b17023SJohn Marino     }
726*e4b17023SJohn Marino 
727*e4b17023SJohn Marino   XDELETEVEC (index);
728*e4b17023SJohn Marino   XDELETEVEC (nametab);
729*e4b17023SJohn Marino   XDELETEVEC (strtab);
730*e4b17023SJohn Marino   XDELETEVEC (secdata);
731*e4b17023SJohn Marino 
732*e4b17023SJohn Marino   return 1;
733*e4b17023SJohn Marino }
734*e4b17023SJohn Marino 
735*e4b17023SJohn Marino /* Find all sections in a Mach-O file.  */
736*e4b17023SJohn Marino 
737*e4b17023SJohn Marino 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)738*e4b17023SJohn Marino simple_object_mach_o_find_sections (simple_object_read *sobj,
739*e4b17023SJohn Marino 				    int (*pfn) (void *, const char *,
740*e4b17023SJohn Marino 						off_t offset, off_t length),
741*e4b17023SJohn Marino 				    void *data,
742*e4b17023SJohn Marino 				    int *err)
743*e4b17023SJohn Marino {
744*e4b17023SJohn Marino   struct simple_object_mach_o_read *omr =
745*e4b17023SJohn Marino     (struct simple_object_mach_o_read *) sobj->data;
746*e4b17023SJohn Marino   off_t offset;
747*e4b17023SJohn Marino   size_t seghdrsize;
748*e4b17023SJohn Marino   unsigned int (*fetch_32) (const unsigned char *);
749*e4b17023SJohn Marino   const char *errmsg;
750*e4b17023SJohn Marino   unsigned int i;
751*e4b17023SJohn Marino 
752*e4b17023SJohn Marino   if (omr->magic == MACH_O_MH_MAGIC)
753*e4b17023SJohn Marino     {
754*e4b17023SJohn Marino       offset = sizeof (struct mach_o_header_32);
755*e4b17023SJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_32);
756*e4b17023SJohn Marino     }
757*e4b17023SJohn Marino   else
758*e4b17023SJohn Marino     {
759*e4b17023SJohn Marino       offset = sizeof (struct mach_o_header_64);
760*e4b17023SJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_64);
761*e4b17023SJohn Marino     }
762*e4b17023SJohn Marino 
763*e4b17023SJohn Marino   fetch_32 = (omr->is_big_endian
764*e4b17023SJohn Marino 	      ? simple_object_fetch_big_32
765*e4b17023SJohn Marino 	      : simple_object_fetch_little_32);
766*e4b17023SJohn Marino 
767*e4b17023SJohn Marino   for (i = 0; i < omr->ncmds; ++i)
768*e4b17023SJohn Marino     {
769*e4b17023SJohn Marino       unsigned char loadbuf[sizeof (struct mach_o_load_command)];
770*e4b17023SJohn Marino       unsigned int cmd;
771*e4b17023SJohn Marino       unsigned int cmdsize;
772*e4b17023SJohn Marino 
773*e4b17023SJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
774*e4b17023SJohn Marino 					sobj->offset + offset,
775*e4b17023SJohn Marino 					loadbuf,
776*e4b17023SJohn Marino 					sizeof (struct mach_o_load_command),
777*e4b17023SJohn Marino 					&errmsg, err))
778*e4b17023SJohn Marino 	return errmsg;
779*e4b17023SJohn Marino 
780*e4b17023SJohn Marino       cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
781*e4b17023SJohn Marino       cmdsize = (*fetch_32) (loadbuf
782*e4b17023SJohn Marino 			     + offsetof (struct mach_o_load_command, cmdsize));
783*e4b17023SJohn Marino 
784*e4b17023SJohn Marino       if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
785*e4b17023SJohn Marino 	{
786*e4b17023SJohn Marino 	  unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
787*e4b17023SJohn Marino 	  int r;
788*e4b17023SJohn Marino 
789*e4b17023SJohn Marino 	  if (!simple_object_internal_read (sobj->descriptor,
790*e4b17023SJohn Marino 					    sobj->offset + offset,
791*e4b17023SJohn Marino 					    segbuf, seghdrsize, &errmsg, err))
792*e4b17023SJohn Marino 	    return errmsg;
793*e4b17023SJohn Marino 
794*e4b17023SJohn Marino 	  r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
795*e4b17023SJohn Marino 					    data, &errmsg, err);
796*e4b17023SJohn Marino 	  if (!r)
797*e4b17023SJohn Marino 	    return errmsg;
798*e4b17023SJohn Marino 	}
799*e4b17023SJohn Marino 
800*e4b17023SJohn Marino       offset += cmdsize;
801*e4b17023SJohn Marino     }
802*e4b17023SJohn Marino 
803*e4b17023SJohn Marino   return NULL;
804*e4b17023SJohn Marino }
805*e4b17023SJohn Marino 
806*e4b17023SJohn Marino /* Fetch the attributes for an simple_object_read.  */
807*e4b17023SJohn Marino 
808*e4b17023SJohn Marino static void *
simple_object_mach_o_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)809*e4b17023SJohn Marino simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
810*e4b17023SJohn Marino 				       const char **errmsg ATTRIBUTE_UNUSED,
811*e4b17023SJohn Marino 				       int *err ATTRIBUTE_UNUSED)
812*e4b17023SJohn Marino {
813*e4b17023SJohn Marino   struct simple_object_mach_o_read *omr =
814*e4b17023SJohn Marino     (struct simple_object_mach_o_read *) sobj->data;
815*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *ret;
816*e4b17023SJohn Marino 
817*e4b17023SJohn Marino   ret = XNEW (struct simple_object_mach_o_attributes);
818*e4b17023SJohn Marino   ret->magic = omr->magic;
819*e4b17023SJohn Marino   ret->is_big_endian = omr->is_big_endian;
820*e4b17023SJohn Marino   ret->cputype = omr->cputype;
821*e4b17023SJohn Marino   ret->cpusubtype = omr->cpusubtype;
822*e4b17023SJohn Marino   ret->flags = omr->flags;
823*e4b17023SJohn Marino   ret->reserved = omr->reserved;
824*e4b17023SJohn Marino   return ret;
825*e4b17023SJohn Marino }
826*e4b17023SJohn Marino 
827*e4b17023SJohn Marino /* Release the private data for an simple_object_read.  */
828*e4b17023SJohn Marino 
829*e4b17023SJohn Marino static void
simple_object_mach_o_release_read(void * data)830*e4b17023SJohn Marino simple_object_mach_o_release_read (void *data)
831*e4b17023SJohn Marino {
832*e4b17023SJohn Marino   struct simple_object_mach_o_read *omr =
833*e4b17023SJohn Marino     (struct simple_object_mach_o_read *) data;
834*e4b17023SJohn Marino 
835*e4b17023SJohn Marino   free (omr->segment_name);
836*e4b17023SJohn Marino   XDELETE (omr);
837*e4b17023SJohn Marino }
838*e4b17023SJohn Marino 
839*e4b17023SJohn Marino /* Compare two attributes structures.  */
840*e4b17023SJohn Marino 
841*e4b17023SJohn Marino static const char *
simple_object_mach_o_attributes_merge(void * todata,void * fromdata,int * err)842*e4b17023SJohn Marino simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
843*e4b17023SJohn Marino {
844*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *to =
845*e4b17023SJohn Marino     (struct simple_object_mach_o_attributes *) todata;
846*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *from =
847*e4b17023SJohn Marino     (struct simple_object_mach_o_attributes *) fromdata;
848*e4b17023SJohn Marino 
849*e4b17023SJohn Marino   if (to->magic != from->magic
850*e4b17023SJohn Marino       || to->is_big_endian != from->is_big_endian
851*e4b17023SJohn Marino       || to->cputype != from->cputype)
852*e4b17023SJohn Marino     {
853*e4b17023SJohn Marino       *err = 0;
854*e4b17023SJohn Marino       return "Mach-O object format mismatch";
855*e4b17023SJohn Marino     }
856*e4b17023SJohn Marino   return NULL;
857*e4b17023SJohn Marino }
858*e4b17023SJohn Marino 
859*e4b17023SJohn Marino /* Release the private data for an attributes structure.  */
860*e4b17023SJohn Marino 
861*e4b17023SJohn Marino static void
simple_object_mach_o_release_attributes(void * data)862*e4b17023SJohn Marino simple_object_mach_o_release_attributes (void *data)
863*e4b17023SJohn Marino {
864*e4b17023SJohn Marino   XDELETE (data);
865*e4b17023SJohn Marino }
866*e4b17023SJohn Marino 
867*e4b17023SJohn Marino /* Prepare to write out a file.  */
868*e4b17023SJohn Marino 
869*e4b17023SJohn Marino static void *
simple_object_mach_o_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)870*e4b17023SJohn Marino simple_object_mach_o_start_write (void *attributes_data,
871*e4b17023SJohn Marino 				  const char **errmsg ATTRIBUTE_UNUSED,
872*e4b17023SJohn Marino 				  int *err ATTRIBUTE_UNUSED)
873*e4b17023SJohn Marino {
874*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *attrs =
875*e4b17023SJohn Marino     (struct simple_object_mach_o_attributes *) attributes_data;
876*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *ret;
877*e4b17023SJohn Marino 
878*e4b17023SJohn Marino   /* We're just going to record the attributes, but we need to make a
879*e4b17023SJohn Marino      copy because the user may delete them.  */
880*e4b17023SJohn Marino   ret = XNEW (struct simple_object_mach_o_attributes);
881*e4b17023SJohn Marino   *ret = *attrs;
882*e4b17023SJohn Marino   return ret;
883*e4b17023SJohn Marino }
884*e4b17023SJohn Marino 
885*e4b17023SJohn Marino /* Write out the header of a Mach-O file.  */
886*e4b17023SJohn Marino 
887*e4b17023SJohn Marino static int
simple_object_mach_o_write_header(simple_object_write * sobj,int descriptor,size_t nsects,const char ** errmsg,int * err)888*e4b17023SJohn Marino simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
889*e4b17023SJohn Marino 				   size_t nsects, const char **errmsg,
890*e4b17023SJohn Marino 				   int *err)
891*e4b17023SJohn Marino {
892*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *attrs =
893*e4b17023SJohn Marino     (struct simple_object_mach_o_attributes *) sobj->data;
894*e4b17023SJohn Marino   void (*set_32) (unsigned char *, unsigned int);
895*e4b17023SJohn Marino   unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
896*e4b17023SJohn Marino   unsigned char *hdr;
897*e4b17023SJohn Marino   size_t wrsize;
898*e4b17023SJohn Marino 
899*e4b17023SJohn Marino   set_32 = (attrs->is_big_endian
900*e4b17023SJohn Marino 	    ? simple_object_set_big_32
901*e4b17023SJohn Marino 	    : simple_object_set_little_32);
902*e4b17023SJohn Marino 
903*e4b17023SJohn Marino   memset (hdrbuf, 0, sizeof hdrbuf);
904*e4b17023SJohn Marino 
905*e4b17023SJohn Marino   /* The 32-bit and 64-bit headers start out the same.  */
906*e4b17023SJohn Marino 
907*e4b17023SJohn Marino   hdr = &hdrbuf[0];
908*e4b17023SJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
909*e4b17023SJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
910*e4b17023SJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
911*e4b17023SJohn Marino 	  attrs->cpusubtype);
912*e4b17023SJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
913*e4b17023SJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
914*e4b17023SJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
915*e4b17023SJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
916*e4b17023SJohn Marino     {
917*e4b17023SJohn Marino       wrsize = sizeof (struct mach_o_header_32);
918*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
919*e4b17023SJohn Marino 	      (sizeof (struct mach_o_segment_command_32)
920*e4b17023SJohn Marino 	       + nsects * sizeof (struct mach_o_section_32)));
921*e4b17023SJohn Marino     }
922*e4b17023SJohn Marino   else
923*e4b17023SJohn Marino     {
924*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
925*e4b17023SJohn Marino 	      (sizeof (struct mach_o_segment_command_64)
926*e4b17023SJohn Marino 	       + nsects * sizeof (struct mach_o_section_64)));
927*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
928*e4b17023SJohn Marino 	      attrs->reserved);
929*e4b17023SJohn Marino       wrsize = sizeof (struct mach_o_header_64);
930*e4b17023SJohn Marino     }
931*e4b17023SJohn Marino 
932*e4b17023SJohn Marino   return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
933*e4b17023SJohn Marino 				       errmsg, err);
934*e4b17023SJohn Marino }
935*e4b17023SJohn Marino 
936*e4b17023SJohn Marino /* Write a Mach-O section header.  */
937*e4b17023SJohn Marino 
938*e4b17023SJohn Marino 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)939*e4b17023SJohn Marino simple_object_mach_o_write_section_header (simple_object_write *sobj,
940*e4b17023SJohn Marino 					   int descriptor,
941*e4b17023SJohn Marino 					   size_t sechdr_offset,
942*e4b17023SJohn Marino 					   const char *name, const char *segn,
943*e4b17023SJohn Marino 					   size_t secaddr, size_t secsize,
944*e4b17023SJohn Marino 					   size_t offset, unsigned int align,
945*e4b17023SJohn Marino 					   const char **errmsg, int *err)
946*e4b17023SJohn Marino {
947*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *attrs =
948*e4b17023SJohn Marino     (struct simple_object_mach_o_attributes *) sobj->data;
949*e4b17023SJohn Marino   void (*set_32) (unsigned char *, unsigned int);
950*e4b17023SJohn Marino   unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
951*e4b17023SJohn Marino   unsigned char *hdr;
952*e4b17023SJohn Marino   size_t sechdrsize;
953*e4b17023SJohn Marino 
954*e4b17023SJohn Marino   set_32 = (attrs->is_big_endian
955*e4b17023SJohn Marino 	    ? simple_object_set_big_32
956*e4b17023SJohn Marino 	    : simple_object_set_little_32);
957*e4b17023SJohn Marino 
958*e4b17023SJohn Marino   memset (hdrbuf, 0, sizeof hdrbuf);
959*e4b17023SJohn Marino 
960*e4b17023SJohn Marino   hdr = &hdrbuf[0];
961*e4b17023SJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
962*e4b17023SJohn Marino     {
963*e4b17023SJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
964*e4b17023SJohn Marino 	       name, MACH_O_NAME_LEN);
965*e4b17023SJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
966*e4b17023SJohn Marino 	       segn, MACH_O_NAME_LEN);
967*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
968*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
969*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
970*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
971*e4b17023SJohn Marino       /* reloff left as zero.  */
972*e4b17023SJohn Marino       /* nreloc left as zero.  */
973*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, flags),
974*e4b17023SJohn Marino 	      MACH_O_S_ATTR_DEBUG);
975*e4b17023SJohn Marino       /* reserved1 left as zero.  */
976*e4b17023SJohn Marino       /* reserved2 left as zero.  */
977*e4b17023SJohn Marino       sechdrsize = sizeof (struct mach_o_section_32);
978*e4b17023SJohn Marino     }
979*e4b17023SJohn Marino   else
980*e4b17023SJohn Marino     {
981*e4b17023SJohn Marino #ifdef UNSIGNED_64BIT_TYPE
982*e4b17023SJohn Marino       void (*set_64) (unsigned char *, ulong_type);
983*e4b17023SJohn Marino 
984*e4b17023SJohn Marino       set_64 = (attrs->is_big_endian
985*e4b17023SJohn Marino 		? simple_object_set_big_64
986*e4b17023SJohn Marino 		: simple_object_set_little_64);
987*e4b17023SJohn Marino 
988*e4b17023SJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
989*e4b17023SJohn Marino 	       name, MACH_O_NAME_LEN);
990*e4b17023SJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
991*e4b17023SJohn Marino 	       segn, MACH_O_NAME_LEN);
992*e4b17023SJohn Marino       set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
993*e4b17023SJohn Marino       set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
994*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
995*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
996*e4b17023SJohn Marino       /* reloff left as zero.  */
997*e4b17023SJohn Marino       /* nreloc left as zero.  */
998*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_64, flags),
999*e4b17023SJohn Marino 	      MACH_O_S_ATTR_DEBUG);
1000*e4b17023SJohn Marino       /* reserved1 left as zero.  */
1001*e4b17023SJohn Marino       /* reserved2 left as zero.  */
1002*e4b17023SJohn Marino       /* reserved3 left as zero.  */
1003*e4b17023SJohn Marino #endif
1004*e4b17023SJohn Marino       sechdrsize = sizeof (struct mach_o_section_64);
1005*e4b17023SJohn Marino     }
1006*e4b17023SJohn Marino 
1007*e4b17023SJohn Marino   return simple_object_internal_write (descriptor, sechdr_offset, hdr,
1008*e4b17023SJohn Marino 				       sechdrsize, errmsg, err);
1009*e4b17023SJohn Marino }
1010*e4b17023SJohn Marino 
1011*e4b17023SJohn Marino /* Write out the single (anonymous) segment containing the sections of a Mach-O
1012*e4b17023SJohn Marino    Object file.
1013*e4b17023SJohn Marino 
1014*e4b17023SJohn Marino    As a GNU extension to mach-o, when the caller specifies a segment name in
1015*e4b17023SJohn Marino    sobj->segment_name, all the sections passed will be output under a single
1016*e4b17023SJohn Marino    mach-o section header.  The caller's sections are indexed within this
1017*e4b17023SJohn Marino    'wrapper' section by a table stored in a second mach-o section.  Finally,
1018*e4b17023SJohn Marino    arbitrary length section names are permitted by the extension and these are
1019*e4b17023SJohn Marino    stored in a table in a third mach-o section.
1020*e4b17023SJohn Marino 
1021*e4b17023SJohn Marino    Note that this is only likely to make any sense for the __GNU_LTO segment
1022*e4b17023SJohn Marino    at present.
1023*e4b17023SJohn Marino 
1024*e4b17023SJohn Marino    If the wrapper extension is not in force, we assume that the section name
1025*e4b17023SJohn Marino    is in the form __SEGMENT_NAME,__section_name as per Mach-O asm.  */
1026*e4b17023SJohn Marino 
1027*e4b17023SJohn Marino static int
simple_object_mach_o_write_segment(simple_object_write * sobj,int descriptor,size_t * nsects,const char ** errmsg,int * err)1028*e4b17023SJohn Marino simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
1029*e4b17023SJohn Marino 				    size_t *nsects, const char **errmsg,
1030*e4b17023SJohn Marino 				    int *err)
1031*e4b17023SJohn Marino {
1032*e4b17023SJohn Marino   struct simple_object_mach_o_attributes *attrs =
1033*e4b17023SJohn Marino     (struct simple_object_mach_o_attributes *) sobj->data;
1034*e4b17023SJohn Marino   void (*set_32) (unsigned char *, unsigned int);
1035*e4b17023SJohn Marino   size_t hdrsize;
1036*e4b17023SJohn Marino   size_t seghdrsize;
1037*e4b17023SJohn Marino   size_t sechdrsize;
1038*e4b17023SJohn Marino   size_t cmdsize;
1039*e4b17023SJohn Marino   size_t offset;
1040*e4b17023SJohn Marino   size_t sechdr_offset;
1041*e4b17023SJohn Marino   size_t secaddr;
1042*e4b17023SJohn Marino   unsigned int name_offset;
1043*e4b17023SJohn Marino   simple_object_write_section *section;
1044*e4b17023SJohn Marino   unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
1045*e4b17023SJohn Marino   unsigned char *hdr;
1046*e4b17023SJohn Marino   size_t nsects_in;
1047*e4b17023SJohn Marino   unsigned int *index;
1048*e4b17023SJohn Marino   char *snames;
1049*e4b17023SJohn Marino   unsigned int sect;
1050*e4b17023SJohn Marino 
1051*e4b17023SJohn Marino   set_32 = (attrs->is_big_endian
1052*e4b17023SJohn Marino 	    ? simple_object_set_big_32
1053*e4b17023SJohn Marino 	    : simple_object_set_little_32);
1054*e4b17023SJohn Marino 
1055*e4b17023SJohn Marino   /* Write out the sections first.  */
1056*e4b17023SJohn Marino 
1057*e4b17023SJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
1058*e4b17023SJohn Marino     {
1059*e4b17023SJohn Marino       hdrsize = sizeof (struct mach_o_header_32);
1060*e4b17023SJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_32);
1061*e4b17023SJohn Marino       sechdrsize = sizeof (struct mach_o_section_32);
1062*e4b17023SJohn Marino     }
1063*e4b17023SJohn Marino   else
1064*e4b17023SJohn Marino     {
1065*e4b17023SJohn Marino       hdrsize = sizeof (struct mach_o_header_64);
1066*e4b17023SJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_64);
1067*e4b17023SJohn Marino       sechdrsize = sizeof (struct mach_o_section_64);
1068*e4b17023SJohn Marino     }
1069*e4b17023SJohn Marino 
1070*e4b17023SJohn Marino   name_offset = 0;
1071*e4b17023SJohn Marino   *nsects = nsects_in = 0;
1072*e4b17023SJohn Marino 
1073*e4b17023SJohn Marino   /* Count the number of sections we start with.  */
1074*e4b17023SJohn Marino 
1075*e4b17023SJohn Marino   for (section = sobj->sections; section != NULL; section = section->next)
1076*e4b17023SJohn Marino     nsects_in++;
1077*e4b17023SJohn Marino 
1078*e4b17023SJohn Marino   if (sobj->segment_name != NULL)
1079*e4b17023SJohn Marino     {
1080*e4b17023SJohn Marino       /* We will only write 3 sections: wrapped data, index and names.  */
1081*e4b17023SJohn Marino 
1082*e4b17023SJohn Marino       *nsects = 3;
1083*e4b17023SJohn Marino 
1084*e4b17023SJohn Marino       /* The index has four entries per wrapped section:
1085*e4b17023SJohn Marino 	   Section Offset, length,  Name offset, length.
1086*e4b17023SJohn Marino 	 Where the offsets are based at the start of the wrapper and name
1087*e4b17023SJohn Marino 	 sections respectively.
1088*e4b17023SJohn Marino 	 The values are stored as 32 bit int for both 32 and 64 bit mach-o
1089*e4b17023SJohn Marino 	 since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
1090*e4b17023SJohn Marino 	 other constraints.  */
1091*e4b17023SJohn Marino 
1092*e4b17023SJohn Marino       index = XNEWVEC (unsigned int, nsects_in * 4);
1093*e4b17023SJohn Marino 
1094*e4b17023SJohn Marino       /* We now need to figure out the size of the names section.  This just
1095*e4b17023SJohn Marino 	 stores the names as null-terminated c strings, packed without any
1096*e4b17023SJohn Marino 	 alignment padding.  */
1097*e4b17023SJohn Marino 
1098*e4b17023SJohn Marino       for (section = sobj->sections, sect = 0; section != NULL;
1099*e4b17023SJohn Marino 	   section = section->next, sect++)
1100*e4b17023SJohn Marino 	{
1101*e4b17023SJohn Marino 	  index[sect*4+2] = name_offset;
1102*e4b17023SJohn Marino 	  index[sect*4+3] = strlen (section->name) + 1;
1103*e4b17023SJohn Marino 	  name_offset += strlen (section->name) + 1;
1104*e4b17023SJohn Marino 	}
1105*e4b17023SJohn Marino       snames = XNEWVEC (char, name_offset);
1106*e4b17023SJohn Marino     }
1107*e4b17023SJohn Marino   else
1108*e4b17023SJohn Marino     {
1109*e4b17023SJohn Marino       *nsects = nsects_in;
1110*e4b17023SJohn Marino       index = NULL;
1111*e4b17023SJohn Marino       snames = NULL;
1112*e4b17023SJohn Marino     }
1113*e4b17023SJohn Marino 
1114*e4b17023SJohn Marino   sechdr_offset = hdrsize + seghdrsize;
1115*e4b17023SJohn Marino   cmdsize = seghdrsize + *nsects * sechdrsize;
1116*e4b17023SJohn Marino   offset = hdrsize + cmdsize;
1117*e4b17023SJohn Marino   secaddr = 0;
1118*e4b17023SJohn Marino 
1119*e4b17023SJohn Marino   for (section = sobj->sections, sect = 0;
1120*e4b17023SJohn Marino        section != NULL; section = section->next, sect++)
1121*e4b17023SJohn Marino     {
1122*e4b17023SJohn Marino       size_t mask;
1123*e4b17023SJohn Marino       size_t new_offset;
1124*e4b17023SJohn Marino       size_t secsize;
1125*e4b17023SJohn Marino       struct simple_object_write_section_buffer *buffer;
1126*e4b17023SJohn Marino 
1127*e4b17023SJohn Marino       mask = (1U << section->align) - 1;
1128*e4b17023SJohn Marino       new_offset = offset + mask;
1129*e4b17023SJohn Marino       new_offset &= ~ mask;
1130*e4b17023SJohn Marino       while (new_offset > offset)
1131*e4b17023SJohn Marino 	{
1132*e4b17023SJohn Marino 	  unsigned char zeroes[16];
1133*e4b17023SJohn Marino 	  size_t write;
1134*e4b17023SJohn Marino 
1135*e4b17023SJohn Marino 	  memset (zeroes, 0, sizeof zeroes);
1136*e4b17023SJohn Marino 	  write = new_offset - offset;
1137*e4b17023SJohn Marino 	  if (write > sizeof zeroes)
1138*e4b17023SJohn Marino 	    write = sizeof zeroes;
1139*e4b17023SJohn Marino 	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
1140*e4b17023SJohn Marino 					     errmsg, err))
1141*e4b17023SJohn Marino 	    return 0;
1142*e4b17023SJohn Marino 	  offset += write;
1143*e4b17023SJohn Marino 	}
1144*e4b17023SJohn Marino 
1145*e4b17023SJohn Marino       secsize = 0;
1146*e4b17023SJohn Marino       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1147*e4b17023SJohn Marino 	{
1148*e4b17023SJohn Marino 	  if (!simple_object_internal_write (descriptor, offset + secsize,
1149*e4b17023SJohn Marino 					     ((const unsigned char *)
1150*e4b17023SJohn Marino 					      buffer->buffer),
1151*e4b17023SJohn Marino 					     buffer->size, errmsg, err))
1152*e4b17023SJohn Marino 	    return 0;
1153*e4b17023SJohn Marino 	  secsize += buffer->size;
1154*e4b17023SJohn Marino 	}
1155*e4b17023SJohn Marino 
1156*e4b17023SJohn Marino       if (sobj->segment_name != NULL)
1157*e4b17023SJohn Marino 	{
1158*e4b17023SJohn Marino 	  index[sect*4+0] = (unsigned int) offset;
1159*e4b17023SJohn Marino 	  index[sect*4+1] = secsize;
1160*e4b17023SJohn Marino 	  /* Stash the section name in our table.  */
1161*e4b17023SJohn Marino 	  memcpy (snames + index[sect * 4 + 2], section->name,
1162*e4b17023SJohn Marino 		  index[sect * 4 + 3]);
1163*e4b17023SJohn Marino 	}
1164*e4b17023SJohn Marino       else
1165*e4b17023SJohn Marino 	{
1166*e4b17023SJohn Marino 	  char namebuf[MACH_O_NAME_LEN + 1];
1167*e4b17023SJohn Marino 	  char segnbuf[MACH_O_NAME_LEN + 1];
1168*e4b17023SJohn Marino 	  char *comma;
1169*e4b17023SJohn Marino 
1170*e4b17023SJohn Marino 	  /* Try to extract segment,section from the input name.  */
1171*e4b17023SJohn Marino 
1172*e4b17023SJohn Marino 	  memset (namebuf, 0, sizeof namebuf);
1173*e4b17023SJohn Marino 	  memset (segnbuf, 0, sizeof segnbuf);
1174*e4b17023SJohn Marino 	  comma = strchr (section->name, ',');
1175*e4b17023SJohn Marino 	  if (comma != NULL)
1176*e4b17023SJohn Marino 	    {
1177*e4b17023SJohn Marino 	      int len = comma - section->name;
1178*e4b17023SJohn Marino 	      len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
1179*e4b17023SJohn Marino 	      strncpy (namebuf, section->name, len);
1180*e4b17023SJohn Marino 	      strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
1181*e4b17023SJohn Marino 	    }
1182*e4b17023SJohn Marino 	  else /* just try to copy the name, leave segment blank.  */
1183*e4b17023SJohn Marino 	    strncpy (namebuf, section->name, MACH_O_NAME_LEN);
1184*e4b17023SJohn Marino 
1185*e4b17023SJohn Marino 	  if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1186*e4b17023SJohn Marino 							  sechdr_offset,
1187*e4b17023SJohn Marino 							  namebuf, segnbuf,
1188*e4b17023SJohn Marino 							  secaddr, secsize,
1189*e4b17023SJohn Marino 							  offset,
1190*e4b17023SJohn Marino 							  section->align,
1191*e4b17023SJohn Marino 							  errmsg, err))
1192*e4b17023SJohn Marino 	    return 0;
1193*e4b17023SJohn Marino 	  sechdr_offset += sechdrsize;
1194*e4b17023SJohn Marino 	}
1195*e4b17023SJohn Marino 
1196*e4b17023SJohn Marino       offset += secsize;
1197*e4b17023SJohn Marino       secaddr += secsize;
1198*e4b17023SJohn Marino     }
1199*e4b17023SJohn Marino 
1200*e4b17023SJohn Marino   if (sobj->segment_name != NULL)
1201*e4b17023SJohn Marino     {
1202*e4b17023SJohn Marino       size_t secsize;
1203*e4b17023SJohn Marino       unsigned int i;
1204*e4b17023SJohn Marino 
1205*e4b17023SJohn Marino       /* Write the section header for the wrapper.  */
1206*e4b17023SJohn Marino       /* Account for any initial aligment - which becomes the alignment for this
1207*e4b17023SJohn Marino 	 created section.  */
1208*e4b17023SJohn Marino 
1209*e4b17023SJohn Marino       secsize = (offset - index[0]);
1210*e4b17023SJohn Marino       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1211*e4b17023SJohn Marino 						      sechdr_offset,
1212*e4b17023SJohn Marino 						      GNU_WRAPPER_SECTS,
1213*e4b17023SJohn Marino 						      sobj->segment_name,
1214*e4b17023SJohn Marino 						      0 /*secaddr*/,
1215*e4b17023SJohn Marino 						      secsize, index[0],
1216*e4b17023SJohn Marino 						      sobj->sections->align,
1217*e4b17023SJohn Marino 						      errmsg, err))
1218*e4b17023SJohn Marino 	return 0;
1219*e4b17023SJohn Marino 
1220*e4b17023SJohn Marino       /* Subtract the wrapper section start from the begining of each sub
1221*e4b17023SJohn Marino 	 section.  */
1222*e4b17023SJohn Marino 
1223*e4b17023SJohn Marino       for (i = 1; i < nsects_in; ++i)
1224*e4b17023SJohn Marino 	index[4 * i] -= index[0];
1225*e4b17023SJohn Marino       index[0] = 0;
1226*e4b17023SJohn Marino 
1227*e4b17023SJohn Marino       sechdr_offset += sechdrsize;
1228*e4b17023SJohn Marino 
1229*e4b17023SJohn Marino       /* Write out the section names.
1230*e4b17023SJohn Marino 	 ... the header ...
1231*e4b17023SJohn Marino 	 name_offset contains the length of the section.  It is not aligned.  */
1232*e4b17023SJohn Marino 
1233*e4b17023SJohn Marino       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1234*e4b17023SJohn Marino 						      sechdr_offset,
1235*e4b17023SJohn Marino 						      GNU_WRAPPER_NAMES,
1236*e4b17023SJohn Marino 						      sobj->segment_name,
1237*e4b17023SJohn Marino 						      0 /*secaddr*/,
1238*e4b17023SJohn Marino 						      name_offset,
1239*e4b17023SJohn Marino 						      offset,
1240*e4b17023SJohn Marino 						      0, errmsg, err))
1241*e4b17023SJohn Marino 	return 0;
1242*e4b17023SJohn Marino 
1243*e4b17023SJohn Marino       /* ... and the content.. */
1244*e4b17023SJohn Marino       if (!simple_object_internal_write (descriptor, offset,
1245*e4b17023SJohn Marino 					 (const unsigned char *) snames,
1246*e4b17023SJohn Marino 					 name_offset, errmsg, err))
1247*e4b17023SJohn Marino 	return 0;
1248*e4b17023SJohn Marino 
1249*e4b17023SJohn Marino       sechdr_offset += sechdrsize;
1250*e4b17023SJohn Marino       secaddr += name_offset;
1251*e4b17023SJohn Marino       offset += name_offset;
1252*e4b17023SJohn Marino 
1253*e4b17023SJohn Marino       /* Now do the index, we'll align this to 4 bytes although the read code
1254*e4b17023SJohn Marino 	 will handle unaligned.  */
1255*e4b17023SJohn Marino 
1256*e4b17023SJohn Marino       offset += 3;
1257*e4b17023SJohn Marino       offset &= ~0x03;
1258*e4b17023SJohn Marino       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1259*e4b17023SJohn Marino 						      sechdr_offset,
1260*e4b17023SJohn Marino 						      GNU_WRAPPER_INDEX,
1261*e4b17023SJohn Marino 						      sobj->segment_name,
1262*e4b17023SJohn Marino 						      0 /*secaddr*/,
1263*e4b17023SJohn Marino 						      nsects_in * 16,
1264*e4b17023SJohn Marino 						      offset,
1265*e4b17023SJohn Marino 						      2, errmsg, err))
1266*e4b17023SJohn Marino 	return 0;
1267*e4b17023SJohn Marino 
1268*e4b17023SJohn Marino       /* ... and the content.. */
1269*e4b17023SJohn Marino       if (!simple_object_internal_write (descriptor, offset,
1270*e4b17023SJohn Marino 					 (const unsigned char *) index,
1271*e4b17023SJohn Marino 					 nsects_in*16, errmsg, err))
1272*e4b17023SJohn Marino 	return 0;
1273*e4b17023SJohn Marino 
1274*e4b17023SJohn Marino       XDELETEVEC (index);
1275*e4b17023SJohn Marino       XDELETEVEC (snames);
1276*e4b17023SJohn Marino     }
1277*e4b17023SJohn Marino 
1278*e4b17023SJohn Marino   /* Write out the segment header.  */
1279*e4b17023SJohn Marino 
1280*e4b17023SJohn Marino   memset (hdrbuf, 0, sizeof hdrbuf);
1281*e4b17023SJohn Marino 
1282*e4b17023SJohn Marino   hdr = &hdrbuf[0];
1283*e4b17023SJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
1284*e4b17023SJohn Marino     {
1285*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
1286*e4b17023SJohn Marino 	      MACH_O_LC_SEGMENT);
1287*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
1288*e4b17023SJohn Marino 	      cmdsize);
1289*e4b17023SJohn Marino      /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1290*e4b17023SJohn Marino 	 is left empty.  */
1291*e4b17023SJohn Marino       /* vmaddr left as zero.  */
1292*e4b17023SJohn Marino       /* vmsize left as zero.  */
1293*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
1294*e4b17023SJohn Marino 	      hdrsize + cmdsize);
1295*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
1296*e4b17023SJohn Marino 	      offset - (hdrsize + cmdsize));
1297*e4b17023SJohn Marino       /* maxprot left as zero.  */
1298*e4b17023SJohn Marino       /* initprot left as zero.  */
1299*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
1300*e4b17023SJohn Marino 	      *nsects);
1301*e4b17023SJohn Marino       /* flags left as zero.  */
1302*e4b17023SJohn Marino     }
1303*e4b17023SJohn Marino   else
1304*e4b17023SJohn Marino     {
1305*e4b17023SJohn Marino #ifdef UNSIGNED_64BIT_TYPE
1306*e4b17023SJohn Marino       void (*set_64) (unsigned char *, ulong_type);
1307*e4b17023SJohn Marino 
1308*e4b17023SJohn Marino       set_64 = (attrs->is_big_endian
1309*e4b17023SJohn Marino 		? simple_object_set_big_64
1310*e4b17023SJohn Marino 		: simple_object_set_little_64);
1311*e4b17023SJohn Marino 
1312*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
1313*e4b17023SJohn Marino 	      MACH_O_LC_SEGMENT);
1314*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
1315*e4b17023SJohn Marino 	      cmdsize);
1316*e4b17023SJohn Marino       /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1317*e4b17023SJohn Marino 	 is left empty.  */
1318*e4b17023SJohn Marino       /* vmaddr left as zero.  */
1319*e4b17023SJohn Marino       /* vmsize left as zero.  */
1320*e4b17023SJohn Marino       set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
1321*e4b17023SJohn Marino 	      hdrsize + cmdsize);
1322*e4b17023SJohn Marino       set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
1323*e4b17023SJohn Marino 	      offset - (hdrsize + cmdsize));
1324*e4b17023SJohn Marino       /* maxprot left as zero.  */
1325*e4b17023SJohn Marino       /* initprot left as zero.  */
1326*e4b17023SJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
1327*e4b17023SJohn Marino 	      *nsects);
1328*e4b17023SJohn Marino       /* flags left as zero.  */
1329*e4b17023SJohn Marino #endif
1330*e4b17023SJohn Marino     }
1331*e4b17023SJohn Marino 
1332*e4b17023SJohn Marino   return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
1333*e4b17023SJohn Marino 				       errmsg, err);
1334*e4b17023SJohn Marino }
1335*e4b17023SJohn Marino 
1336*e4b17023SJohn Marino /* Write out a complete Mach-O file.  */
1337*e4b17023SJohn Marino 
1338*e4b17023SJohn Marino static const char *
simple_object_mach_o_write_to_file(simple_object_write * sobj,int descriptor,int * err)1339*e4b17023SJohn Marino simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
1340*e4b17023SJohn Marino 				    int *err)
1341*e4b17023SJohn Marino {
1342*e4b17023SJohn Marino   size_t nsects = 0;
1343*e4b17023SJohn Marino   const char *errmsg;
1344*e4b17023SJohn Marino 
1345*e4b17023SJohn Marino   if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
1346*e4b17023SJohn Marino 					   &errmsg, err))
1347*e4b17023SJohn Marino     return errmsg;
1348*e4b17023SJohn Marino 
1349*e4b17023SJohn Marino   if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
1350*e4b17023SJohn Marino 					  &errmsg, err))
1351*e4b17023SJohn Marino     return errmsg;
1352*e4b17023SJohn Marino 
1353*e4b17023SJohn Marino   return NULL;
1354*e4b17023SJohn Marino }
1355*e4b17023SJohn Marino 
1356*e4b17023SJohn Marino /* Release the private data for an simple_object_write structure.  */
1357*e4b17023SJohn Marino 
1358*e4b17023SJohn Marino static void
simple_object_mach_o_release_write(void * data)1359*e4b17023SJohn Marino simple_object_mach_o_release_write (void *data)
1360*e4b17023SJohn Marino {
1361*e4b17023SJohn Marino   XDELETE (data);
1362*e4b17023SJohn Marino }
1363*e4b17023SJohn Marino 
1364*e4b17023SJohn Marino /* The Mach-O functions.  */
1365*e4b17023SJohn Marino 
1366*e4b17023SJohn Marino const struct simple_object_functions simple_object_mach_o_functions =
1367*e4b17023SJohn Marino {
1368*e4b17023SJohn Marino   simple_object_mach_o_match,
1369*e4b17023SJohn Marino   simple_object_mach_o_find_sections,
1370*e4b17023SJohn Marino   simple_object_mach_o_fetch_attributes,
1371*e4b17023SJohn Marino   simple_object_mach_o_release_read,
1372*e4b17023SJohn Marino   simple_object_mach_o_attributes_merge,
1373*e4b17023SJohn Marino   simple_object_mach_o_release_attributes,
1374*e4b17023SJohn Marino   simple_object_mach_o_start_write,
1375*e4b17023SJohn Marino   simple_object_mach_o_write_to_file,
1376*e4b17023SJohn Marino   simple_object_mach_o_release_write
1377*e4b17023SJohn Marino };
1378