/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef RLD #include #include #include #include #include #include #include #include #include #include #include "stuff/bool.h" #include "stuff/errors.h" #include "stuff/allocate.h" #include "stuff/guess_short_name.h" #include "stuff/seg_addr_table.h" /* * parse_default_seg_addr_table() simply calls parse_seg_addr_table() with * the default file that contains the segment address table. */ struct seg_addr_table * parse_default_seg_addr_table( char **seg_addr_table_name, unsigned long *table_size) { #ifdef __GONZO_BUNSEN_BEAKER__ *seg_addr_table_name = "/Local/Developer/seg_addr_table"; #else *seg_addr_table_name = "/AppleInternal/Developer/seg_addr_table"; #endif return(parse_seg_addr_table(*seg_addr_table_name, "default", "segment address table", table_size)); } /* * parse_seg_addr_table() opens the file_name passed to it and parses it as a * segment address table. The flag and argument parameters are used for * error messages if there is a problem parsing the file. The file should * contains lines of the form: * * or * * The first form with one specifies the -seg1addr of the * dynamic shared library with the specified . The second form * specifies the -segs_read_only_addr and the -segs_read_write_addr addresses * of the dynamic shared library. The fields are to be separated by spaces or * tabs. Comment lines starting with a '#' character are ignored as well as * lines with just spaces and tabs. This routine returns the parsed table as an * array of seg_addr_table structs. The last entry in the table has a NULL * install_name. For lines with two addresses the field split will be TRUE * otherwise it will be FALSE. */ struct seg_addr_table * parse_seg_addr_table( char *file_name,/* file name of the seg_addr_table file */ char *flag, /* "-seg_addr_table" or "default" */ char *argument, /* -seg_addr_table argument or "segment address table" */ unsigned long *table_size) { int fd; kern_return_t r; struct stat stat_buf; unsigned long j, k, file_size, seg_addr_table_size, line; char *file_addr, *endp; struct seg_addr_table *new_seg_addr_table; if((fd = open(file_name, O_RDONLY, 0)) == -1) system_fatal("Can't open: %s for %s %s", file_name, flag, argument); if(fstat(fd, &stat_buf) == -1) system_fatal("Can't stat file: %s for %s %s", file_name, flag, argument); /* * For some reason mapping files with zero size fails * so it has to be handled specially. */ if(stat_buf.st_size != 0){ if((r = map_fd((int)fd, (vm_offset_t)0, (vm_offset_t *)&file_addr, (boolean_t)TRUE, (vm_size_t)stat_buf.st_size)) != KERN_SUCCESS) mach_fatal(r, "can't map file: %s for %s %s", file_name, flag, argument); } else fatal("Empty file: %s for %s %s", file_name, flag, argument); close(fd); file_size = stat_buf.st_size; /* * Got the file mapped now parse it. */ if(file_addr[file_size - 1] != '\n') fatal("file: %s for %s %s does not end in new line", file_name, flag, argument); seg_addr_table_size = 0; for(j = 1; j < file_size; j++){ if(file_addr[j] == '\n'){ seg_addr_table_size++; } } seg_addr_table_size++; new_seg_addr_table = allocate(sizeof(struct seg_addr_table) * seg_addr_table_size); k = 0; line = 1; for(j = 0; j < file_size; /* no increment expression */ ){ /* Skip lines that start with '#' */ if(file_addr[j] == '#'){ j++; while(file_addr[j] != '\n') j++; continue; } /* Skip blank lines */ while(file_addr[j] == ' ' || file_addr[j] == '\t') j++; if(file_addr[j] == '\n'){ j++; line++; continue; } new_seg_addr_table[k].seg1addr = strtoul(file_addr + j, &endp, 16); if(endp == NULL) fatal("improper hexadecimal number on line %lu in " "file: %s for %s %s", j, file_name, flag, argument); j = endp - file_addr; if(j == file_size) fatal("missing library install name on line %lu in file: " "%s for %s %s", j, file_name, flag, argument); /* * Since we checked to see the file ends in a '\n' we can * be assured this won't run off the end of the file. */ while(file_addr[j] == ' ' || file_addr[j] == '\t') j++; if(file_addr[j] == '\n') fatal("missing library install name on line %lu in file: " "%s for %s %s", j, file_name, flag, argument); new_seg_addr_table[k].segs_read_write_addr = strtoul(file_addr + j, &endp, 16); if(endp == NULL || endp == file_addr + j){ new_seg_addr_table[k].split = FALSE; new_seg_addr_table[k].segs_read_write_addr = ULONG_MAX; } else{ j = endp - file_addr; new_seg_addr_table[k].split = TRUE; new_seg_addr_table[k].segs_read_only_addr = new_seg_addr_table[k].seg1addr; new_seg_addr_table[k].seg1addr = ULONG_MAX; while(file_addr[j] == ' ' || file_addr[j] == '\t') j++; } new_seg_addr_table[k].install_name = file_addr + j; new_seg_addr_table[k].line = line; k++; while(file_addr[j] != '\n') j++; file_addr[j] = '\0'; line++; j++; } new_seg_addr_table[k].install_name = NULL; new_seg_addr_table[k].seg1addr = 0; new_seg_addr_table[k].split = FALSE; new_seg_addr_table[k].segs_read_only_addr = ULONG_MAX; new_seg_addr_table[k].segs_read_write_addr = ULONG_MAX; new_seg_addr_table[k].line = line; *table_size = k; return(new_seg_addr_table); } /* * search_seg_addr_table() searches the specified segment address table for the * specified name and returns the entry to it if it is found. If it is not * found NULL is returned. */ struct seg_addr_table * search_seg_addr_table( struct seg_addr_table *seg_addr_table, char *install_name) { struct seg_addr_table *p; if(seg_addr_table == NULL) return(NULL); for(p = seg_addr_table; p->install_name != NULL; p++){ if(strcmp(p->install_name, install_name) == 0) return(p); } return(NULL); } /* * process_seg_addr_table() is used to create an new segment address table from * an existing segment address table. It opens and parses "file_name" as a * segment address table. It copies the comment lines that don't start with * "comment_prefix" to "out_fp". For entries in the file it calls the function * processor() pass to it and passes it the parsed entry from the file, the * "out_fp" and the "cookie" passed to process_seg_addr_table(). */ void process_seg_addr_table( char *file_name, FILE *out_fp, char *comment_prefix, void (*processor)(struct seg_addr_table *entry, FILE *out_fp, void *cookie), void *cookie) { int fd; kern_return_t r; struct stat stat_buf; unsigned long i, file_size, line, comment_prefix_length; char *file_addr, *endp; struct seg_addr_table entry; if((fd = open(file_name, O_RDONLY, 0)) == -1) system_fatal("can't open file: %s", file_name); if(fstat(fd, &stat_buf) == -1) system_fatal("can't stat file: %s", file_name); /* * For some reason mapping files with zero size fails * so it has to be handled specially. */ if(stat_buf.st_size != 0){ if((r = map_fd((int)fd, (vm_offset_t)0, (vm_offset_t *)&file_addr, (boolean_t)TRUE, (vm_size_t)stat_buf.st_size)) != KERN_SUCCESS) mach_fatal(r, "can't map file: %s", file_name); } else fatal("empty file: %s ", file_name); close(fd); file_size = stat_buf.st_size; /* * Got the file mapped now parse and process it. */ if(file_addr[file_size - 1] != '\n') fatal("file: %s does not end in new line", file_name); line = 1; comment_prefix_length = strlen(comment_prefix); for(i = 0; i < file_size; /* no increment expression */ ){ /* Copy comment lines that start with '#' */ if(file_addr[i] == '#'){ if(strncmp(comment_prefix, file_addr + i + 1, comment_prefix_length) == 0){ i++; while(file_addr[i] != '\n') i++; if(file_addr[i] == '\n'){ i++; line++; } continue; } fputc(file_addr[i], out_fp); i++; while(file_addr[i] != '\n'){ fputc(file_addr[i], out_fp); i++; } continue; } /* Copy blank lines */ while(file_addr[i] == ' ' || file_addr[i] == '\t'){ fputc(file_addr[i], out_fp); i++; } if(file_addr[i] == '\n'){ fputc(file_addr[i], out_fp); i++; line++; continue; } entry.seg1addr = strtoul(file_addr + i, &endp, 16); if(endp == NULL) fatal("improper hexadecimal number on line %lu in file: %s", line, file_name); i = endp - file_addr; if(i == file_size) fatal("missing library install name on line %lu in file: %s", line, file_name); /* * Since we checked to see the file ends in a '\n' we can * be assured this won't run off the end of the file. */ while(file_addr[i] == ' ' || file_addr[i] == '\t') i++; if(file_addr[i] == '\n') fatal("missing library install name on line %lu in file: %s", line, file_name); entry.segs_read_write_addr = strtoul(file_addr + i, &endp, 16); if(endp == NULL || endp == file_addr + i){ entry.split = FALSE; entry.segs_read_write_addr = ULONG_MAX; } else{ i = endp - file_addr; entry.split = TRUE; entry.segs_read_only_addr = entry.seg1addr; entry.seg1addr = ULONG_MAX; while(file_addr[i] == ' ' || file_addr[i] == '\t') i++; } entry.install_name = file_addr + i; entry.line = line; while(file_addr[i] != '\n') i++; file_addr[i] = '\0'; processor(&entry, out_fp, cookie); line++; i++; } } #endif /* !defined(RLD) */