Integrate cctools-822 changes
[striptease.git] / libstuff / breakout.c
blob50fec73e51384030170d9273aedb2e485759014d
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #ifndef RLD
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "stuff/ofile.h"
28 #include "stuff/breakout.h"
29 #include "stuff/allocate.h"
30 #include "stuff/errors.h"
31 #include "stuff/rnd.h"
32 #include "stuff/crc32.h"
34 static void breakout_internal(
35 char *filename,
36 struct arch **archs,
37 uint32_t *narchs,
38 enum bool calculate_input_prebind_cksum,
39 struct ofile *ofile);
40 static void breakout_loop_through_archive(
41 char *filename,
42 struct arch *arch,
43 struct ofile *ofile);
44 static void cksum_object(
45 struct arch *arch,
46 enum bool calculate_input_prebind_cksum);
47 static struct arch *new_arch(
48 struct arch **archs,
49 uint32_t *narchs);
50 static struct member *new_member(
51 struct arch *arch);
53 __private_extern__
54 struct ofile *
55 breakout_mem(
56 void *membuf,
57 uint32_t length,
58 char *filename,
59 struct arch **archs,
60 uint32_t *narchs,
61 enum bool calculate_input_prebind_cksum)
63 struct ofile *ofile;
64 uint32_t previous_errors;
66 *archs = NULL;
67 *narchs = 0;
68 ofile = allocate(sizeof(struct ofile));
71 * If the file_name is NULL, we will use a dummy file name so
72 * that error reporting, etc. works.
74 if(filename == NULL)
75 filename = "(broken out from memory)";
78 * Rely on the ofile_*() routines to do all the checking and only
79 * return valid ofiles files broken out.
81 if(ofile_map_from_memory((char *)membuf, length, filename, 0,NULL, NULL,
82 ofile, FALSE) == FALSE){
83 free(ofile);
84 return(NULL);
87 previous_errors = errors;
88 breakout_internal(filename, archs, narchs,
89 calculate_input_prebind_cksum, ofile);
90 errors += previous_errors;
91 if(errors != 0){
92 free(ofile);
93 return(NULL);
95 return(ofile);
98 __private_extern__
99 struct ofile *
100 breakout(
101 char *filename,
102 struct arch **archs,
103 uint32_t *narchs,
104 enum bool calculate_input_prebind_cksum)
106 struct ofile *ofile;
107 uint32_t previous_errors;
109 *archs = NULL;
110 *narchs = 0;
111 ofile = allocate(sizeof(struct ofile));
113 * Rely on the ofile_*() routines to do all the checking and only
114 * return valid ofiles files broken out.
116 if(ofile_map(filename, NULL, NULL, ofile, FALSE) == FALSE){
117 free(ofile);
118 return(NULL);
121 previous_errors = errors;
122 breakout_internal(filename, archs, narchs,
123 calculate_input_prebind_cksum, ofile);
124 errors += previous_errors;
125 if(errors != 0){
126 free(ofile);
127 return(NULL);
129 return(ofile);
132 static
133 void
134 breakout_internal(
135 char *filename,
136 struct arch **archs,
137 uint32_t *narchs,
138 enum bool calculate_input_prebind_cksum,
139 struct ofile *ofile)
141 struct arch *arch;
143 errors = 0;
144 if(ofile->file_type == OFILE_FAT && errors == 0){
145 /* loop through the fat architectures (can't have zero archs) */
146 (void)ofile_first_arch(ofile);
148 if(errors != 0)
149 break;
150 arch = new_arch(archs, narchs);
151 arch->file_name = savestr(filename);
152 arch->type = ofile->arch_type;
153 arch->fat_arch = ofile->fat_archs + ofile->narch;
154 arch->fat_arch_name = savestr(ofile->arch_flag.name);
156 if(ofile->arch_type == OFILE_ARCHIVE){
157 breakout_loop_through_archive(filename, arch, ofile);
159 else if(ofile->arch_type == OFILE_Mach_O){
160 arch->object = allocate(sizeof(struct object));
161 memset(arch->object, '\0', sizeof(struct object));
162 arch->object->object_addr = ofile->object_addr;
163 arch->object->object_size = ofile->object_size;
164 arch->object->object_byte_sex = ofile->object_byte_sex;
165 arch->object->mh64 = ofile->mh64;
166 arch->object->mh = ofile->mh;
167 arch->object->mh_filetype = ofile->mh_filetype;
168 arch->object->mh_cputype = ofile->mh_cputype;
169 arch->object->mh_cpusubtype = ofile->mh_cpusubtype;
170 arch->object->load_commands = ofile->load_commands;
171 cksum_object(arch, calculate_input_prebind_cksum);
173 else{ /* ofile->arch_type == OFILE_UNKNOWN */
174 arch->unknown_addr = ofile->file_addr +
175 arch->fat_arch->offset;
176 arch->unknown_size = arch->fat_arch->size;
178 }while(ofile_next_arch(ofile) == TRUE);
180 else if(ofile->file_type == OFILE_ARCHIVE && errors == 0){
181 arch = new_arch(archs, narchs);
182 arch->file_name = savestr(filename);
183 arch->type = ofile->file_type;
185 breakout_loop_through_archive(filename, arch, ofile);
187 else if(ofile->file_type == OFILE_Mach_O && errors == 0){
188 arch = new_arch(archs, narchs);
189 arch->file_name = savestr(filename);
190 arch->type = ofile->file_type;
191 arch->object = allocate(sizeof(struct object));
192 memset(arch->object, '\0', sizeof(struct object));
193 arch->object->object_addr = ofile->object_addr;
194 arch->object->object_size = ofile->object_size;
195 arch->object->object_byte_sex = ofile->object_byte_sex;
196 arch->object->mh64 = ofile->mh64;
197 arch->object->mh = ofile->mh;
198 arch->object->mh_filetype = ofile->mh_filetype;
199 arch->object->mh_cputype = ofile->mh_cputype;
200 arch->object->mh_cpusubtype = ofile->mh_cpusubtype;
201 arch->object->load_commands = ofile->load_commands;
202 cksum_object(arch, calculate_input_prebind_cksum);
204 else if(errors == 0){ /* ofile->file_type == OFILE_UNKNOWN */
205 arch = new_arch(archs, narchs);
206 arch->file_name = savestr(filename);
207 arch->type = ofile->file_type;
208 arch->unknown_addr = ofile->file_addr;
209 arch->unknown_size = ofile->file_size;
211 if(errors != 0){
212 free_archs(*archs, *narchs);
213 *archs = NULL;
214 *narchs = 0;
218 static
219 void
220 breakout_loop_through_archive(
221 char *filename,
222 struct arch *arch,
223 struct ofile *ofile)
225 struct member *member;
226 enum bool flag;
227 struct ar_hdr *ar_hdr;
228 uint32_t size, ar_name_size;
229 char ar_name_buf[sizeof(ofile->member_ar_hdr->ar_name) + 1];
230 char ar_size_buf[sizeof(ofile->member_ar_hdr->ar_size) + 1];
232 /* loop through archive (can be empty) */
233 if((flag = ofile_first_member(ofile)) == TRUE && errors == 0){
235 * If the first member is a table of contents then skip
236 * it as it is always rebuilt (so to get the time to
237 * match the modtime so it won't appear out of date).
238 * Also force it to be a long name so members can be 8 byte
239 * aligned.
241 if(ofile->member_ar_hdr != NULL &&
242 strncmp(ofile->member_name, SYMDEF,
243 sizeof(SYMDEF) - 1) == 0){
244 arch->toc_long_name = TRUE;
245 flag = ofile_next_member(ofile);
247 while(flag == TRUE && errors == 0){
248 member = new_member(arch);
249 member->type = ofile->member_type;
250 member->member_name = ofile->member_name;
252 * Determine the size this member will have in the library which
253 * includes the padding as a result of rounding the size of the
254 * member. To get all members on an 8 byte boundary (so that
255 * mapping in object files can be used directly) the size of the
256 * member is CHANGED to reflect this padding. In the UNIX
257 * definition of archives the size of the member is never
258 * changed but the offset to the next member is defined to be
259 * the offset of the previous member plus the size of the
260 * previous member rounded to 2. So to get 8 byte boundaries
261 * without breaking the UNIX definition of archives the size is
262 * changed here. As with the UNIX ar(1) program the padded
263 * bytes will be set to the character '\n'.
265 if(ofile->mh != NULL || ofile->mh64 != NULL)
266 size = rnd(ofile->object_size, 8);
267 else
268 size = rnd(ofile->member_size, 8);
270 * We will force the use of long names so we can make sure the
271 * size of the name and the size of struct ar_hdr are rounded to
272 * 8 bytes. And that rounded size is what will be in the
273 * ar_name with the AR_EFMT1 string. To avoid growing the size
274 * of names first trim the name size before rounding up.
276 member->member_long_name = TRUE;
277 for(ar_name_size = ofile->member_name_size;
278 ar_name_size > 1 ;
279 ar_name_size--){
280 if(ofile->member_name[ar_name_size - 1] != '\0')
281 break;
283 member->member_name_size = ar_name_size;
284 ar_name_size = rnd(ar_name_size, 8) +
285 (rnd(sizeof(struct ar_hdr), 8) -
286 sizeof(struct ar_hdr));
287 size += ar_name_size;
289 * Now with the output sizes of the long member name and rounded
290 * size of the member the offset to this member can be set and
291 * then left incremented for the next member's offset.
293 member->offset = arch->library_size;
294 arch->library_size += sizeof(struct ar_hdr) + size;
296 * Since we are rounding the member size and forcing a the use
297 * of a long name make a new ar_hdr with this information.
298 * Note the code in writeout() will do the padding with '\n'
299 * characters as needed.
301 ar_hdr = allocate(sizeof(struct ar_hdr));
302 *ar_hdr = *(ofile->member_ar_hdr);
303 sprintf(ar_name_buf, "%s%-*lu", AR_EFMT1,
304 (int)(sizeof(ar_hdr->ar_name) - (sizeof(AR_EFMT1) - 1)),
305 (long unsigned int)ar_name_size);
306 memcpy(ar_hdr->ar_name, ar_name_buf,
307 sizeof(ar_hdr->ar_name));
308 sprintf(ar_size_buf, "%-*ld",
309 (int)sizeof(ar_hdr->ar_size), (long unsigned int)size);
310 memcpy(ar_hdr->ar_size, ar_size_buf,
311 sizeof(ar_hdr->ar_size));
313 member->ar_hdr = ar_hdr;
314 member->input_ar_hdr = ofile->member_ar_hdr;
315 member->input_file_name = filename;
317 if(ofile->member_type == OFILE_Mach_O){
318 member->object = allocate(sizeof(struct object));
319 memset(member->object, '\0', sizeof(struct object));
320 member->object->object_addr = ofile->object_addr;
321 member->object->object_size = ofile->object_size;
322 member->object->object_byte_sex = ofile->object_byte_sex;
323 member->object->mh64 = ofile->mh64;
324 member->object->mh = ofile->mh;
325 member->object->mh_filetype = ofile->mh_filetype;
326 member->object->mh_cputype = ofile->mh_cputype;
327 member->object->mh_cpusubtype = ofile->mh_cpusubtype;
328 member->object->load_commands = ofile->load_commands;
330 else{ /* ofile->member_type == OFILE_UNKNOWN */
331 member->unknown_addr = ofile->member_addr;
332 member->unknown_size = ofile->member_size;
334 flag = ofile_next_member(ofile);
340 * cksum_object() is called to set the pointer to the LC_PREBIND_CKSUM load
341 * command in the object struct for the specified arch. If the parameter
342 * calculate_input_prebind_cksum is TRUE then calculate the value
343 * of the check sum for the input object if needed, set that into the
344 * the calculated_input_prebind_cksum field of the object struct for the
345 * specified arch. This is needed for prebound files where the original
346 * checksum (or zero) is recorded in the LC_PREBIND_CKSUM load command.
347 * Only redo_prebinding operations sets the value of the cksum field to
348 * non-zero and only if previously zero. All other operations will set this
349 * field to zero indicating a new original prebound file.
351 static
352 void
353 cksum_object(
354 struct arch *arch,
355 enum bool calculate_input_prebind_cksum)
357 uint32_t i, buf_size, ncmds;
358 struct load_command *lc;
359 enum byte_sex host_byte_sex;
360 char *buf;
362 arch->object->cs = NULL;
363 lc = arch->object->load_commands;
364 if(arch->object->mh != NULL)
365 ncmds = arch->object->mh->ncmds;
366 else
367 ncmds = arch->object->mh64->ncmds;
368 for(i = 0;
369 i < ncmds && arch->object->cs == NULL;
370 i++){
371 if(lc->cmd == LC_PREBIND_CKSUM)
372 arch->object->cs = (struct prebind_cksum_command *)lc;
373 lc = (struct load_command *)((char *)lc + lc->cmdsize);
377 * If we don't want to calculate the input check sum, or there is no
378 * LC_PREBIND_CKSUM load command or there is one and the check sum is
379 * not zero then return.
381 if(calculate_input_prebind_cksum == FALSE ||
382 arch->object->cs == NULL ||
383 arch->object->cs->cksum != 0)
384 return;
387 host_byte_sex = get_host_byte_sex();
388 buf_size = 0;
389 buf = NULL;
390 if(arch->object->object_byte_sex != host_byte_sex){
391 if(arch->object->mh != NULL){
392 buf_size = sizeof(struct mach_header) +
393 arch->object->mh->sizeofcmds;
394 buf = allocate(buf_size);
395 memcpy(buf, arch->object->mh, buf_size);
396 if(swap_object_headers(arch->object->mh,
397 arch->object->load_commands) == FALSE)
398 return;
400 else{
401 buf_size = sizeof(struct mach_header_64) +
402 arch->object->mh64->sizeofcmds;
403 buf = allocate(buf_size);
404 memcpy(buf, arch->object->mh64, buf_size);
405 if(swap_object_headers(arch->object->mh64,
406 arch->object->load_commands) == FALSE)
407 return;
411 arch->object->calculated_input_prebind_cksum =
412 crc32(arch->object->object_addr, arch->object->object_size);
414 if(arch->object->object_byte_sex != host_byte_sex){
415 if(arch->object->mh != NULL)
416 memcpy(arch->object->mh, buf, buf_size);
417 else
418 memcpy(arch->object->mh64, buf, buf_size);
419 free(buf);
423 __private_extern__
424 void
425 free_archs(
426 struct arch *archs,
427 uint32_t narchs)
429 uint32_t i, j;
431 for(i = 0; i < narchs; i++){
432 if(archs[i].type == OFILE_ARCHIVE){
433 for(j = 0; j < archs[i].nmembers; j++){
434 if(archs[i].members[j].type == OFILE_Mach_O){
435 if(archs[i].members[j].object->ld_r_ofile != NULL)
436 ofile_unmap(archs[i].members[j].object->ld_r_ofile);
437 free(archs[i].members[j].object);
440 if(archs[i].nmembers > 0 && archs[i].members != NULL)
441 free(archs[i].members);
443 else if(archs[i].type == OFILE_Mach_O){
444 if(archs[i].object->ld_r_ofile != NULL)
445 ofile_unmap(archs[i].object->ld_r_ofile);
446 free(archs[i].object);
449 if(narchs > 0 && archs != NULL)
450 free(archs);
453 static
454 struct arch *
455 new_arch(
456 struct arch **archs,
457 uint32_t *narchs)
459 struct arch *arch;
461 *archs = reallocate(*archs, (*narchs + 1) * sizeof(struct arch));
462 arch = *archs + *narchs;
463 *narchs = *narchs + 1;
464 memset(arch, '\0', sizeof(struct arch));
465 return(arch);
468 static
469 struct member *
470 new_member(
471 struct arch *arch)
473 struct member *member;
475 arch->members = reallocate(arch->members,
476 (arch->nmembers + 1) * sizeof(struct member));
477 member = arch->members + arch->nmembers;
478 arch->nmembers++;
479 memset(member, '\0', sizeof(struct member));
480 return(member);
482 #endif /* !defined(RLD) */