Integrate cctools-822 changes
[striptease.git] / libstuff / checkout.c
blob5b893c1b7e8b0d3fe0bfffae7cf290765e3c9fbf
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 <string.h>
26 #include "stuff/ofile.h"
27 #include "stuff/breakout.h"
28 #include "stuff/rnd.h"
30 static void check_object(
31 struct arch *arch,
32 struct member *member,
33 struct object *object);
35 static void symbol_string_at_end(
36 struct arch *arch,
37 struct member *member,
38 struct object *object);
40 static void dyld_order(
41 struct arch *arch,
42 struct member *member,
43 struct object *object);
45 static void order_error(
46 struct arch *arch,
47 struct member *member,
48 char *reason);
50 __private_extern__
51 void
52 checkout(
53 struct arch *archs,
54 uint32_t narchs)
56 uint32_t i, j;
58 for(i = 0; i < narchs; i++){
59 if(archs[i].type == OFILE_ARCHIVE){
60 for(j = 0; j < archs[i].nmembers; j++){
61 if(archs[i].members[j].type == OFILE_Mach_O){
62 check_object(archs + i, archs[i].members + j,
63 archs[i].members[j].object);
67 else if(archs[i].type == OFILE_Mach_O){
68 check_object(archs + i, NULL, archs[i].object);
73 static
74 void
75 check_object(
76 struct arch *arch,
77 struct member *member,
78 struct object *object)
80 uint32_t i, ncmds, flags;
81 struct load_command *lc;
82 struct segment_command *sg;
83 struct segment_command_64 *sg64;
84 struct dylib_command *dl_id;
87 * Set up the symtab load command field and link edit segment feilds in
88 * the object structure.
90 object->st = NULL;
91 object->dyst = NULL;
92 object->hints_cmd = NULL;
93 object->seg_linkedit = NULL;
94 object->seg_linkedit64 = NULL;
95 object->code_sig_cmd = NULL;
96 dl_id = NULL;
97 lc = object->load_commands;
98 if(object->mh != NULL){
99 ncmds = object->mh->ncmds;
100 flags = object->mh->flags;
102 else{
103 ncmds = object->mh64->ncmds;
104 flags = object->mh64->flags;
106 for(i = 0; i < ncmds; i++){
107 if(lc->cmd == LC_SYMTAB){
108 if(object->st != NULL)
109 fatal_arch(arch, member, "malformed file (more than one "
110 "LC_SYMTAB load command): ");
111 object->st = (struct symtab_command *)lc;
113 else if(lc->cmd == LC_DYSYMTAB){
114 if(object->dyst != NULL)
115 fatal_arch(arch, member, "malformed file (more than one "
116 "LC_DYSYMTAB load command): ");
117 object->dyst = (struct dysymtab_command *)lc;
119 else if(lc->cmd == LC_TWOLEVEL_HINTS){
120 if(object->hints_cmd != NULL)
121 fatal_arch(arch, member, "malformed file (more than one "
122 "LC_TWOLEVEL_HINTS load command): ");
123 object->hints_cmd = (struct twolevel_hints_command *)lc;
125 else if(lc->cmd == LC_CODE_SIGNATURE){
126 if(object->code_sig_cmd != NULL)
127 fatal_arch(arch, member, "malformed file (more than one "
128 "LC_CODE_SIGNATURE load command): ");
129 object->code_sig_cmd = (struct linkedit_data_command *)lc;
131 else if(lc->cmd == LC_SEGMENT_SPLIT_INFO){
132 if(object->split_info_cmd != NULL)
133 fatal_arch(arch, member, "malformed file (more than one "
134 "LC_SEGMENT_SPLIT_INFO load command): ");
135 object->split_info_cmd = (struct linkedit_data_command *)lc;
137 else if(lc->cmd == LC_FUNCTION_STARTS){
138 if(object->func_starts_info_cmd != NULL)
139 fatal_arch(arch, member, "malformed file (more than one "
140 "LC_FUNCTION_STARTS load command): ");
141 object->func_starts_info_cmd =
142 (struct linkedit_data_command *)lc;
144 else if(lc->cmd == LC_DATA_IN_CODE){
145 if(object->data_in_code_cmd != NULL)
146 fatal_arch(arch, member, "malformed file (more than one "
147 "LC_DATA_IN_CODE load command): ");
148 object->data_in_code_cmd =
149 (struct linkedit_data_command *)lc;
151 else if(lc->cmd == LC_DYLIB_CODE_SIGN_DRS){
152 if(object->code_sign_drs_cmd != NULL)
153 fatal_arch(arch, member, "malformed file (more than one "
154 "LC_DYLIB_CODE_SIGN_DRS load command): ");
155 object->code_sign_drs_cmd =
156 (struct linkedit_data_command *)lc;
158 else if((lc->cmd == LC_DYLD_INFO) ||(lc->cmd == LC_DYLD_INFO_ONLY)){
159 if(object->dyld_info != NULL)
160 fatal_arch(arch, member, "malformed file (more than one "
161 "LC_DYLD_INFO load command): ");
162 object->dyld_info = (struct dyld_info_command *)lc;
164 else if(lc->cmd == LC_SEGMENT){
165 sg = (struct segment_command *)lc;
166 if(strcmp(sg->segname, SEG_LINKEDIT) == 0){
167 if(object->seg_linkedit != NULL)
168 fatal_arch(arch, member, "malformed file (more than "
169 "one " SEG_LINKEDIT "segment): ");
170 object->seg_linkedit = sg;
173 else if(lc->cmd == LC_SEGMENT_64){
174 sg64 = (struct segment_command_64 *)lc;
175 if(strcmp(sg64->segname, SEG_LINKEDIT) == 0){
176 if(object->seg_linkedit64 != NULL)
177 fatal_arch(arch, member, "malformed file (more than "
178 "one " SEG_LINKEDIT "segment): ");
179 object->seg_linkedit64 = sg64;
182 else if(lc->cmd == LC_ID_DYLIB){
183 if(dl_id != NULL)
184 fatal_arch(arch, member, "malformed file (more than one "
185 "LC_ID_DYLIB load command): ");
186 dl_id = (struct dylib_command *)lc;
187 if(dl_id->dylib.name.offset >= dl_id->cmdsize)
188 fatal_arch(arch, member, "malformed file (name.offset of "
189 "load command %u extends past the end of the load "
190 "command): ", i);
192 lc = (struct load_command *)((char *)lc + lc->cmdsize);
194 if((object->mh_filetype == MH_DYLIB ||
195 (object->mh_filetype == MH_DYLIB_STUB && ncmds > 0)) &&
196 dl_id == NULL)
197 fatal_arch(arch, member, "malformed file (no LC_ID_DYLIB load "
198 "command in %s file): ", object->mh_filetype == MH_DYLIB ?
199 "MH_DYLIB" : "MH_DYLIB_STUB");
200 if(object->hints_cmd != NULL){
201 if(object->dyst == NULL && object->hints_cmd->nhints != 0)
202 fatal_arch(arch, member, "malformed file (LC_TWOLEVEL_HINTS "
203 "load command present without an LC_DYSYMTAB load command):");
204 if(object->hints_cmd->nhints != 0 &&
205 object->hints_cmd->nhints != object->dyst->nundefsym)
206 fatal_arch(arch, member, "malformed file (LC_TWOLEVEL_HINTS "
207 "load command's nhints does not match LC_DYSYMTAB load "
208 "command's nundefsym):");
212 * For objects without a dynamic symbol table check to see that the
213 * string table is at the end of the file and that the symbol table is
214 * just before it.
216 if(object->dyst == NULL){
217 symbol_string_at_end(arch, member, object);
219 else{
221 * This file has a dynamic symbol table command. We handle three
222 * cases, a dynamic shared library, a file for the dynamic linker,
223 * and a relocatable object file. Since it has a dynamic symbol
224 * table command it could have an indirect symbol table.
226 if(object->mh_filetype == MH_DYLIB /* ||
227 object->mh_filetype == MH_DYLIB_STUB */ ){
229 * This is a dynamic shared library.
230 * The order of the symbolic info is:
231 * local relocation entries
232 * symbol table
233 * local symbols
234 * defined external symbols
235 * undefined symbols
236 * two-level namespace hints
237 * external relocation entries
238 * indirect symbol table
239 * table of contents
240 * module table
241 * reference table
242 * string table
243 * strings for external symbols
244 * strings for local symbols
245 * code signature data (16 byte aligned)
247 dyld_order(arch, member, object);
249 else if(flags & MH_DYLDLINK){
251 * This is a file for the dynamic linker (output of ld(1) with
252 * -output_for_dyld . That is the relocation entries are split
253 * into local and external and hanging off the dysymtab not off
254 * the sections.
255 * The order of the symbolic info is:
256 * local relocation entries
257 * symbol table
258 * local symbols (in order as appeared in stabs)
259 * defined external symbols (sorted by name)
260 * undefined symbols (sorted by name)
261 * external relocation entries
262 * indirect symbol table
263 * string table
264 * strings for external symbols
265 * strings for local symbols
266 * code signature data (16 byte aligned)
268 dyld_order(arch, member, object);
270 else{
272 * This is a relocatable object file either the output of the
273 * assembler or output of ld(1) with -r. For the output of
274 * the assembler:
275 * The order of the symbolic info is:
276 * relocation entries (by section)
277 * indirect symbol table
278 * symbol table
279 * local symbols (in order as appeared in stabs)
280 * defined external symbols (sorted by name)
281 * undefined symbols (sorted by name)
282 * string table
283 * strings for external symbols
284 * strings for local symbols
285 * With this order the symbol table can be replaced and the
286 * relocation entries and the indirect symbol table entries
287 * can be updated in the file and not moved.
288 * For the output of ld -r:
289 * The order of the symbolic info is:
290 * relocation entries (by section)
291 * symbol table
292 * local symbols (in order as appeared in stabs)
293 * defined external symbols (sorted by name)
294 * undefined symbols (sorted by name)
295 * indirect symbol table
296 * string table
297 * strings for external symbols
298 * strings for local symbols
299 * code signature
301 symbol_string_at_end(arch, member, object);
306 static
307 void
308 dyld_order(
309 struct arch *arch,
310 struct member *member,
311 struct object *object)
313 uint32_t offset, rounded_offset, isym;
315 if(object->mh != NULL){
316 if(object->seg_linkedit == NULL)
317 fatal_arch(arch, member, "malformed file (no " SEG_LINKEDIT
318 " segment): ");
319 if(object->seg_linkedit->filesize != 0 &&
320 object->seg_linkedit->fileoff +
321 object->seg_linkedit->filesize != object->object_size)
322 fatal_arch(arch, member, "the " SEG_LINKEDIT " segment "
323 "does not cover the end of the file (can't "
324 "be processed) in: ");
326 offset = object->seg_linkedit->fileoff;
328 else{
329 if(object->seg_linkedit64 == NULL)
330 fatal_arch(arch, member, "malformed file (no " SEG_LINKEDIT
331 " segment): ");
332 if(object->seg_linkedit64->filesize != 0 &&
333 object->seg_linkedit64->fileoff +
334 object->seg_linkedit64->filesize != object->object_size)
335 fatal_arch(arch, member, "the " SEG_LINKEDIT " segment "
336 "does not cover the end of the file (can't "
337 "be processed) in: ");
339 offset = object->seg_linkedit64->fileoff;
341 if(object->dyld_info != NULL){
342 /* dyld_info starts at beginning of __LINKEDIT */
343 if (object->dyld_info->rebase_off != 0){
344 if (object->dyld_info->rebase_off != offset)
345 order_error(arch, member, "dyld_info "
346 "out of place");
348 else if (object->dyld_info->bind_off != 0){
349 if (object->dyld_info->bind_off != offset)
350 order_error(arch, member, "dyld_info "
351 "out of place");
353 /* update offset to end of dyld_info contents */
354 if (object->dyld_info->export_size != 0)
355 offset = object->dyld_info->export_off +
356 object->dyld_info->export_size;
357 else if (object->dyld_info->lazy_bind_size != 0)
358 offset = object->dyld_info->lazy_bind_off +
359 object->dyld_info->lazy_bind_size;
360 else if (object->dyld_info->weak_bind_size != 0)
361 offset = object->dyld_info->weak_bind_off +
362 object->dyld_info->weak_bind_size;
363 else if (object->dyld_info->bind_size != 0)
364 offset = object->dyld_info->bind_off +
365 object->dyld_info->bind_size;
366 else if (object->dyld_info->rebase_size != 0)
367 offset = object->dyld_info->rebase_off +
368 object->dyld_info->rebase_size;
370 if(object->dyst->nlocrel != 0){
371 if(object->dyst->locreloff != offset)
372 order_error(arch, member, "local relocation entries "
373 "out of place");
374 offset += object->dyst->nlocrel *
375 sizeof(struct relocation_info);
377 if(object->split_info_cmd != NULL){
378 if(object->split_info_cmd->dataoff != offset)
379 order_error(arch, member, "split info data out of place");
380 offset += object->split_info_cmd->datasize;
382 if(object->func_starts_info_cmd != NULL){
383 if(object->func_starts_info_cmd->dataoff != offset)
384 order_error(arch, member, "function starts data out of place");
385 offset += object->func_starts_info_cmd->datasize;
387 if(object->data_in_code_cmd != NULL){
388 if(object->data_in_code_cmd->dataoff != offset)
389 order_error(arch, member, "data in code info out of place");
390 offset += object->data_in_code_cmd->datasize;
392 if(object->code_sign_drs_cmd != NULL){
393 if(object->code_sign_drs_cmd->dataoff != offset)
394 order_error(arch, member, "code signing DRs info out of place");
395 offset += object->code_sign_drs_cmd->datasize;
397 if(object->st->nsyms != 0){
398 if(object->st->symoff != offset)
399 order_error(arch, member, "symbol table out of place");
400 if(object->mh != NULL)
401 offset += object->st->nsyms * sizeof(struct nlist);
402 else
403 offset += object->st->nsyms * sizeof(struct nlist_64);
405 isym = 0;
406 if(object->dyst->nlocalsym != 0){
407 if(object->dyst->ilocalsym != isym)
408 order_error(arch, member, "local symbols out of place");
409 isym += object->dyst->nlocalsym;
411 if(object->dyst->nextdefsym != 0){
412 if(object->dyst->iextdefsym != isym)
413 order_error(arch, member, "externally defined symbols out of "
414 "place");
415 isym += object->dyst->nextdefsym;
417 if(object->dyst->nundefsym != 0){
418 if(object->dyst->iundefsym != isym)
419 order_error(arch, member, "undefined symbols out of place");
420 isym += object->dyst->nundefsym;
422 if(object->hints_cmd != NULL && object->hints_cmd->nhints != 0){
423 if(object->hints_cmd->offset != offset)
424 order_error(arch, member, "hints table out of place");
425 offset += object->hints_cmd->nhints * sizeof(struct twolevel_hint);
427 if(object->dyst->nextrel != 0){
428 if(object->dyst->extreloff != offset)
429 order_error(arch, member, "external relocation entries"
430 " out of place");
431 offset += object->dyst->nextrel *
432 sizeof(struct relocation_info);
434 if(object->dyst->nindirectsyms != 0){
435 if(object->dyst->indirectsymoff != offset)
436 order_error(arch, member, "indirect symbol table "
437 "out of place");
438 offset += object->dyst->nindirectsyms *
439 sizeof(uint32_t);
443 * If this is a 64-bit Mach-O file and has an odd number of indirect
444 * symbol table entries the next offset MAYBE rounded to a multiple of
445 * 8 or MAY NOT BE. This should done to keep all the tables aligned but
446 * was not done for 64-bit Mach-O in Mac OS X 10.4.
448 object->input_indirectsym_pad = 0;
449 if(object->mh64 != NULL &&
450 (object->dyst->nindirectsyms % 2) != 0){
451 rounded_offset = rnd(offset, 8);
453 else{
454 rounded_offset = offset;
457 if(object->dyst->ntoc != 0){
458 if(object->dyst->tocoff != offset &&
459 object->dyst->tocoff != rounded_offset)
460 order_error(arch, member, "table of contents out of place");
461 if(object->dyst->tocoff == offset){
462 offset += object->dyst->ntoc *
463 sizeof(struct dylib_table_of_contents);
464 rounded_offset = offset;
466 else if(object->dyst->tocoff == rounded_offset){
467 object->input_indirectsym_pad = rounded_offset - offset;
468 rounded_offset += object->dyst->ntoc *
469 sizeof(struct dylib_table_of_contents);
470 offset = rounded_offset;
473 if(object->dyst->nmodtab != 0){
474 if(object->dyst->modtaboff != offset &&
475 object->dyst->modtaboff != rounded_offset)
476 order_error(arch, member, "module table out of place");
477 if(object->mh != NULL){
478 offset += object->dyst->nmodtab *
479 sizeof(struct dylib_module);
480 rounded_offset = offset;
482 else{
483 if(object->dyst->modtaboff == offset){
484 offset += object->dyst->nmodtab *
485 sizeof(struct dylib_module_64);
486 rounded_offset = offset;
488 else if(object->dyst->modtaboff == rounded_offset){
489 object->input_indirectsym_pad = rounded_offset - offset;
490 rounded_offset += object->dyst->nmodtab *
491 sizeof(struct dylib_module_64);
492 offset = rounded_offset;
496 if(object->dyst->nextrefsyms != 0){
497 if(object->dyst->extrefsymoff != offset &&
498 object->dyst->extrefsymoff != rounded_offset)
499 order_error(arch, member, "reference table out of place");
500 if(object->dyst->extrefsymoff == offset){
501 offset += object->dyst->nextrefsyms *
502 sizeof(struct dylib_reference);
503 rounded_offset = offset;
505 else if(object->dyst->extrefsymoff == rounded_offset){
506 object->input_indirectsym_pad = rounded_offset - offset;
507 rounded_offset += object->dyst->nextrefsyms *
508 sizeof(struct dylib_reference);
509 offset = rounded_offset;
512 if(object->st->strsize != 0){
513 if(object->st->stroff != offset &&
514 object->st->stroff != rounded_offset)
515 order_error(arch, member, "string table out of place");
516 if(object->st->stroff == offset){
517 offset += object->st->strsize;
518 rounded_offset = offset;
520 else if(object->st->stroff == rounded_offset){
521 object->input_indirectsym_pad = rounded_offset - offset;
522 rounded_offset += object->st->strsize;
523 offset = rounded_offset;
526 if(object->code_sig_cmd != NULL){
527 rounded_offset = rnd(rounded_offset, 16);
528 if(object->code_sig_cmd->dataoff != rounded_offset)
529 order_error(arch, member, "code signature data out of place");
530 rounded_offset += object->code_sig_cmd->datasize;
531 offset = rounded_offset;
533 if(offset != object->object_size &&
534 rounded_offset != object->object_size)
535 order_error(arch, member, "link edit information does not fill the "
536 SEG_LINKEDIT " segment");
539 static
540 void
541 order_error(
542 struct arch *arch,
543 struct member *member,
544 char *reason)
546 fatal_arch(arch, member, "file not in an order that can be processed "
547 "(%s): ", reason);
550 static
551 void
552 symbol_string_at_end(
553 struct arch *arch,
554 struct member *member,
555 struct object *object)
557 uint32_t end, sigend, strend, rounded_strend;
558 uint32_t indirectend, rounded_indirectend;
560 if(object->st != NULL && object->st->nsyms != 0){
561 end = object->object_size;
562 if(object->code_sig_cmd != NULL){
563 sigend = object->code_sig_cmd->dataoff +
564 object->code_sig_cmd->datasize;
565 if(sigend != end)
566 fatal_arch(arch, member, "code signature not at the end "
567 "of the file (can't be processed) in file: ");
569 * The code signature starts at a 16 byte offset. So if the
570 * string table end rouned to 16 bytes is the offset where the
571 * code signature starts then just back up the current "end" to
572 * the end of the string table.
574 end = object->code_sig_cmd->dataoff;
575 if(object->st->strsize != 0){
576 strend = object->st->stroff + object->st->strsize;
577 rounded_strend = rnd(strend, 16);
578 if(object->code_sig_cmd->dataoff == rounded_strend)
579 end = strend;
582 if(object->st->strsize != 0){
583 strend = object->st->stroff + object->st->strsize;
585 * Since archive member sizes are now rounded to 8 bytes the
586 * string table may not be exactly at the end of the
587 * object_size due to rounding.
589 rounded_strend = rnd(strend, 8);
590 if(strend != end && rounded_strend != end)
591 fatal_arch(arch, member, "string table not at the end "
592 "of the file (can't be processed) in file: ");
594 * To make the code work that assumes the end of string table is
595 * at the end of the object file change the object_size to be
596 * the end of the string table here. This could be done at the
597 * end of this routine but since all the later checks are fatal
598 * we'll just do this here.
600 if(rounded_strend != strend)
601 object->object_size = strend;
602 end = object->st->stroff;
604 if(object->dyst != NULL &&
605 object->dyst->nindirectsyms != 0 &&
606 object->st->nsyms != 0 &&
607 object->dyst->indirectsymoff > object->st->symoff){
609 indirectend = object->dyst->indirectsymoff +
610 object->dyst->nindirectsyms * sizeof(uint32_t);
613 * If this is a 64-bit Mach-O file and has an odd number of
614 * indirect symbol table entries the next offset MAYBE rounded
615 * to a multiple of 8 or MAY NOT BE. This should done to keep
616 * all the tables aligned but was not done for 64-bit Mach-O in
617 * Mac OS X 10.4.
619 if(object->mh64 != NULL &&
620 (object->dyst->nindirectsyms % 2) != 0){
621 rounded_indirectend = rnd(indirectend, 8);
623 else{
624 rounded_indirectend = indirectend;
627 if(indirectend != end && rounded_indirectend != end){
628 fatal_arch(arch, member, "indirect symbol table does not "
629 "directly preceed the string table (can't be "
630 "processed) in file: ");
632 object->input_indirectsym_pad = end - indirectend;
633 end = object->dyst->indirectsymoff;
634 if(object->mh != NULL){
635 if(object->st->symoff +
636 object->st->nsyms * sizeof(struct nlist) != end)
637 fatal_arch(arch, member, "symbol table does not "
638 "directly preceed the indirect symbol table (can't "
639 "be processed) in file: ");
641 else{
642 if(object->st->symoff +
643 object->st->nsyms * sizeof(struct nlist_64) != end)
644 fatal_arch(arch, member, "symbol table does not "
645 "directly preceed the indirect symbol table (can't "
646 "be processed) in file: ");
649 else{
650 if(object->mh != NULL){
651 if(object->st->symoff +
652 object->st->nsyms * sizeof(struct nlist) != end)
653 fatal_arch(arch, member, "symbol table and string "
654 "table not at the end of the file (can't be "
655 "processed) in file: ");
657 else{
658 if(object->st->symoff +
659 object->st->nsyms * sizeof(struct nlist_64) != end)
660 fatal_arch(arch, member, "symbol table and string "
661 "table not at the end of the file (can't be "
662 "processed) in file: ");
665 if(object->seg_linkedit != NULL &&
666 (object->seg_linkedit->flags & SG_FVMLIB) != SG_FVMLIB &&
667 object->seg_linkedit->filesize != 0){
668 if(object->seg_linkedit->fileoff +
669 object->seg_linkedit->filesize != object->object_size)
670 fatal_arch(arch, member, "the " SEG_LINKEDIT " segment "
671 "does not cover the symbol and string table (can't "
672 "be processed) in file: ");
676 #endif /* !defined(RLD) */