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