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