xref: /dflybsd-src/contrib/gdb-7/libiberty/simple-object-mach-o.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
1c50c785cSJohn Marino /* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2*ef5ccd6cSJohn Marino    Copyright 2010, 2011, 2013 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 
177a45ae5f8SJohn Marino /* A GNU-specific extension to wrap multiple sections using three
178a45ae5f8SJohn Marino    mach-o sections within a given segment.  The section '__wrapper_sects'
179a45ae5f8SJohn Marino    is subdivided according to the index '__wrapper_index' and each sub
180a45ae5f8SJohn Marino    sect is named according to the names supplied in '__wrapper_names'.  */
181a45ae5f8SJohn Marino 
182a45ae5f8SJohn Marino #define GNU_WRAPPER_SECTS "__wrapper_sects"
183a45ae5f8SJohn Marino #define GNU_WRAPPER_INDEX "__wrapper_index"
184a45ae5f8SJohn Marino #define GNU_WRAPPER_NAMES "__wrapper_names"
185a45ae5f8SJohn 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 
226a45ae5f8SJohn Marino /* See if we have a Mach-O MH_OBJECT file:
227a45ae5f8SJohn Marino 
228a45ae5f8SJohn Marino    A standard MH_OBJECT (from as) will have three load commands:
229a45ae5f8SJohn Marino    0 - LC_SEGMENT/LC_SEGMENT64
230a45ae5f8SJohn Marino    1 - LC_SYMTAB
231a45ae5f8SJohn Marino    2 - LC_DYSYMTAB
232a45ae5f8SJohn Marino 
233a45ae5f8SJohn Marino    The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment
234a45ae5f8SJohn Marino    containing all the sections.
235a45ae5f8SJohn Marino 
236a45ae5f8SJohn Marino    Files written by simple-object will have only the segment command
237a45ae5f8SJohn Marino    (no symbol tables).  */
238c50c785cSJohn Marino 
239c50c785cSJohn Marino static void *
simple_object_mach_o_match(unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],int descriptor,off_t offset,const char * segment_name,const char ** errmsg,int * err)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
simple_object_mach_o_section_info(int is_big_endian,int is_32,const unsigned char * sechdr,off_t * offset,size_t * size)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 
379a45ae5f8SJohn Marino /* Handle a segment in a Mach-O Object file.
380a45ae5f8SJohn Marino 
381a45ae5f8SJohn Marino    This will callback to the function pfn for each "section found" the meaning
382a45ae5f8SJohn Marino    of which depends on gnu extensions to mach-o:
383a45ae5f8SJohn Marino 
384a45ae5f8SJohn Marino    If we find mach-o sections (with the segment name as specified) which also
385a45ae5f8SJohn Marino    contain: a 'sects' wrapper, an index, and a  name table, we expand this into
386a45ae5f8SJohn Marino    as many sections as are specified in the index.  In this case, there will
387a45ae5f8SJohn Marino    be a callback for each of these.
388a45ae5f8SJohn Marino 
389a45ae5f8SJohn Marino    We will also allow an extension that permits long names (more than 16
390a45ae5f8SJohn Marino    characters) to be used with mach-o.  In this case, the section name has
391a45ae5f8SJohn Marino    a specific format embedding an index into a name table, and the file must
392a45ae5f8SJohn Marino    contain such name table.
393a45ae5f8SJohn Marino 
394a45ae5f8SJohn Marino    Return 1 if we should continue, 0 if the caller should return.  */
395a45ae5f8SJohn Marino 
396a45ae5f8SJohn Marino #define SOMO_SECTS_PRESENT 0x01
397a45ae5f8SJohn Marino #define SOMO_INDEX_PRESENT 0x02
398a45ae5f8SJohn Marino #define SOMO_NAMES_PRESENT 0x04
399a45ae5f8SJohn Marino #define SOMO_LONGN_PRESENT 0x08
400a45ae5f8SJohn Marino #define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \
401a45ae5f8SJohn Marino 		       | SOMO_NAMES_PRESENT)
402c50c785cSJohn Marino 
403c50c785cSJohn Marino static int
simple_object_mach_o_segment(simple_object_read * sobj,off_t offset,const unsigned char * segbuf,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,const char ** errmsg,int * err)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;
422a45ae5f8SJohn Marino   unsigned int gnu_sections_found;
423c50c785cSJohn Marino   unsigned int strtab_index;
424a45ae5f8SJohn Marino   unsigned int index_index;
425a45ae5f8SJohn Marino   unsigned int nametab_index;
426a45ae5f8SJohn Marino   unsigned int sections_index;
427c50c785cSJohn Marino   char *strtab;
428a45ae5f8SJohn Marino   char *nametab;
429a45ae5f8SJohn Marino   unsigned char *index;
430c50c785cSJohn Marino   size_t strtab_size;
431a45ae5f8SJohn Marino   size_t nametab_size;
432a45ae5f8SJohn Marino   size_t index_size;
433a45ae5f8SJohn Marino   unsigned int n_wrapped_sects;
434a45ae5f8SJohn Marino   size_t wrapper_sect_size;
435a45ae5f8SJohn 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 
464a45ae5f8SJohn Marino   /* Fetch the section headers from the segment command.  */
465a45ae5f8SJohn 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 
474a45ae5f8SJohn Marino   /* Scan for special sections that signal GNU extensions to the format.  */
475c50c785cSJohn Marino 
476a45ae5f8SJohn Marino   gnu_sections_found = 0;
477a45ae5f8SJohn Marino   index_index = nsects;
478a45ae5f8SJohn Marino   sections_index = nsects;
479a45ae5f8SJohn Marino   strtab_index = nsects;
480a45ae5f8SJohn 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;
488a45ae5f8SJohn Marino 
489c50c785cSJohn Marino       nameoff = i * sechdrsize + sectname_offset;
490a45ae5f8SJohn Marino       if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0)
491a45ae5f8SJohn Marino 	{
492a45ae5f8SJohn Marino 	  nametab_index = i;
493a45ae5f8SJohn Marino 	  gnu_sections_found |= SOMO_NAMES_PRESENT;
494a45ae5f8SJohn Marino 	}
495a45ae5f8SJohn Marino       else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0)
496a45ae5f8SJohn Marino 	{
497a45ae5f8SJohn Marino 	  index_index = i;
498a45ae5f8SJohn Marino 	  gnu_sections_found |= SOMO_INDEX_PRESENT;
499a45ae5f8SJohn Marino 	}
500a45ae5f8SJohn Marino       else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0)
501a45ae5f8SJohn Marino 	{
502a45ae5f8SJohn Marino 	  sections_index = i;
503a45ae5f8SJohn Marino 	  gnu_sections_found |= SOMO_SECTS_PRESENT;
504a45ae5f8SJohn Marino 	}
505a45ae5f8SJohn Marino       else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
506a45ae5f8SJohn Marino 	{
507a45ae5f8SJohn Marino 	  strtab_index = i;
508a45ae5f8SJohn Marino 	  gnu_sections_found |= SOMO_LONGN_PRESENT;
509a45ae5f8SJohn Marino 	}
510c50c785cSJohn Marino     }
511c50c785cSJohn Marino 
512a45ae5f8SJohn Marino   /* If any of the special wrapper section components is present, then
513a45ae5f8SJohn Marino      they all should be.  */
514a45ae5f8SJohn Marino 
515a45ae5f8SJohn Marino   if ((gnu_sections_found & SOMO_WRAPPING) != 0)
516c50c785cSJohn Marino     {
517a45ae5f8SJohn Marino       off_t nametab_offset;
518a45ae5f8SJohn Marino       off_t index_offset;
519a45ae5f8SJohn Marino 
520a45ae5f8SJohn Marino       if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING)
521a45ae5f8SJohn Marino 	{
522a45ae5f8SJohn Marino 	  *errmsg = "GNU Mach-o section wrapper: required section missing";
523a45ae5f8SJohn Marino 	  *err = 0; /* No useful errno.  */
524a45ae5f8SJohn Marino 	  XDELETEVEC (secdata);
525a45ae5f8SJohn Marino 	  return 0;
526a45ae5f8SJohn Marino 	}
527a45ae5f8SJohn Marino 
528a45ae5f8SJohn Marino       /* Fetch the name table.  */
529a45ae5f8SJohn Marino 
530a45ae5f8SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
531a45ae5f8SJohn Marino 					 secdata + nametab_index * sechdrsize,
532a45ae5f8SJohn Marino 					 &nametab_offset, &nametab_size);
533a45ae5f8SJohn Marino       nametab = XNEWVEC (char, nametab_size);
534a45ae5f8SJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
535a45ae5f8SJohn Marino 					sobj->offset + nametab_offset,
536a45ae5f8SJohn Marino 					(unsigned char *) nametab, nametab_size,
537a45ae5f8SJohn Marino 					errmsg, err))
538a45ae5f8SJohn Marino 	{
539a45ae5f8SJohn Marino 	  XDELETEVEC (nametab);
540a45ae5f8SJohn Marino 	  XDELETEVEC (secdata);
541a45ae5f8SJohn Marino 	  return 0;
542a45ae5f8SJohn Marino 	}
543a45ae5f8SJohn Marino 
544a45ae5f8SJohn Marino       /* Fetch the index.  */
545a45ae5f8SJohn Marino 
546a45ae5f8SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
547a45ae5f8SJohn Marino 					 secdata + index_index * sechdrsize,
548a45ae5f8SJohn Marino 					 &index_offset, &index_size);
549a45ae5f8SJohn Marino       index = XNEWVEC (unsigned char, index_size);
550a45ae5f8SJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
551a45ae5f8SJohn Marino 					sobj->offset + index_offset,
552a45ae5f8SJohn Marino 					index, index_size,
553a45ae5f8SJohn Marino 					errmsg, err))
554a45ae5f8SJohn Marino 	{
555a45ae5f8SJohn Marino 	  XDELETEVEC (index);
556a45ae5f8SJohn Marino 	  XDELETEVEC (nametab);
557a45ae5f8SJohn Marino 	  XDELETEVEC (secdata);
558a45ae5f8SJohn Marino 	  return 0;
559a45ae5f8SJohn Marino 	}
560a45ae5f8SJohn Marino 
561a45ae5f8SJohn Marino       /* The index contains 4 unsigned ints per sub-section:
562a45ae5f8SJohn Marino 	 sub-section offset/length, sub-section name/length.
563a45ae5f8SJohn Marino 	 We fix this for both 32 and 64 bit mach-o for now, since
564a45ae5f8SJohn Marino 	 other fields limit the maximum size of an object to 4G.  */
565a45ae5f8SJohn Marino       n_wrapped_sects = index_size / 16;
566a45ae5f8SJohn Marino 
567a45ae5f8SJohn Marino       /* Get the parameters for the wrapper too.  */
568a45ae5f8SJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
569a45ae5f8SJohn Marino 					 secdata + sections_index * sechdrsize,
570a45ae5f8SJohn Marino 					 &wrapper_sect_offset,
571a45ae5f8SJohn Marino 					 &wrapper_sect_size);
572c50c785cSJohn Marino     }
573c50c785cSJohn Marino   else
574c50c785cSJohn Marino     {
575a45ae5f8SJohn Marino       index = NULL;
576a45ae5f8SJohn Marino       index_size = 0;
577a45ae5f8SJohn Marino       nametab = NULL;
578a45ae5f8SJohn Marino       nametab_size = 0;
579a45ae5f8SJohn Marino       n_wrapped_sects = 0;
580a45ae5f8SJohn Marino     }
581a45ae5f8SJohn Marino 
582a45ae5f8SJohn Marino   /* If we have a long names section, fetch it.  */
583a45ae5f8SJohn Marino 
584a45ae5f8SJohn Marino   if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
585a45ae5f8SJohn 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);
598a45ae5f8SJohn Marino 	  XDELETEVEC (index);
599a45ae5f8SJohn Marino 	  XDELETEVEC (nametab);
600c50c785cSJohn Marino 	  XDELETEVEC (secdata);
601c50c785cSJohn Marino 	  return 0;
602c50c785cSJohn Marino 	}
603c50c785cSJohn Marino     }
604a45ae5f8SJohn Marino   else
605a45ae5f8SJohn Marino     {
606a45ae5f8SJohn Marino       strtab = NULL;
607a45ae5f8SJohn Marino       strtab_size = 0;
608a45ae5f8SJohn Marino       strtab_index = nsects;
609a45ae5f8SJohn 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;
616a45ae5f8SJohn Marino       char namebuf[MACH_O_NAME_LEN * 2 + 2];
617c50c785cSJohn Marino       char *name;
618c50c785cSJohn Marino       off_t secoffset;
619c50c785cSJohn Marino       size_t secsize;
620a45ae5f8SJohn Marino       int l;
621c50c785cSJohn Marino 
622c50c785cSJohn Marino       sechdr = secdata + i * sechdrsize;
623c50c785cSJohn Marino 
624a45ae5f8SJohn Marino       /* We've already processed the long section names.  */
625a45ae5f8SJohn Marino 
626a45ae5f8SJohn Marino       if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0
627a45ae5f8SJohn Marino 	  && i == strtab_index)
628a45ae5f8SJohn Marino 	continue;
629a45ae5f8SJohn Marino 
630a45ae5f8SJohn Marino       /* We only act on the segment named.  */
631a45ae5f8SJohn Marino 
632c50c785cSJohn Marino       if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
633c50c785cSJohn Marino 	continue;
634c50c785cSJohn Marino 
635a45ae5f8SJohn Marino       /* Process sections associated with the wrapper.  */
636a45ae5f8SJohn Marino 
637a45ae5f8SJohn Marino       if ((gnu_sections_found & SOMO_WRAPPING) != 0)
638a45ae5f8SJohn Marino 	{
639a45ae5f8SJohn Marino 	  if (i == nametab_index || i == index_index)
640a45ae5f8SJohn Marino 	    continue;
641a45ae5f8SJohn Marino 
642a45ae5f8SJohn Marino 	  if (i == sections_index)
643a45ae5f8SJohn Marino 	    {
644a45ae5f8SJohn Marino 	      unsigned int j;
645a45ae5f8SJohn Marino 	      for (j = 0; j < n_wrapped_sects; ++j)
646a45ae5f8SJohn Marino 		{
647a45ae5f8SJohn Marino 		  unsigned int subsect_offset, subsect_length, name_offset;
648a45ae5f8SJohn Marino 		  subsect_offset = (*fetch_32) (index + 16 * j);
649a45ae5f8SJohn Marino 		  subsect_length = (*fetch_32) (index + 16 * j + 4);
650a45ae5f8SJohn Marino 		  name_offset = (*fetch_32) (index + 16 * j + 8);
651a45ae5f8SJohn Marino 		  /* We don't need the name_length yet.  */
652a45ae5f8SJohn Marino 
653a45ae5f8SJohn Marino 		  secoffset = wrapper_sect_offset + subsect_offset;
654a45ae5f8SJohn Marino 		  secsize = subsect_length;
655a45ae5f8SJohn Marino 		  name = nametab + name_offset;
656a45ae5f8SJohn Marino 
657a45ae5f8SJohn Marino 		  if (!(*pfn) (data, name, secoffset, secsize))
658a45ae5f8SJohn Marino 		    {
659a45ae5f8SJohn Marino 		      *errmsg = NULL;
660a45ae5f8SJohn Marino 		      *err = 0;
661a45ae5f8SJohn Marino 		      XDELETEVEC (index);
662a45ae5f8SJohn Marino 		      XDELETEVEC (nametab);
663a45ae5f8SJohn Marino 		      XDELETEVEC (strtab);
664a45ae5f8SJohn Marino 		      XDELETEVEC (secdata);
665a45ae5f8SJohn Marino 		      return 0;
666a45ae5f8SJohn Marino 		    }
667a45ae5f8SJohn Marino 		}
668a45ae5f8SJohn Marino 	      continue;
669a45ae5f8SJohn Marino 	    }
670a45ae5f8SJohn Marino 	}
671a45ae5f8SJohn Marino 
672a45ae5f8SJohn Marino       if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
673a45ae5f8SJohn 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;
688a45ae5f8SJohn Marino 		      XDELETEVEC (index);
689a45ae5f8SJohn 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 	  }
698a45ae5f8SJohn Marino 	}
699a45ae5f8SJohn Marino       else
700a45ae5f8SJohn Marino 	{
701a45ae5f8SJohn Marino 	   /* Otherwise, make a name like __segment,__section as per the
702a45ae5f8SJohn Marino 	      convention in mach-o asm.  */
703a45ae5f8SJohn Marino 	  name = &namebuf[0];
704a45ae5f8SJohn Marino 	  memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
705*ef5ccd6cSJohn Marino 	  namebuf[MACH_O_NAME_LEN] = '\0';
706a45ae5f8SJohn Marino 	  l = strlen (namebuf);
707a45ae5f8SJohn Marino 	  namebuf[l] = ',';
708a45ae5f8SJohn Marino 	  memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
709a45ae5f8SJohn Marino 		  MACH_O_NAME_LEN);
710*ef5ccd6cSJohn Marino 	  namebuf[l + 1 + MACH_O_NAME_LEN] = '\0';
711a45ae5f8SJohn Marino 	}
712c50c785cSJohn Marino 
713c50c785cSJohn Marino       simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
714c50c785cSJohn Marino 					 &secoffset, &secsize);
715c50c785cSJohn Marino 
716c50c785cSJohn Marino       if (!(*pfn) (data, name, secoffset, secsize))
717c50c785cSJohn Marino 	{
718c50c785cSJohn Marino 	  *errmsg = NULL;
719c50c785cSJohn Marino 	  *err = 0;
720a45ae5f8SJohn Marino 	  XDELETEVEC (index);
721a45ae5f8SJohn Marino 	  XDELETEVEC (nametab);
722c50c785cSJohn Marino 	  XDELETEVEC (strtab);
723c50c785cSJohn Marino 	  XDELETEVEC (secdata);
724c50c785cSJohn Marino 	  return 0;
725c50c785cSJohn Marino 	}
726c50c785cSJohn Marino     }
727c50c785cSJohn Marino 
728a45ae5f8SJohn Marino   XDELETEVEC (index);
729a45ae5f8SJohn Marino   XDELETEVEC (nametab);
730c50c785cSJohn Marino   XDELETEVEC (strtab);
731c50c785cSJohn Marino   XDELETEVEC (secdata);
732c50c785cSJohn Marino 
733c50c785cSJohn Marino   return 1;
734c50c785cSJohn Marino }
735c50c785cSJohn Marino 
736c50c785cSJohn Marino /* Find all sections in a Mach-O file.  */
737c50c785cSJohn Marino 
738c50c785cSJohn Marino static const char *
simple_object_mach_o_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,int * err)739c50c785cSJohn Marino simple_object_mach_o_find_sections (simple_object_read *sobj,
740c50c785cSJohn Marino 				    int (*pfn) (void *, const char *,
741c50c785cSJohn Marino 						off_t offset, off_t length),
742c50c785cSJohn Marino 				    void *data,
743c50c785cSJohn Marino 				    int *err)
744c50c785cSJohn Marino {
745c50c785cSJohn Marino   struct simple_object_mach_o_read *omr =
746c50c785cSJohn Marino     (struct simple_object_mach_o_read *) sobj->data;
747c50c785cSJohn Marino   off_t offset;
748c50c785cSJohn Marino   size_t seghdrsize;
749c50c785cSJohn Marino   unsigned int (*fetch_32) (const unsigned char *);
750c50c785cSJohn Marino   const char *errmsg;
751c50c785cSJohn Marino   unsigned int i;
752c50c785cSJohn Marino 
753c50c785cSJohn Marino   if (omr->magic == MACH_O_MH_MAGIC)
754c50c785cSJohn Marino     {
755c50c785cSJohn Marino       offset = sizeof (struct mach_o_header_32);
756c50c785cSJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_32);
757c50c785cSJohn Marino     }
758c50c785cSJohn Marino   else
759c50c785cSJohn Marino     {
760c50c785cSJohn Marino       offset = sizeof (struct mach_o_header_64);
761c50c785cSJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_64);
762c50c785cSJohn Marino     }
763c50c785cSJohn Marino 
764c50c785cSJohn Marino   fetch_32 = (omr->is_big_endian
765c50c785cSJohn Marino 	      ? simple_object_fetch_big_32
766c50c785cSJohn Marino 	      : simple_object_fetch_little_32);
767c50c785cSJohn Marino 
768c50c785cSJohn Marino   for (i = 0; i < omr->ncmds; ++i)
769c50c785cSJohn Marino     {
770c50c785cSJohn Marino       unsigned char loadbuf[sizeof (struct mach_o_load_command)];
771c50c785cSJohn Marino       unsigned int cmd;
772c50c785cSJohn Marino       unsigned int cmdsize;
773c50c785cSJohn Marino 
774c50c785cSJohn Marino       if (!simple_object_internal_read (sobj->descriptor,
775c50c785cSJohn Marino 					sobj->offset + offset,
776c50c785cSJohn Marino 					loadbuf,
777c50c785cSJohn Marino 					sizeof (struct mach_o_load_command),
778c50c785cSJohn Marino 					&errmsg, err))
779c50c785cSJohn Marino 	return errmsg;
780c50c785cSJohn Marino 
781c50c785cSJohn Marino       cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
782c50c785cSJohn Marino       cmdsize = (*fetch_32) (loadbuf
783c50c785cSJohn Marino 			     + offsetof (struct mach_o_load_command, cmdsize));
784c50c785cSJohn Marino 
785c50c785cSJohn Marino       if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
786c50c785cSJohn Marino 	{
787c50c785cSJohn Marino 	  unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
788c50c785cSJohn Marino 	  int r;
789c50c785cSJohn Marino 
790c50c785cSJohn Marino 	  if (!simple_object_internal_read (sobj->descriptor,
791c50c785cSJohn Marino 					    sobj->offset + offset,
792c50c785cSJohn Marino 					    segbuf, seghdrsize, &errmsg, err))
793c50c785cSJohn Marino 	    return errmsg;
794c50c785cSJohn Marino 
795c50c785cSJohn Marino 	  r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
796c50c785cSJohn Marino 					    data, &errmsg, err);
797c50c785cSJohn Marino 	  if (!r)
798c50c785cSJohn Marino 	    return errmsg;
799c50c785cSJohn Marino 	}
800c50c785cSJohn Marino 
801c50c785cSJohn Marino       offset += cmdsize;
802c50c785cSJohn Marino     }
803c50c785cSJohn Marino 
804c50c785cSJohn Marino   return NULL;
805c50c785cSJohn Marino }
806c50c785cSJohn Marino 
807c50c785cSJohn Marino /* Fetch the attributes for an simple_object_read.  */
808c50c785cSJohn Marino 
809c50c785cSJohn Marino static void *
simple_object_mach_o_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)810c50c785cSJohn Marino simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
811c50c785cSJohn Marino 				       const char **errmsg ATTRIBUTE_UNUSED,
812c50c785cSJohn Marino 				       int *err ATTRIBUTE_UNUSED)
813c50c785cSJohn Marino {
814c50c785cSJohn Marino   struct simple_object_mach_o_read *omr =
815c50c785cSJohn Marino     (struct simple_object_mach_o_read *) sobj->data;
816c50c785cSJohn Marino   struct simple_object_mach_o_attributes *ret;
817c50c785cSJohn Marino 
818c50c785cSJohn Marino   ret = XNEW (struct simple_object_mach_o_attributes);
819c50c785cSJohn Marino   ret->magic = omr->magic;
820c50c785cSJohn Marino   ret->is_big_endian = omr->is_big_endian;
821c50c785cSJohn Marino   ret->cputype = omr->cputype;
822c50c785cSJohn Marino   ret->cpusubtype = omr->cpusubtype;
823c50c785cSJohn Marino   ret->flags = omr->flags;
824c50c785cSJohn Marino   ret->reserved = omr->reserved;
825c50c785cSJohn Marino   return ret;
826c50c785cSJohn Marino }
827c50c785cSJohn Marino 
828c50c785cSJohn Marino /* Release the private data for an simple_object_read.  */
829c50c785cSJohn Marino 
830c50c785cSJohn Marino static void
simple_object_mach_o_release_read(void * data)831c50c785cSJohn Marino simple_object_mach_o_release_read (void *data)
832c50c785cSJohn Marino {
833c50c785cSJohn Marino   struct simple_object_mach_o_read *omr =
834c50c785cSJohn Marino     (struct simple_object_mach_o_read *) data;
835c50c785cSJohn Marino 
836c50c785cSJohn Marino   free (omr->segment_name);
837c50c785cSJohn Marino   XDELETE (omr);
838c50c785cSJohn Marino }
839c50c785cSJohn Marino 
840c50c785cSJohn Marino /* Compare two attributes structures.  */
841c50c785cSJohn Marino 
842c50c785cSJohn Marino static const char *
simple_object_mach_o_attributes_merge(void * todata,void * fromdata,int * err)843c50c785cSJohn Marino simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
844c50c785cSJohn Marino {
845c50c785cSJohn Marino   struct simple_object_mach_o_attributes *to =
846c50c785cSJohn Marino     (struct simple_object_mach_o_attributes *) todata;
847c50c785cSJohn Marino   struct simple_object_mach_o_attributes *from =
848c50c785cSJohn Marino     (struct simple_object_mach_o_attributes *) fromdata;
849c50c785cSJohn Marino 
850c50c785cSJohn Marino   if (to->magic != from->magic
851c50c785cSJohn Marino       || to->is_big_endian != from->is_big_endian
852c50c785cSJohn Marino       || to->cputype != from->cputype)
853c50c785cSJohn Marino     {
854c50c785cSJohn Marino       *err = 0;
855c50c785cSJohn Marino       return "Mach-O object format mismatch";
856c50c785cSJohn Marino     }
857c50c785cSJohn Marino   return NULL;
858c50c785cSJohn Marino }
859c50c785cSJohn Marino 
860c50c785cSJohn Marino /* Release the private data for an attributes structure.  */
861c50c785cSJohn Marino 
862c50c785cSJohn Marino static void
simple_object_mach_o_release_attributes(void * data)863c50c785cSJohn Marino simple_object_mach_o_release_attributes (void *data)
864c50c785cSJohn Marino {
865c50c785cSJohn Marino   XDELETE (data);
866c50c785cSJohn Marino }
867c50c785cSJohn Marino 
868c50c785cSJohn Marino /* Prepare to write out a file.  */
869c50c785cSJohn Marino 
870c50c785cSJohn Marino static void *
simple_object_mach_o_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)871c50c785cSJohn Marino simple_object_mach_o_start_write (void *attributes_data,
872c50c785cSJohn Marino 				  const char **errmsg ATTRIBUTE_UNUSED,
873c50c785cSJohn Marino 				  int *err ATTRIBUTE_UNUSED)
874c50c785cSJohn Marino {
875c50c785cSJohn Marino   struct simple_object_mach_o_attributes *attrs =
876c50c785cSJohn Marino     (struct simple_object_mach_o_attributes *) attributes_data;
877c50c785cSJohn Marino   struct simple_object_mach_o_attributes *ret;
878c50c785cSJohn Marino 
879c50c785cSJohn Marino   /* We're just going to record the attributes, but we need to make a
880c50c785cSJohn Marino      copy because the user may delete them.  */
881c50c785cSJohn Marino   ret = XNEW (struct simple_object_mach_o_attributes);
882c50c785cSJohn Marino   *ret = *attrs;
883c50c785cSJohn Marino   return ret;
884c50c785cSJohn Marino }
885c50c785cSJohn Marino 
886c50c785cSJohn Marino /* Write out the header of a Mach-O file.  */
887c50c785cSJohn Marino 
888c50c785cSJohn Marino static int
simple_object_mach_o_write_header(simple_object_write * sobj,int descriptor,size_t nsects,const char ** errmsg,int * err)889c50c785cSJohn Marino simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
890c50c785cSJohn Marino 				   size_t nsects, const char **errmsg,
891c50c785cSJohn Marino 				   int *err)
892c50c785cSJohn Marino {
893c50c785cSJohn Marino   struct simple_object_mach_o_attributes *attrs =
894c50c785cSJohn Marino     (struct simple_object_mach_o_attributes *) sobj->data;
895c50c785cSJohn Marino   void (*set_32) (unsigned char *, unsigned int);
896c50c785cSJohn Marino   unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
897c50c785cSJohn Marino   unsigned char *hdr;
898c50c785cSJohn Marino   size_t wrsize;
899c50c785cSJohn Marino 
900c50c785cSJohn Marino   set_32 = (attrs->is_big_endian
901c50c785cSJohn Marino 	    ? simple_object_set_big_32
902c50c785cSJohn Marino 	    : simple_object_set_little_32);
903c50c785cSJohn Marino 
904c50c785cSJohn Marino   memset (hdrbuf, 0, sizeof hdrbuf);
905c50c785cSJohn Marino 
906c50c785cSJohn Marino   /* The 32-bit and 64-bit headers start out the same.  */
907c50c785cSJohn Marino 
908c50c785cSJohn Marino   hdr = &hdrbuf[0];
909c50c785cSJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
910c50c785cSJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
911c50c785cSJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
912c50c785cSJohn Marino 	  attrs->cpusubtype);
913c50c785cSJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
914c50c785cSJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
915c50c785cSJohn Marino   set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
916c50c785cSJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
917c50c785cSJohn Marino     {
918c50c785cSJohn Marino       wrsize = sizeof (struct mach_o_header_32);
919c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
920c50c785cSJohn Marino 	      (sizeof (struct mach_o_segment_command_32)
921c50c785cSJohn Marino 	       + nsects * sizeof (struct mach_o_section_32)));
922c50c785cSJohn Marino     }
923c50c785cSJohn Marino   else
924c50c785cSJohn Marino     {
925c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
926c50c785cSJohn Marino 	      (sizeof (struct mach_o_segment_command_64)
927c50c785cSJohn Marino 	       + nsects * sizeof (struct mach_o_section_64)));
928c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
929c50c785cSJohn Marino 	      attrs->reserved);
930c50c785cSJohn Marino       wrsize = sizeof (struct mach_o_header_64);
931c50c785cSJohn Marino     }
932c50c785cSJohn Marino 
933c50c785cSJohn Marino   return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
934c50c785cSJohn Marino 				       errmsg, err);
935c50c785cSJohn Marino }
936c50c785cSJohn Marino 
937c50c785cSJohn Marino /* Write a Mach-O section header.  */
938c50c785cSJohn Marino 
939c50c785cSJohn Marino static int
simple_object_mach_o_write_section_header(simple_object_write * sobj,int descriptor,size_t sechdr_offset,const char * name,const char * segn,size_t secaddr,size_t secsize,size_t offset,unsigned int align,const char ** errmsg,int * err)940c50c785cSJohn Marino simple_object_mach_o_write_section_header (simple_object_write *sobj,
941c50c785cSJohn Marino 					   int descriptor,
942c50c785cSJohn Marino 					   size_t sechdr_offset,
943a45ae5f8SJohn Marino 					   const char *name, const char *segn,
944a45ae5f8SJohn Marino 					   size_t secaddr, size_t secsize,
945a45ae5f8SJohn Marino 					   size_t offset, unsigned int align,
946c50c785cSJohn Marino 					   const char **errmsg, int *err)
947c50c785cSJohn Marino {
948c50c785cSJohn Marino   struct simple_object_mach_o_attributes *attrs =
949c50c785cSJohn Marino     (struct simple_object_mach_o_attributes *) sobj->data;
950c50c785cSJohn Marino   void (*set_32) (unsigned char *, unsigned int);
951c50c785cSJohn Marino   unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
952c50c785cSJohn Marino   unsigned char *hdr;
953c50c785cSJohn Marino   size_t sechdrsize;
954c50c785cSJohn Marino 
955c50c785cSJohn Marino   set_32 = (attrs->is_big_endian
956c50c785cSJohn Marino 	    ? simple_object_set_big_32
957c50c785cSJohn Marino 	    : simple_object_set_little_32);
958c50c785cSJohn Marino 
959c50c785cSJohn Marino   memset (hdrbuf, 0, sizeof hdrbuf);
960c50c785cSJohn Marino 
961c50c785cSJohn Marino   hdr = &hdrbuf[0];
962c50c785cSJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
963c50c785cSJohn Marino     {
964c50c785cSJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
965c50c785cSJohn Marino 	       name, MACH_O_NAME_LEN);
966c50c785cSJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
967a45ae5f8SJohn Marino 	       segn, MACH_O_NAME_LEN);
968c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
969c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
970c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
971c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
972c50c785cSJohn Marino       /* reloff left as zero.  */
973c50c785cSJohn Marino       /* nreloc left as zero.  */
974c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_32, flags),
975c50c785cSJohn Marino 	      MACH_O_S_ATTR_DEBUG);
976c50c785cSJohn Marino       /* reserved1 left as zero.  */
977c50c785cSJohn Marino       /* reserved2 left as zero.  */
978c50c785cSJohn Marino       sechdrsize = sizeof (struct mach_o_section_32);
979c50c785cSJohn Marino     }
980c50c785cSJohn Marino   else
981c50c785cSJohn Marino     {
982c50c785cSJohn Marino #ifdef UNSIGNED_64BIT_TYPE
983c50c785cSJohn Marino       void (*set_64) (unsigned char *, ulong_type);
984c50c785cSJohn Marino 
985c50c785cSJohn Marino       set_64 = (attrs->is_big_endian
986c50c785cSJohn Marino 		? simple_object_set_big_64
987c50c785cSJohn Marino 		: simple_object_set_little_64);
988c50c785cSJohn Marino 
989c50c785cSJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
990c50c785cSJohn Marino 	       name, MACH_O_NAME_LEN);
991c50c785cSJohn Marino       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
992a45ae5f8SJohn Marino 	       segn, MACH_O_NAME_LEN);
993c50c785cSJohn Marino       set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
994c50c785cSJohn Marino       set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
995c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
996c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
997c50c785cSJohn Marino       /* reloff left as zero.  */
998c50c785cSJohn Marino       /* nreloc left as zero.  */
999c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_section_64, flags),
1000c50c785cSJohn Marino 	      MACH_O_S_ATTR_DEBUG);
1001c50c785cSJohn Marino       /* reserved1 left as zero.  */
1002c50c785cSJohn Marino       /* reserved2 left as zero.  */
1003c50c785cSJohn Marino       /* reserved3 left as zero.  */
1004c50c785cSJohn Marino #endif
1005c50c785cSJohn Marino       sechdrsize = sizeof (struct mach_o_section_64);
1006c50c785cSJohn Marino     }
1007c50c785cSJohn Marino 
1008c50c785cSJohn Marino   return simple_object_internal_write (descriptor, sechdr_offset, hdr,
1009c50c785cSJohn Marino 				       sechdrsize, errmsg, err);
1010c50c785cSJohn Marino }
1011c50c785cSJohn Marino 
1012a45ae5f8SJohn Marino /* Write out the single (anonymous) segment containing the sections of a Mach-O
1013a45ae5f8SJohn Marino    Object file.
1014a45ae5f8SJohn Marino 
1015a45ae5f8SJohn Marino    As a GNU extension to mach-o, when the caller specifies a segment name in
1016a45ae5f8SJohn Marino    sobj->segment_name, all the sections passed will be output under a single
1017a45ae5f8SJohn Marino    mach-o section header.  The caller's sections are indexed within this
1018a45ae5f8SJohn Marino    'wrapper' section by a table stored in a second mach-o section.  Finally,
1019a45ae5f8SJohn Marino    arbitrary length section names are permitted by the extension and these are
1020a45ae5f8SJohn Marino    stored in a table in a third mach-o section.
1021a45ae5f8SJohn Marino 
1022a45ae5f8SJohn Marino    Note that this is only likely to make any sense for the __GNU_LTO segment
1023a45ae5f8SJohn Marino    at present.
1024a45ae5f8SJohn Marino 
1025a45ae5f8SJohn Marino    If the wrapper extension is not in force, we assume that the section name
1026a45ae5f8SJohn Marino    is in the form __SEGMENT_NAME,__section_name as per Mach-O asm.  */
1027c50c785cSJohn Marino 
1028c50c785cSJohn Marino static int
simple_object_mach_o_write_segment(simple_object_write * sobj,int descriptor,size_t * nsects,const char ** errmsg,int * err)1029c50c785cSJohn Marino simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
1030a45ae5f8SJohn Marino 				    size_t *nsects, const char **errmsg,
1031c50c785cSJohn Marino 				    int *err)
1032c50c785cSJohn Marino {
1033c50c785cSJohn Marino   struct simple_object_mach_o_attributes *attrs =
1034c50c785cSJohn Marino     (struct simple_object_mach_o_attributes *) sobj->data;
1035c50c785cSJohn Marino   void (*set_32) (unsigned char *, unsigned int);
1036c50c785cSJohn Marino   size_t hdrsize;
1037c50c785cSJohn Marino   size_t seghdrsize;
1038c50c785cSJohn Marino   size_t sechdrsize;
1039c50c785cSJohn Marino   size_t cmdsize;
1040c50c785cSJohn Marino   size_t offset;
1041c50c785cSJohn Marino   size_t sechdr_offset;
1042c50c785cSJohn Marino   size_t secaddr;
1043c50c785cSJohn Marino   unsigned int name_offset;
1044c50c785cSJohn Marino   simple_object_write_section *section;
1045c50c785cSJohn Marino   unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
1046c50c785cSJohn Marino   unsigned char *hdr;
1047a45ae5f8SJohn Marino   size_t nsects_in;
1048a45ae5f8SJohn Marino   unsigned int *index;
1049a45ae5f8SJohn Marino   char *snames;
1050a45ae5f8SJohn Marino   unsigned int sect;
1051c50c785cSJohn Marino 
1052c50c785cSJohn Marino   set_32 = (attrs->is_big_endian
1053c50c785cSJohn Marino 	    ? simple_object_set_big_32
1054c50c785cSJohn Marino 	    : simple_object_set_little_32);
1055c50c785cSJohn Marino 
1056c50c785cSJohn Marino   /* Write out the sections first.  */
1057c50c785cSJohn Marino 
1058c50c785cSJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
1059c50c785cSJohn Marino     {
1060c50c785cSJohn Marino       hdrsize = sizeof (struct mach_o_header_32);
1061c50c785cSJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_32);
1062c50c785cSJohn Marino       sechdrsize = sizeof (struct mach_o_section_32);
1063c50c785cSJohn Marino     }
1064c50c785cSJohn Marino   else
1065c50c785cSJohn Marino     {
1066c50c785cSJohn Marino       hdrsize = sizeof (struct mach_o_header_64);
1067c50c785cSJohn Marino       seghdrsize = sizeof (struct mach_o_segment_command_64);
1068c50c785cSJohn Marino       sechdrsize = sizeof (struct mach_o_section_64);
1069c50c785cSJohn Marino     }
1070c50c785cSJohn Marino 
1071c50c785cSJohn Marino   name_offset = 0;
1072a45ae5f8SJohn Marino   *nsects = nsects_in = 0;
1073a45ae5f8SJohn Marino 
1074a45ae5f8SJohn Marino   /* Count the number of sections we start with.  */
1075c50c785cSJohn Marino 
1076c50c785cSJohn Marino   for (section = sobj->sections; section != NULL; section = section->next)
1077a45ae5f8SJohn Marino     nsects_in++;
1078a45ae5f8SJohn Marino 
1079a45ae5f8SJohn Marino   if (sobj->segment_name != NULL)
1080a45ae5f8SJohn Marino     {
1081a45ae5f8SJohn Marino       /* We will only write 3 sections: wrapped data, index and names.  */
1082a45ae5f8SJohn Marino 
1083a45ae5f8SJohn Marino       *nsects = 3;
1084a45ae5f8SJohn Marino 
1085a45ae5f8SJohn Marino       /* The index has four entries per wrapped section:
1086a45ae5f8SJohn Marino 	   Section Offset, length,  Name offset, length.
1087a45ae5f8SJohn Marino 	 Where the offsets are based at the start of the wrapper and name
1088a45ae5f8SJohn Marino 	 sections respectively.
1089a45ae5f8SJohn Marino 	 The values are stored as 32 bit int for both 32 and 64 bit mach-o
1090a45ae5f8SJohn Marino 	 since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
1091a45ae5f8SJohn Marino 	 other constraints.  */
1092a45ae5f8SJohn Marino 
1093a45ae5f8SJohn Marino       index = XNEWVEC (unsigned int, nsects_in * 4);
1094a45ae5f8SJohn Marino 
1095a45ae5f8SJohn Marino       /* We now need to figure out the size of the names section.  This just
1096a45ae5f8SJohn Marino 	 stores the names as null-terminated c strings, packed without any
1097a45ae5f8SJohn Marino 	 alignment padding.  */
1098a45ae5f8SJohn Marino 
1099a45ae5f8SJohn Marino       for (section = sobj->sections, sect = 0; section != NULL;
1100a45ae5f8SJohn Marino 	   section = section->next, sect++)
1101a45ae5f8SJohn Marino 	{
1102a45ae5f8SJohn Marino 	  index[sect*4+2] = name_offset;
1103a45ae5f8SJohn Marino 	  index[sect*4+3] = strlen (section->name) + 1;
1104a45ae5f8SJohn Marino 	  name_offset += strlen (section->name) + 1;
1105a45ae5f8SJohn Marino 	}
1106a45ae5f8SJohn Marino       snames = XNEWVEC (char, name_offset);
1107a45ae5f8SJohn Marino     }
1108a45ae5f8SJohn Marino   else
1109a45ae5f8SJohn Marino     {
1110a45ae5f8SJohn Marino       *nsects = nsects_in;
1111a45ae5f8SJohn Marino       index = NULL;
1112a45ae5f8SJohn Marino       snames = NULL;
1113a45ae5f8SJohn Marino     }
1114a45ae5f8SJohn Marino 
1115a45ae5f8SJohn Marino   sechdr_offset = hdrsize + seghdrsize;
1116a45ae5f8SJohn Marino   cmdsize = seghdrsize + *nsects * sechdrsize;
1117a45ae5f8SJohn Marino   offset = hdrsize + cmdsize;
1118a45ae5f8SJohn Marino   secaddr = 0;
1119a45ae5f8SJohn Marino 
1120a45ae5f8SJohn Marino   for (section = sobj->sections, sect = 0;
1121a45ae5f8SJohn Marino        section != NULL; section = section->next, sect++)
1122c50c785cSJohn Marino     {
1123c50c785cSJohn Marino       size_t mask;
1124c50c785cSJohn Marino       size_t new_offset;
1125c50c785cSJohn Marino       size_t secsize;
1126c50c785cSJohn Marino       struct simple_object_write_section_buffer *buffer;
1127c50c785cSJohn Marino 
1128c50c785cSJohn Marino       mask = (1U << section->align) - 1;
1129c50c785cSJohn Marino       new_offset = offset + mask;
1130c50c785cSJohn Marino       new_offset &= ~ mask;
1131c50c785cSJohn Marino       while (new_offset > offset)
1132c50c785cSJohn Marino 	{
1133c50c785cSJohn Marino 	  unsigned char zeroes[16];
1134c50c785cSJohn Marino 	  size_t write;
1135c50c785cSJohn Marino 
1136c50c785cSJohn Marino 	  memset (zeroes, 0, sizeof zeroes);
1137c50c785cSJohn Marino 	  write = new_offset - offset;
1138c50c785cSJohn Marino 	  if (write > sizeof zeroes)
1139c50c785cSJohn Marino 	    write = sizeof zeroes;
1140c50c785cSJohn Marino 	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
1141c50c785cSJohn Marino 					     errmsg, err))
1142c50c785cSJohn Marino 	    return 0;
1143c50c785cSJohn Marino 	  offset += write;
1144c50c785cSJohn Marino 	}
1145c50c785cSJohn Marino 
1146c50c785cSJohn Marino       secsize = 0;
1147c50c785cSJohn Marino       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1148c50c785cSJohn Marino 	{
1149c50c785cSJohn Marino 	  if (!simple_object_internal_write (descriptor, offset + secsize,
1150c50c785cSJohn Marino 					     ((const unsigned char *)
1151c50c785cSJohn Marino 					      buffer->buffer),
1152c50c785cSJohn Marino 					     buffer->size, errmsg, err))
1153c50c785cSJohn Marino 	    return 0;
1154c50c785cSJohn Marino 	  secsize += buffer->size;
1155c50c785cSJohn Marino 	}
1156c50c785cSJohn Marino 
1157a45ae5f8SJohn Marino       if (sobj->segment_name != NULL)
1158a45ae5f8SJohn Marino 	{
1159a45ae5f8SJohn Marino 	  index[sect*4+0] = (unsigned int) offset;
1160a45ae5f8SJohn Marino 	  index[sect*4+1] = secsize;
1161a45ae5f8SJohn Marino 	  /* Stash the section name in our table.  */
1162a45ae5f8SJohn Marino 	  memcpy (snames + index[sect * 4 + 2], section->name,
1163a45ae5f8SJohn Marino 		  index[sect * 4 + 3]);
1164c50c785cSJohn Marino 	}
1165a45ae5f8SJohn Marino       else
1166a45ae5f8SJohn Marino 	{
1167a45ae5f8SJohn Marino 	  char namebuf[MACH_O_NAME_LEN + 1];
1168a45ae5f8SJohn Marino 	  char segnbuf[MACH_O_NAME_LEN + 1];
1169a45ae5f8SJohn Marino 	  char *comma;
1170c50c785cSJohn Marino 
1171a45ae5f8SJohn Marino 	  /* Try to extract segment,section from the input name.  */
1172a45ae5f8SJohn Marino 
1173a45ae5f8SJohn Marino 	  memset (namebuf, 0, sizeof namebuf);
1174a45ae5f8SJohn Marino 	  memset (segnbuf, 0, sizeof segnbuf);
1175a45ae5f8SJohn Marino 	  comma = strchr (section->name, ',');
1176a45ae5f8SJohn Marino 	  if (comma != NULL)
1177a45ae5f8SJohn Marino 	    {
1178a45ae5f8SJohn Marino 	      int len = comma - section->name;
1179a45ae5f8SJohn Marino 	      len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
1180a45ae5f8SJohn Marino 	      strncpy (namebuf, section->name, len);
1181a45ae5f8SJohn Marino 	      strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
1182a45ae5f8SJohn Marino 	    }
1183a45ae5f8SJohn Marino 	  else /* just try to copy the name, leave segment blank.  */
1184a45ae5f8SJohn Marino 	    strncpy (namebuf, section->name, MACH_O_NAME_LEN);
1185c50c785cSJohn Marino 
1186c50c785cSJohn Marino 	  if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1187c50c785cSJohn Marino 							  sechdr_offset,
1188a45ae5f8SJohn Marino 							  namebuf, segnbuf,
1189a45ae5f8SJohn Marino 							  secaddr, secsize,
1190a45ae5f8SJohn Marino 							  offset,
1191a45ae5f8SJohn Marino 							  section->align,
1192a45ae5f8SJohn Marino 							  errmsg, err))
1193a45ae5f8SJohn Marino 	    return 0;
1194a45ae5f8SJohn Marino 	  sechdr_offset += sechdrsize;
1195a45ae5f8SJohn Marino 	}
1196a45ae5f8SJohn Marino 
1197a45ae5f8SJohn Marino       offset += secsize;
1198a45ae5f8SJohn Marino       secaddr += secsize;
1199a45ae5f8SJohn Marino     }
1200a45ae5f8SJohn Marino 
1201a45ae5f8SJohn Marino   if (sobj->segment_name != NULL)
1202a45ae5f8SJohn Marino     {
1203a45ae5f8SJohn Marino       size_t secsize;
1204a45ae5f8SJohn Marino       unsigned int i;
1205a45ae5f8SJohn Marino 
1206a45ae5f8SJohn Marino       /* Write the section header for the wrapper.  */
1207a45ae5f8SJohn Marino       /* Account for any initial aligment - which becomes the alignment for this
1208a45ae5f8SJohn Marino 	 created section.  */
1209a45ae5f8SJohn Marino 
1210a45ae5f8SJohn Marino       secsize = (offset - index[0]);
1211a45ae5f8SJohn Marino       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1212a45ae5f8SJohn Marino 						      sechdr_offset,
1213a45ae5f8SJohn Marino 						      GNU_WRAPPER_SECTS,
1214a45ae5f8SJohn Marino 						      sobj->segment_name,
1215a45ae5f8SJohn Marino 						      0 /*secaddr*/,
1216a45ae5f8SJohn Marino 						      secsize, index[0],
1217a45ae5f8SJohn Marino 						      sobj->sections->align,
1218c50c785cSJohn Marino 						      errmsg, err))
1219c50c785cSJohn Marino 	return 0;
1220c50c785cSJohn Marino 
1221a45ae5f8SJohn Marino       /* Subtract the wrapper section start from the begining of each sub
1222a45ae5f8SJohn Marino 	 section.  */
1223c50c785cSJohn Marino 
1224a45ae5f8SJohn Marino       for (i = 1; i < nsects_in; ++i)
1225a45ae5f8SJohn Marino 	index[4 * i] -= index[0];
1226a45ae5f8SJohn Marino       index[0] = 0;
1227a45ae5f8SJohn Marino 
1228a45ae5f8SJohn Marino       sechdr_offset += sechdrsize;
1229a45ae5f8SJohn Marino 
1230a45ae5f8SJohn Marino       /* Write out the section names.
1231a45ae5f8SJohn Marino 	 ... the header ...
1232a45ae5f8SJohn Marino 	 name_offset contains the length of the section.  It is not aligned.  */
1233a45ae5f8SJohn Marino 
1234a45ae5f8SJohn Marino       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1235a45ae5f8SJohn Marino 						      sechdr_offset,
1236a45ae5f8SJohn Marino 						      GNU_WRAPPER_NAMES,
1237a45ae5f8SJohn Marino 						      sobj->segment_name,
1238a45ae5f8SJohn Marino 						      0 /*secaddr*/,
1239a45ae5f8SJohn Marino 						      name_offset,
1240a45ae5f8SJohn Marino 						      offset,
1241a45ae5f8SJohn Marino 						      0, errmsg, err))
1242c50c785cSJohn Marino 	return 0;
1243a45ae5f8SJohn Marino 
1244a45ae5f8SJohn Marino       /* ... and the content.. */
1245a45ae5f8SJohn Marino       if (!simple_object_internal_write (descriptor, offset,
1246a45ae5f8SJohn Marino 					 (const unsigned char *) snames,
1247a45ae5f8SJohn Marino 					 name_offset, errmsg, err))
1248a45ae5f8SJohn Marino 	return 0;
1249a45ae5f8SJohn Marino 
1250a45ae5f8SJohn Marino       sechdr_offset += sechdrsize;
1251a45ae5f8SJohn Marino       secaddr += name_offset;
1252a45ae5f8SJohn Marino       offset += name_offset;
1253a45ae5f8SJohn Marino 
1254a45ae5f8SJohn Marino       /* Now do the index, we'll align this to 4 bytes although the read code
1255a45ae5f8SJohn Marino 	 will handle unaligned.  */
1256a45ae5f8SJohn Marino 
1257a45ae5f8SJohn Marino       offset += 3;
1258a45ae5f8SJohn Marino       offset &= ~0x03;
1259a45ae5f8SJohn Marino       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1260a45ae5f8SJohn Marino 						      sechdr_offset,
1261a45ae5f8SJohn Marino 						      GNU_WRAPPER_INDEX,
1262a45ae5f8SJohn Marino 						      sobj->segment_name,
1263a45ae5f8SJohn Marino 						      0 /*secaddr*/,
1264a45ae5f8SJohn Marino 						      nsects_in * 16,
1265a45ae5f8SJohn Marino 						      offset,
1266a45ae5f8SJohn Marino 						      2, errmsg, err))
1267a45ae5f8SJohn Marino 	return 0;
1268a45ae5f8SJohn Marino 
1269a45ae5f8SJohn Marino       /* ... and the content.. */
1270a45ae5f8SJohn Marino       if (!simple_object_internal_write (descriptor, offset,
1271a45ae5f8SJohn Marino 					 (const unsigned char *) index,
1272a45ae5f8SJohn Marino 					 nsects_in*16, errmsg, err))
1273a45ae5f8SJohn Marino 	return 0;
1274a45ae5f8SJohn Marino 
1275a45ae5f8SJohn Marino       XDELETEVEC (index);
1276a45ae5f8SJohn Marino       XDELETEVEC (snames);
1277c50c785cSJohn Marino     }
1278c50c785cSJohn Marino 
1279c50c785cSJohn Marino   /* Write out the segment header.  */
1280c50c785cSJohn Marino 
1281c50c785cSJohn Marino   memset (hdrbuf, 0, sizeof hdrbuf);
1282c50c785cSJohn Marino 
1283c50c785cSJohn Marino   hdr = &hdrbuf[0];
1284c50c785cSJohn Marino   if (attrs->magic == MACH_O_MH_MAGIC)
1285c50c785cSJohn Marino     {
1286c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
1287c50c785cSJohn Marino 	      MACH_O_LC_SEGMENT);
1288c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
1289c50c785cSJohn Marino 	      cmdsize);
1290a45ae5f8SJohn Marino      /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1291a45ae5f8SJohn Marino 	 is left empty.  */
1292c50c785cSJohn Marino       /* vmaddr left as zero.  */
1293c50c785cSJohn Marino       /* vmsize left as zero.  */
1294c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
1295c50c785cSJohn Marino 	      hdrsize + cmdsize);
1296c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
1297c50c785cSJohn Marino 	      offset - (hdrsize + cmdsize));
1298c50c785cSJohn Marino       /* maxprot left as zero.  */
1299c50c785cSJohn Marino       /* initprot left as zero.  */
1300c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
1301a45ae5f8SJohn Marino 	      *nsects);
1302c50c785cSJohn Marino       /* flags left as zero.  */
1303c50c785cSJohn Marino     }
1304c50c785cSJohn Marino   else
1305c50c785cSJohn Marino     {
1306c50c785cSJohn Marino #ifdef UNSIGNED_64BIT_TYPE
1307c50c785cSJohn Marino       void (*set_64) (unsigned char *, ulong_type);
1308c50c785cSJohn Marino 
1309c50c785cSJohn Marino       set_64 = (attrs->is_big_endian
1310c50c785cSJohn Marino 		? simple_object_set_big_64
1311c50c785cSJohn Marino 		: simple_object_set_little_64);
1312c50c785cSJohn Marino 
1313c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
1314c50c785cSJohn Marino 	      MACH_O_LC_SEGMENT);
1315c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
1316c50c785cSJohn Marino 	      cmdsize);
1317a45ae5f8SJohn Marino       /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1318a45ae5f8SJohn Marino 	 is left empty.  */
1319c50c785cSJohn Marino       /* vmaddr left as zero.  */
1320c50c785cSJohn Marino       /* vmsize left as zero.  */
1321c50c785cSJohn Marino       set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
1322c50c785cSJohn Marino 	      hdrsize + cmdsize);
1323c50c785cSJohn Marino       set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
1324c50c785cSJohn Marino 	      offset - (hdrsize + cmdsize));
1325c50c785cSJohn Marino       /* maxprot left as zero.  */
1326c50c785cSJohn Marino       /* initprot left as zero.  */
1327c50c785cSJohn Marino       set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
1328a45ae5f8SJohn Marino 	      *nsects);
1329c50c785cSJohn Marino       /* flags left as zero.  */
1330c50c785cSJohn Marino #endif
1331c50c785cSJohn Marino     }
1332c50c785cSJohn Marino 
1333c50c785cSJohn Marino   return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
1334c50c785cSJohn Marino 				       errmsg, err);
1335c50c785cSJohn Marino }
1336c50c785cSJohn Marino 
1337c50c785cSJohn Marino /* Write out a complete Mach-O file.  */
1338c50c785cSJohn Marino 
1339c50c785cSJohn Marino static const char *
simple_object_mach_o_write_to_file(simple_object_write * sobj,int descriptor,int * err)1340c50c785cSJohn Marino simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
1341c50c785cSJohn Marino 				    int *err)
1342c50c785cSJohn Marino {
1343a45ae5f8SJohn Marino   size_t nsects = 0;
1344c50c785cSJohn Marino   const char *errmsg;
1345c50c785cSJohn Marino 
1346a45ae5f8SJohn Marino   if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
1347c50c785cSJohn Marino 					   &errmsg, err))
1348c50c785cSJohn Marino     return errmsg;
1349c50c785cSJohn Marino 
1350a45ae5f8SJohn Marino   if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
1351c50c785cSJohn Marino 					  &errmsg, err))
1352c50c785cSJohn Marino     return errmsg;
1353c50c785cSJohn Marino 
1354c50c785cSJohn Marino   return NULL;
1355c50c785cSJohn Marino }
1356c50c785cSJohn Marino 
1357c50c785cSJohn Marino /* Release the private data for an simple_object_write structure.  */
1358c50c785cSJohn Marino 
1359c50c785cSJohn Marino static void
simple_object_mach_o_release_write(void * data)1360c50c785cSJohn Marino simple_object_mach_o_release_write (void *data)
1361c50c785cSJohn Marino {
1362c50c785cSJohn Marino   XDELETE (data);
1363c50c785cSJohn Marino }
1364c50c785cSJohn Marino 
1365c50c785cSJohn Marino /* The Mach-O functions.  */
1366c50c785cSJohn Marino 
1367c50c785cSJohn Marino const struct simple_object_functions simple_object_mach_o_functions =
1368c50c785cSJohn Marino {
1369c50c785cSJohn Marino   simple_object_mach_o_match,
1370c50c785cSJohn Marino   simple_object_mach_o_find_sections,
1371c50c785cSJohn Marino   simple_object_mach_o_fetch_attributes,
1372c50c785cSJohn Marino   simple_object_mach_o_release_read,
1373c50c785cSJohn Marino   simple_object_mach_o_attributes_merge,
1374c50c785cSJohn Marino   simple_object_mach_o_release_attributes,
1375c50c785cSJohn Marino   simple_object_mach_o_start_write,
1376c50c785cSJohn Marino   simple_object_mach_o_write_to_file,
1377c50c785cSJohn Marino   simple_object_mach_o_release_write
1378c50c785cSJohn Marino };
1379