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