1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 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. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 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" 33 34static 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); 40static void breakout_loop_through_archive( 41 char *filename, 42 struct arch *arch, 43 struct ofile *ofile); 44static void cksum_object( 45 struct arch *arch, 46 enum bool calculate_input_prebind_cksum); 47static struct arch *new_arch( 48 struct arch **archs, 49 uint32_t *narchs); 50static struct member *new_member( 51 struct arch *arch); 52 53__private_extern__ 54struct ofile * 55breakout_mem( 56void *membuf, 57uint32_t length, 58char *filename, 59struct arch **archs, 60uint32_t *narchs, 61enum bool calculate_input_prebind_cksum) 62{ 63 struct ofile *ofile; 64 uint32_t previous_errors; 65 66 *archs = NULL; 67 *narchs = 0; 68 ofile = allocate(sizeof(struct ofile)); 69 70 /* 71 * If the file_name is NULL, we will use a dummy file name so 72 * that error reporting, etc. works. 73 */ 74 if(filename == NULL) 75 filename = "(broken out from memory)"; 76 77 /* 78 * Rely on the ofile_*() routines to do all the checking and only 79 * return valid ofiles files broken out. 80 */ 81 if(ofile_map_from_memory((char *)membuf, length, filename, 0,NULL, NULL, 82 ofile, FALSE) == FALSE){ 83 free(ofile); 84 return(NULL); 85 } 86 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); 94 } 95 return(ofile); 96} 97 98__private_extern__ 99struct ofile * 100breakout( 101char *filename, 102struct arch **archs, 103uint32_t *narchs, 104enum bool calculate_input_prebind_cksum) 105{ 106 struct ofile *ofile; 107 uint32_t previous_errors; 108 109 *archs = NULL; 110 *narchs = 0; 111 ofile = allocate(sizeof(struct ofile)); 112 /* 113 * Rely on the ofile_*() routines to do all the checking and only 114 * return valid ofiles files broken out. 115 */ 116 if(ofile_map(filename, NULL, NULL, ofile, FALSE) == FALSE){ 117 free(ofile); 118 return(NULL); 119 } 120 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); 128 } 129 return(ofile); 130} 131 132static 133void 134breakout_internal( 135char *filename, 136struct arch **archs, 137uint32_t *narchs, 138enum bool calculate_input_prebind_cksum, 139struct ofile *ofile) 140{ 141 struct arch *arch; 142 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); 147 do{ 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); 155 156 if(ofile->arch_type == OFILE_ARCHIVE){ 157 breakout_loop_through_archive(filename, arch, ofile); 158 } 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); 172 } 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; 177 } 178 }while(ofile_next_arch(ofile) == TRUE); 179 } 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; 184 185 breakout_loop_through_archive(filename, arch, ofile); 186 } 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); 203 } 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; 210 } 211 if(errors != 0){ 212 free_archs(*archs, *narchs); 213 *archs = NULL; 214 *narchs = 0; 215 } 216} 217 218static 219void 220breakout_loop_through_archive( 221char *filename, 222struct arch *arch, 223struct ofile *ofile) 224{ 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]; 231 232 /* loop through archive (can be empty) */ 233 if((flag = ofile_first_member(ofile)) == TRUE && errors == 0){ 234 /* 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. 240 */ 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); 246 } 247 while(flag == TRUE && errors == 0){ 248 member = new_member(arch); 249 member->type = ofile->member_type; 250 member->member_name = ofile->member_name; 251 /* 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'. 264 */ 265 if(ofile->mh != NULL || ofile->mh64 != NULL) 266 size = rnd(ofile->object_size, 8); 267 else 268 size = rnd(ofile->member_size, 8); 269 /* 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. 275 */ 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; 282 } 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; 288 /* 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. 292 */ 293 member->offset = arch->library_size; 294 arch->library_size += sizeof(struct ar_hdr) + size; 295 /* 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. 300 */ 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)); 312 313 member->ar_hdr = ar_hdr; 314 member->input_ar_hdr = ofile->member_ar_hdr; 315 member->input_file_name = filename; 316 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; 329 } 330 else{ /* ofile->member_type == OFILE_UNKNOWN */ 331 member->unknown_addr = ofile->member_addr; 332 member->unknown_size = ofile->member_size; 333 } 334 flag = ofile_next_member(ofile); 335 } 336 } 337} 338 339/* 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. 350 */ 351static 352void 353cksum_object( 354struct arch *arch, 355enum bool calculate_input_prebind_cksum) 356{ 357 uint32_t i, buf_size, ncmds; 358 struct load_command *lc; 359 enum byte_sex host_byte_sex; 360 char *buf; 361 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); 374 } 375 376 /* 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. 380 */ 381 if(calculate_input_prebind_cksum == FALSE || 382 arch->object->cs == NULL || 383 arch->object->cs->cksum != 0) 384 return; 385 386 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; 399 } 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; 408 } 409 } 410 411 arch->object->calculated_input_prebind_cksum = 412 crc32(arch->object->object_addr, arch->object->object_size); 413 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); 420 } 421} 422 423__private_extern__ 424void 425free_archs( 426struct arch *archs, 427uint32_t narchs) 428{ 429 uint32_t i, j; 430 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); 438 } 439 } 440 if(archs[i].nmembers > 0 && archs[i].members != NULL) 441 free(archs[i].members); 442 } 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); 447 } 448 } 449 if(narchs > 0 && archs != NULL) 450 free(archs); 451} 452 453static 454struct arch * 455new_arch( 456struct arch **archs, 457uint32_t *narchs) 458{ 459 struct arch *arch; 460 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); 466} 467 468static 469struct member * 470new_member( 471struct arch *arch) 472{ 473 struct member *member; 474 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); 481} 482#endif /* !defined(RLD) */ 483