This is SegmentManager.m in view mode; [Download] [Up]
#import "SegmentManager.h"
#import <stdlib.h>
#import <string.h>
#import <mach-o/loader.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <mach-o/ldsyms.h>
#import <libc.h>
#import <objc/maptable.h>
#import <mach-o/fat.h>
#define REALLY_SWAP_LONG(a) ( ((a) << 24) | \
(((a) << 8) & 0x00ff0000) | \
(((a) >> 8) & 0x0000ff00) | \
((unsigned long)(a) >> 24) )
#define SWAP_LONG(a) (shouldSwap ? REALLY_SWAP_LONG(a) : (a))
@implementation SegmentManager
static NXMapTable *managers = NULL;
+initialize
{
static BOOL beenHere = NO;
if (!beenHere) {
beenHere = YES;
managers = NXCreateMapTable(NXStrValueMapPrototype, 0);
}
return self;
}
-init
{
relocSize = sizeof(Segment);
rmFlags.shouldSortRelocs = YES;
[self readInAllRelocs];
lastReloc = NULL;
if (numRelocs) {
if (images[0].name)
NXMapInsert(managers, images[0].name, self);
return self;
} else {
[self free];
return nil;
}
}
-(void)setCpuType: (cpu_type_t)type
{
static cpu_type_t defaultCpuType = 0;
if (type)
cpuType = type;
else {
if (!defaultCpuType) {
struct host_basic_info host_basic_info;
unsigned int count = HOST_BASIC_INFO_COUNT;
if (host_info(host_self(), HOST_BASIC_INFO,
(host_info_t)(&host_basic_info),
&count) == KERN_SUCCESS)
defaultCpuType = host_basic_info.cpu_type;
}
cpuType = defaultCpuType;
}
}
-initFile: (STR)theName skipShlibs: (BOOL)shouldSkipShlibs withDesc: (int)desc cpuType: (cpu_type_t)type
{
SegmentManager *oldManager;
if (oldManager = NXMapGet(managers, theName)) {
close(desc);
[self free];
return oldManager;
} else {
name = malloc(strlen(theName) + 1);
strcpy(name, theName);
skipShlibs = shouldSkipShlibs;
imageFd = desc;
[self setCpuType: type];
[self getImages];
return [self init];
}
}
static const char loadedName[] = "loaded file";
-(struct mach_header *)headerFromStart: (void *)start
{
struct mach_header *header = start;
if (header->magic == MH_MAGIC && header->cputype == cpuType)
return header;
else {
struct fat_header *fatHeader = start;
if ((fatHeader->magic == FAT_MAGIC)
|| (fatHeader->magic == REALLY_SWAP_LONG(FAT_MAGIC))) {
BOOL shouldSwap = !(fatHeader->magic == FAT_MAGIC);
unsigned int nArches;
struct fat_arch *fatArch, *foundArch;
for (nArches = SWAP_LONG(fatHeader->nfat_arch),
fatArch = (struct fat_arch *)(fatHeader + 1),
foundArch = NULL;
nArches && !foundArch;
fatArch++, nArches--) {
if (cpuType == SWAP_LONG(fatArch->cputype))
foundArch = fatArch;
}
if (foundArch)
return start + SWAP_LONG(foundArch->offset);
else
return NULL;
} else
return NULL;
}
}
-initHeader: (struct mach_header *)header withSize: (int)size andSlide:(unsigned long)slide
{
numImages = 1;
[self setCpuType: 0];
images = malloc(sizeof(*images));
images->header = [self headerFromStart: header];
images->size = size;
images->name = NULL;
images->mtime = 0;
images->slide = slide;
name = malloc(sizeof(loadedName));
strcpy(name, loadedName);
return [self init];
}
// Assume header and all of it's load commands have been
// warped onto the current memory space.
-initHeader: (struct mach_header *)header withSlide:(unsigned long)slide
{
int i;
struct load_command* cmd;
unsigned long maxAddr;
unsigned long hAddr;
// Compute the size of the module from the load commands.
[self setCpuType: 0];
maxAddr = hAddr = (unsigned) header = [self headerFromStart:header];
for (cmd = (struct load_command *)(header + 1), i = 0;
i < header->ncmds;
((void *)cmd) += cmd->cmdsize, i++) {
unsigned long topAddr;
if (cmd->cmd == LC_SEGMENT)
{
struct segment_command *segCmd = (struct segment_command *)cmd;
topAddr = segCmd->vmaddr + segCmd->vmsize + slide;
if (topAddr > maxAddr)
maxAddr = topAddr;
}
}
return [self initHeader: header
withSize: maxAddr - (unsigned)header
andSlide: slide];
}
+newHeader:(struct mach_header*)header withSlide:(unsigned long)slide
{
return [[self alloc] initHeader:header withSlide:slide];
}
-initHeader: (struct mach_header *)header withSize: (int)size
{
return [self initHeader:header withSize:size andSlide:0];
}
-initHeader: (struct mach_header *)header
{
return [self initHeader:header withSlide:0];
}
-initFile: (STR)theName
{
return [self initFile: theName skipShlibs: NO withDesc: -1 cpuType: 0];
}
+newExecutable: (STR)theName skipShlibs: (BOOL)shouldSkipShlibs withDesc: (int)desc cpuType: (cpu_type_t)type
{
SegmentManager *sm = [[super alloc] initFile: (STR)theName
skipShlibs: shouldSkipShlibs
withDesc: desc
cpuType: type];
if (sm && [sm isExecutable])
return sm;
else {
[sm free];
return nil;
}
}
+newExecutable: (STR)theName
{
return [self newExecutable: theName skipShlibs: NO withDesc: -1 cpuType: 0];
}
+newCore: (STR)theName
{
SegmentManager *sm = [[super alloc] initFile: (STR)theName];
if (sm && [sm isCore])
return sm;
else {
[sm free];
return nil;
}
}
+newFile: (STR)theName
{
return [[super alloc] initFile: (STR)theName];
}
+newShlib: (STR)theName cpuType: (cpu_type_t)type
{
SegmentManager *sm = [[super alloc] initFile: (STR)theName
skipShlibs: YES
withDesc: -1
cpuType: type];
if (sm && [sm isShlib])
return sm;
else {
[sm free];
return nil;
}
}
+newShlib: (STR)theName
{
return [self newShlib: theName cpuType: 0];
}
+newHeader: (struct mach_header *)header withSize: (int)size
{
return [[super alloc] initHeader: header withSize: size];
}
-(STR)executableName
{
return name;
}
-(long)mtime
{
return images[0].mtime;
}
-free
{
NXMapRemove(managers, name);
free(name); name = NULL;
return [super free];
}
-invalidate
{
int count;
Image *image;
if (images) {
for (count = numImages, image = images; count; count--, image++) {
if (image->deallocate)
vm_deallocate(task_self(),
(vm_address_t)image->header,
image->size);
}
free(images); images = NULL;
numImages = 0;
}
return [super invalidate];
}
-(void)getImages
{
struct stat imageStat;
struct load_command *loadCmd;
struct fvmlib_command *fvmCmd;
struct mach_header *header;
int i;
Image *image;
numImages = 0;
if (imageFd < 0)
imageFd = open(name, O_RDONLY, 0);
if (imageFd >= 0) {
extern int errno;
errno = 0;
fstat(imageFd, &imageStat);
if (map_fd(imageFd,
0,
(vm_address_t *)&header,
YES,
imageStat.st_size) == 0) {
// printf("Map_fp successfull.\n");
if (header && (header = [self headerFromStart: header])) {
// printf("Got header.\n");
numImages = 1;
if (skipShlibs) {
images = malloc(sizeof(Image));
images->name = name;
images->header = header;
images->size = imageStat.st_size;
images->deallocate = YES;
images->slide = 0;
images->mtime = imageStat.st_mtime;
} else {
for (i = 0, loadCmd = (struct load_command *)(header + 1);
i < header->ncmds;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
if (loadCmd->cmd == LC_LOADFVMLIB)
numImages++;
}
image
= images
= calloc(numImages, sizeof(Image));
image->name = name;
image->header = header;
image->size = imageStat.st_size;
image->deallocate = YES;
image->slide = 0;
image->mtime = imageStat.st_mtime;
image++;
for (i = 0, loadCmd = (struct load_command *)(header + 1);
i < header->ncmds;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
int shlibFd;
if (loadCmd->cmd == LC_LOADFVMLIB) {
fvmCmd = (struct fvmlib_command *)loadCmd;
image->name
= (void *)fvmCmd + fvmCmd->fvmlib.name.offset;
shlibFd = open(image->name, O_RDONLY, 0);
if (shlibFd >= 0) {
fstat(shlibFd, &imageStat);
image->size = imageStat.st_size;
image->mtime = imageStat.st_mtime;
if (map_fd(shlibFd,
0,
(vm_address_t *)&image->header,
YES,
image->size)
== 0) {
image->header
= [self headerFromStart: image->header];
image->deallocate = YES;
image++;
} else
numImages--;
close(shlibFd);
} else
numImages--;
}
}
}
} else {
printf("Error: file had bad header.\n");
}
} else {
// printf("Map_fd failed, errno = %d.\n", errno);
}
close(imageFd);
imageFd = -1;
}
}
-(int)numSegments
{
int count, numSegs = 0, i;
Image *image;
struct load_command *loadCmd;
struct mach_header *header;
for (count = numImages,
image = images;
count;
count--, image++) {
header = image->header;
for (i = 0, loadCmd = (struct load_command *)(header + 1);
i < header->ncmds;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
if (loadCmd->cmd == LC_SEGMENT)
numSegs++;
}
}
return numSegs;
}
-(BOOL)validate
{
int nImages, i;
Image *image;
struct mach_header *header;
struct load_command *loadCmd;
struct segment_command *segCmd;
BOOL allOK = YES;
for (nImages = numImages,
image = images;
allOK && nImages;
nImages--, image++) {
header = image->header;
for (i = 0, loadCmd = (struct load_command *)(header + 1);
allOK && i < header->ncmds;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
if (loadCmd->cmd == LC_SEGMENT) {
segCmd = (struct segment_command *)loadCmd;
if ((segCmd->fileoff + segCmd->vmsize) > image->size)
allOK = NO;
}
if (!loadCmd->cmdsize)
allOK = NO;
}
}
return allOK;
}
-(void)readInSegments
{
int nImages, i;
Image *image;
struct mach_header *header;
struct load_command *loadCmd;
struct segment_command *segCmd;
Segment *segment = relocs;
for (nImages = numImages,
image = images;
nImages;
nImages--, image++) {
header = image->header;
for (i = 0, loadCmd = (struct load_command *)(header + 1);
i < header->ncmds;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
if (loadCmd->cmd == LC_SEGMENT) {
segCmd = (struct segment_command *)loadCmd;
segment->address = segCmd->vmaddr + image->slide;
segment->size = segCmd->vmsize;
segment->data = (vm_address_t)header + segCmd->fileoff;
segment->maxAddress = segment->address + segment->size;
segment->displacement = segment->data - segment->address;
segment->maxData = segment->data + segment->size;
segment->segName = segCmd->segname;
segment->rFlags.readIn = YES;
((void *)segment) += relocSize;
}
}
}
}
-(void)_readInAllRelocs
{
numRelocs = [self numSegments];
relocs = calloc(numRelocs, relocSize);
[self readInSegments];
rmFlags.invalid = NO;
}
-(struct mach_header *)getMachHeader
{
if (numImages)
return images[0].header;
else
return NULL;
}
-(unsigned)getSlide
{
if (numImages)
return images[0].slide;
else
return 0;
}
-(int)getNumMachHeaders
{
return numImages;
}
-(struct mach_header **)getMachHeaders
{
struct mach_header **headers;
int headerIndex;
headers = malloc((numImages + 1) * sizeof(*headers));
for (headerIndex = 0; headerIndex < numImages; headerIndex++)
headers[headerIndex] = images[headerIndex].header;
headers[numImages] = NULL;
return headers;
}
-(unsigned*)getSlides
{
unsigned *slides;
int slideIndex;
slides = malloc((numImages + 1) * sizeof(*slides));
for (slideIndex = 0; slideIndex < numImages; slideIndex++)
slides[slideIndex] = images[slideIndex].slide;
slides[numImages] = 0;
return slides;
}
-(struct mach_header **)getMachHeadersWithNames: (char ***)names
{
struct mach_header **headers;
char **theNames;
int headerIndex;
headers = malloc((numImages + 1) * sizeof(*headers));
*names = theNames = malloc((numImages + 1) * sizeof(*theNames));
for (headerIndex = 0; headerIndex < numImages; headerIndex++) {
headers[headerIndex] = images[headerIndex].header;
theNames[headerIndex] = images[headerIndex].name;
}
headers[numImages] = NULL;
theNames[numImages] = NULL;
return headers;
}
-(unsigned *)getSlidesWithNames: (char ***)names
{
unsigned *slides;
char **theNames;
int slideIndex;
slides = malloc((numImages + 1) * sizeof(*slides));
*names = theNames = malloc((numImages + 1) * sizeof(*theNames));
for (slideIndex = 0; slideIndex < numImages; slideIndex++) {
slides[slideIndex] = images[slideIndex].slide;
theNames[slideIndex] = images[slideIndex].name;
}
slides[numImages] = 0;
theNames[numImages] = NULL;
return slides;
}
-(struct load_command *)findLoadCommand: (unsigned long)command
forHeader: (struct mach_header *)header
{
int i;
struct load_command *loadCmd, *foundCmd = NULL;
for (i = 0, loadCmd = (struct load_command *)(header + 1);
i < header->ncmds && !foundCmd;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
if (loadCmd->cmd == command)
foundCmd = loadCmd;
}
return foundCmd;
}
-(int)numCommands: (unsigned long)command
forHeader: (struct mach_header *)header
{
int i, nCommands = 0;
struct load_command *loadCmd;
for (i = 0, loadCmd = (struct load_command *)(header + 1);
i < header->ncmds;
i++, ((void *)loadCmd) += loadCmd->cmdsize) {
if (loadCmd->cmd == command)
nCommands++;
}
return nCommands;
}
-(struct symtab_command *)symCmd
{
return (struct symtab_command *)
[self findLoadCommand: LC_SYMTAB
forHeader: images[0].header];
}
-(struct dysymtab_command *)dysymCmd
{
return (struct dysymtab_command *)
[self findLoadCommand: LC_DYSYMTAB
forHeader: images[0].header];
}
-(char *)stringTable
{
struct symtab_command *symCmd = [self symCmd];
return (char *)(images[0].header) + symCmd->stroff;
}
-(struct nlist *)symbolTable
{
struct symtab_command *symCmd = [self symCmd];
return (struct nlist*)((char *)(images[0].header) + symCmd->symoff);
}
-(BOOL)isDylib
{
return images && images[0].header->filetype == MH_DYLIB;
}
-(BOOL)isCore
{
return images && images[0].header->filetype == MH_CORE;
}
-(BOOL)isShlib
{
return images && images[0].header->filetype == MH_FVMLIB;
}
-(BOOL)isExecutable
{
BOOL ret = images && ((images[0].header->filetype == MH_EXECUTE)
|| (images[0].header->filetype == MH_OBJECT)
|| (images[0].header->filetype == MH_PRELOAD));
// if (ret)
// printf("Is executable.\n");
// else
// printf("Isn't executable.\n");
return ret;
}
-(BOOL)isSymbolStub:(void*)pc
{
const struct section *sec;
sec = [self getSeg:"__TEXT" sect:"__picsymbol_stub"];
if (sec == 0)
sec = [self getSeg:"__TEXT" sect:"__symbol_stub"];
if (sec
&& pc >= (void *) ((char *) 0 + (sec->addr + [self getSlide]))
&& pc < (void *) ((char *) 0 + (sec->addr + [self getSlide]
+ sec->size)))
return 1;
else
return 0;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.