mirror of
https://github.com/darlinghq/cctools-port.git
synced 2024-11-26 21:50:26 +00:00
1003 lines
26 KiB
C
1003 lines
26 KiB
C
/*
|
|
* 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@
|
|
*/
|
|
#include <mach/mach.h> /* first so to get rid of a precomp warning */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <mach-o/loader.h>
|
|
#include <mach-o/nlist.h>
|
|
#include <mach-o/stab.h>
|
|
#include <mach-o/arch.h>
|
|
#include "stuff/bool.h"
|
|
#include "stuff/ofile.h"
|
|
#include "stuff/errors.h"
|
|
#include "stuff/allocate.h"
|
|
#include "stuff/guess_short_name.h"
|
|
char *progname = NULL;
|
|
|
|
static void nm(
|
|
struct ofile *ofile,
|
|
char *arch_name,
|
|
void *cookie);
|
|
|
|
static char * get_full_path(
|
|
char *short_name,
|
|
struct ofile *ofile);
|
|
|
|
/* Define the structures used by SymInfo */
|
|
typedef struct {
|
|
char *name;
|
|
const char *arch;
|
|
char *ordinal; /* for imports only */
|
|
}_SymInfoSymbol;
|
|
typedef _SymInfoSymbol *SymInfoSymbol;
|
|
|
|
typedef struct {
|
|
char **subUmbrellas;
|
|
char **subFrameworks;
|
|
unsigned int nSubFrameworks;
|
|
unsigned int nSubUmbrellas;
|
|
}_SymInfoDependencies;
|
|
typedef _SymInfoDependencies *SymInfoDependencies;
|
|
|
|
typedef struct {
|
|
SymInfoSymbol *exports;
|
|
SymInfoSymbol *imports;
|
|
SymInfoDependencies dependencies;
|
|
unsigned int nExports;
|
|
unsigned int nImports;
|
|
char *path;
|
|
char *shortName;
|
|
}_SymInfoList;
|
|
|
|
typedef _SymInfoList *SymInfoList;
|
|
#define __SymInfoTypes__
|
|
#include <cbt/libsyminfo.h>
|
|
|
|
|
|
/* flags to control the nm callback */
|
|
struct cmd_flags {
|
|
enum bool g; /* select only global symbols */
|
|
enum bool u; /* select only undefined symbols */
|
|
enum bool d; /* select only defined symbols, opposite of u */
|
|
enum bool getLibDeps; /* Get the library dependency info like
|
|
SUB_UMBRELLA, SUB_FRAMEWORK, etc */
|
|
enum bool import; /* Flag to identify were looking for imported symbols
|
|
data */
|
|
};
|
|
|
|
/* flags set by processing a specific object file */
|
|
struct process_flags {
|
|
uint32_t nlibs; /* For printing the twolevel namespace */
|
|
char **lib_names; /* references types, the number of libraries */
|
|
/* an array of pointers to library names */
|
|
};
|
|
|
|
/* the internal symbol structure used in this file */
|
|
struct symbol {
|
|
char *name;
|
|
char *indr_name;
|
|
struct nlist_64 nl;
|
|
};
|
|
|
|
static void set_symbol_names(
|
|
struct symbol *symbols,
|
|
uint32_t nsymbols,
|
|
char *strings,
|
|
uint32_t strsize);
|
|
static enum bool select_symbol(
|
|
struct symbol *symbol,
|
|
struct cmd_flags *cmd_flags,
|
|
struct process_flags *process_flags);
|
|
static void make_symbol_32(struct symbol *symbol,
|
|
struct nlist *nl);
|
|
static void make_symbol_32(
|
|
struct symbol *symbol,
|
|
struct nlist *nl);
|
|
static void make_symbol_64(
|
|
struct symbol *symbol,
|
|
struct nlist_64 *nl);
|
|
static struct symbol *select_symbols(
|
|
struct ofile *ofile,
|
|
struct symtab_command *st,
|
|
struct dysymtab_command *dyst,
|
|
struct cmd_flags *cmd_flags,
|
|
struct process_flags *process_flags,
|
|
uint32_t *nsymbols,
|
|
struct nlist *all_symbols,
|
|
struct nlist_64 *all_symbols64);
|
|
|
|
/*
|
|
* Super hack so values can get passed back from the nm callback.
|
|
* The only other way I see to do this is to copy in the ofile_process code
|
|
* and edit it to return a value but that wouldn't work to well. This is
|
|
* ugly but effective.
|
|
*/
|
|
struct selectedSymbolListInfo {
|
|
vm_size_t mappedFileSize;
|
|
void *mappedFile;
|
|
char *cachedFileName;
|
|
int byteSex;
|
|
struct nlist *all_symbols;
|
|
struct nlist_64 *all_symbols64;
|
|
struct symtab_command *st;
|
|
};
|
|
static struct selectedSymbolListInfo *gInfo;
|
|
static SymInfoList self;
|
|
|
|
SymInfoList
|
|
SymInfoCreate(
|
|
char *fileName)
|
|
{
|
|
SymInfoList rList;
|
|
struct cmd_flags cmd_flags = { 0 };
|
|
kern_return_t r;
|
|
|
|
/* Allocate return value and point the global pointer self at it */
|
|
rList = malloc(sizeof(_SymInfoList));
|
|
bzero(rList, sizeof(_SymInfoList));
|
|
if(rList == NULL)
|
|
return(rList);
|
|
self = rList;
|
|
gInfo = allocate(sizeof(struct selectedSymbolListInfo));
|
|
bzero(gInfo,sizeof(struct selectedSymbolListInfo));
|
|
|
|
/*
|
|
* We want to process all the ofiles possible for this file.
|
|
* The cmd_flags are set in nm depending on what is being accomplished.
|
|
*/
|
|
ofile_process(fileName, /* name */
|
|
NULL, /* arch_flags */
|
|
0, /* narch_flags */
|
|
TRUE, /* all_archs */
|
|
FALSE, /* process_non_objects */
|
|
FALSE, /* dylib_flat */
|
|
TRUE, /* use_member_syntax */
|
|
nm, /* processor */
|
|
&cmd_flags); /* cookie */
|
|
|
|
/* Clean up */
|
|
if((r = vm_deallocate(mach_task_self(), (vm_address_t)gInfo->mappedFile,
|
|
(vm_size_t)gInfo->mappedFileSize)) != KERN_SUCCESS){
|
|
my_mach_error(r, "Can't vm_deallocate mapped memory for file: "
|
|
"%s",fileName);
|
|
}
|
|
free(gInfo->cachedFileName);
|
|
return(rList);
|
|
}
|
|
|
|
void
|
|
SymInfoFreeSymbol(
|
|
SymInfoSymbol symbol)
|
|
{
|
|
if(symbol == NULL){
|
|
printf("Null symbol, not doing a thing\n");
|
|
return;
|
|
}
|
|
if(symbol->name)
|
|
free(symbol->name);
|
|
if(symbol->ordinal)
|
|
free(symbol->ordinal);
|
|
if(symbol->arch)
|
|
free((char *)symbol->arch);
|
|
if(symbol)
|
|
free(symbol);
|
|
}
|
|
|
|
void
|
|
SymInfoFree(
|
|
SymInfoList nmList)
|
|
{
|
|
uint32_t i;
|
|
|
|
if(nmList == NULL)
|
|
return;
|
|
|
|
/* Free the Symbols */
|
|
for(i = 0; i < nmList->nExports; i++)
|
|
SymInfoFreeSymbol(nmList->exports[i]);
|
|
if(nmList->exports)
|
|
free(nmList->exports);
|
|
for(i = 0; i < nmList->nImports; i++)
|
|
SymInfoFreeSymbol(nmList->imports[i]);
|
|
if(nmList->imports)
|
|
free(nmList->imports);
|
|
|
|
/* Free the Dependencies */
|
|
SymInfoFreeDependencies(nmList->dependencies);
|
|
|
|
/* Free the rest */
|
|
if(nmList->path)
|
|
free(nmList->path);
|
|
|
|
if(nmList->shortName)
|
|
free(nmList->shortName);
|
|
if(nmList)
|
|
free(nmList);
|
|
if(gInfo)
|
|
free(gInfo);
|
|
}
|
|
|
|
void
|
|
SymInfoFreeDependencies(
|
|
SymInfoDependencies deps)
|
|
{
|
|
uint32_t i;
|
|
|
|
if(deps == NULL)
|
|
return;
|
|
|
|
/* Free the subumbrellas */
|
|
for(i = 0; i < deps->nSubUmbrellas; i++){
|
|
if(deps->subUmbrellas[i])
|
|
free(deps->subUmbrellas[i]);
|
|
}
|
|
if(deps->subUmbrellas)
|
|
free(deps->subUmbrellas);
|
|
|
|
/* Free the subFrameworks */
|
|
for(i = 0; i < deps->nSubFrameworks; i++){
|
|
if(deps->subFrameworks[i])
|
|
free(deps->subFrameworks[i]);
|
|
}
|
|
if(deps->subFrameworks)
|
|
free(deps->subFrameworks);
|
|
free(deps);
|
|
}
|
|
|
|
/* Access functions */
|
|
SymInfoSymbol *
|
|
SymInfoGetImports(
|
|
SymInfoList nmList)
|
|
{
|
|
if(nmList == NULL)
|
|
return(NULL);
|
|
return(nmList->imports);
|
|
}
|
|
|
|
SymInfoSymbol *
|
|
SymInfoGetExports(
|
|
SymInfoList nmList)
|
|
{
|
|
if(nmList == NULL)
|
|
return(NULL);
|
|
return(nmList->exports);
|
|
}
|
|
|
|
SymInfoDependencies
|
|
SymInfoGetLibraryInfo(
|
|
SymInfoList nmList)
|
|
{
|
|
if(nmList == NULL)
|
|
return(NULL);
|
|
return(nmList->dependencies);
|
|
}
|
|
|
|
unsigned int
|
|
SymInfoGetSubFrameworkCount(
|
|
SymInfoDependencies deps)
|
|
{
|
|
if(deps == NULL)
|
|
return(0);
|
|
return(deps->nSubFrameworks);
|
|
}
|
|
|
|
unsigned int
|
|
SymInfoGetSubUmbrellaCount(
|
|
SymInfoDependencies deps)
|
|
{
|
|
if(deps == NULL)
|
|
return(0);
|
|
return(deps->nSubUmbrellas);
|
|
}
|
|
|
|
char **
|
|
SymInfoGetSubUmbrellas(
|
|
SymInfoDependencies deps)
|
|
{
|
|
if(deps == NULL)
|
|
return(NULL);
|
|
return(deps->subUmbrellas);
|
|
}
|
|
|
|
char **
|
|
SymInfoGetSubFrameworks(
|
|
SymInfoDependencies deps)
|
|
{
|
|
if(deps == NULL)
|
|
return(NULL);
|
|
return(deps->subFrameworks);
|
|
}
|
|
|
|
char *
|
|
SymInfoGetSymbolName(
|
|
SymInfoSymbol symbol)
|
|
{
|
|
if(symbol == NULL)
|
|
return(NULL);
|
|
return(symbol->name);
|
|
}
|
|
|
|
const char *
|
|
SymInfoGetSymbolArch(
|
|
SymInfoSymbol symbol)
|
|
{
|
|
if(symbol == NULL)
|
|
return(NULL);
|
|
return(symbol->arch);
|
|
}
|
|
|
|
char *
|
|
SymInfoGetSymbolOrdinal(
|
|
SymInfoSymbol symbol)
|
|
{
|
|
if(symbol == NULL)
|
|
return(NULL);
|
|
return(symbol->ordinal);
|
|
}
|
|
|
|
unsigned int
|
|
SymInfoGetExportCount(
|
|
SymInfoList nmList)
|
|
{
|
|
if(nmList == NULL)
|
|
return(0);
|
|
return(nmList->nExports);
|
|
}
|
|
|
|
unsigned int
|
|
SymInfoGetImportCount(
|
|
SymInfoList nmList)
|
|
{
|
|
if(nmList == NULL)
|
|
return(0);
|
|
return(nmList->nImports);
|
|
}
|
|
|
|
char *
|
|
SymInfoGetShortName(
|
|
SymInfoList nmList)
|
|
{
|
|
if(nmList == NULL)
|
|
return(NULL);
|
|
return(nmList->shortName);
|
|
}
|
|
|
|
/* Function for creating SymInfoSymbol */
|
|
SymInfoSymbol
|
|
SymInfoCreateSymbols(
|
|
char *name,
|
|
char *arch,
|
|
char *ordinal)
|
|
{
|
|
SymInfoSymbol symbol;
|
|
symbol = malloc(sizeof(_SymInfoSymbol));
|
|
symbol->name = name;
|
|
symbol->arch = arch;
|
|
symbol->ordinal = ordinal;
|
|
return(symbol);
|
|
}
|
|
|
|
SymInfoDependencies
|
|
SymInfoCreateDependencies(
|
|
char **subUmbrellas,
|
|
char **subFrameworks,
|
|
int nSubUmbrellas,
|
|
int nSubFrameworks)
|
|
{
|
|
SymInfoDependencies deps;
|
|
|
|
deps = malloc(sizeof(_SymInfoDependencies));
|
|
bzero(deps,sizeof(_SymInfoDependencies));
|
|
deps->subUmbrellas = subUmbrellas;
|
|
deps->subFrameworks = subFrameworks;
|
|
deps->nSubUmbrellas = nSubUmbrellas;
|
|
deps->nSubFrameworks = nSubFrameworks;
|
|
return(deps);
|
|
}
|
|
|
|
/*
|
|
* nm() is the processor routine that will extract export and import info as
|
|
* well as the library information.
|
|
*/
|
|
static
|
|
void
|
|
nm(
|
|
struct ofile *ofile,
|
|
char *arch_name,
|
|
void *cookie)
|
|
{
|
|
struct cmd_flags *cmd_flags;
|
|
struct process_flags process_flags;
|
|
uint32_t i, j;
|
|
struct load_command *lc;
|
|
struct symtab_command *st;
|
|
struct dysymtab_command *dyst;
|
|
struct dylib_command *dl;
|
|
uint32_t library_ordinal;
|
|
uint32_t strsize = 0;
|
|
char *strings = NULL;
|
|
struct symbol *symbols = NULL;
|
|
uint32_t nsymbols;
|
|
uint32_t nlibnames = 0;
|
|
char *short_name, *has_suffix;
|
|
enum bool is_framework;
|
|
int symbolIndex;
|
|
struct nlist *all_symbols;
|
|
struct nlist_64 *all_symbols64;
|
|
struct dylib_module m;
|
|
struct dylib_module_64 m64;
|
|
struct dylib_reference *refs;
|
|
uint32_t ncmds, mh_flags;
|
|
|
|
cmd_flags = (struct cmd_flags *)cookie;
|
|
process_flags.nlibs = 0;
|
|
process_flags.lib_names = NULL;
|
|
|
|
if(ofile->mh != NULL){
|
|
ncmds = ofile->mh->ncmds;
|
|
mh_flags = ofile->mh->flags;
|
|
}
|
|
else{
|
|
ncmds = ofile->mh64->ncmds;
|
|
mh_flags = ofile->mh64->flags;
|
|
}
|
|
st = NULL;
|
|
dyst = NULL;
|
|
lc = ofile->load_commands;
|
|
for(i = 0; i < ncmds; i++){
|
|
if(st == NULL && lc->cmd == LC_SYMTAB){
|
|
st = (struct symtab_command *)lc;
|
|
}
|
|
else if(dyst == NULL && lc->cmd == LC_DYSYMTAB){
|
|
dyst = (struct dysymtab_command *)lc;
|
|
}
|
|
else if((mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL &&
|
|
(lc->cmd == LC_LOAD_DYLIB ||
|
|
lc->cmd == LC_LOAD_WEAK_DYLIB ||
|
|
lc->cmd == LC_REEXPORT_DYLIB ||
|
|
lc->cmd == LC_LOAD_UPWARD_DYLIB)){
|
|
process_flags.nlibs++;
|
|
}
|
|
lc = (struct load_command *)((char *)lc + lc->cmdsize);
|
|
}
|
|
if(st == NULL || st->nsyms == 0){
|
|
/* If there is no name list we don't really care */
|
|
return;
|
|
}
|
|
if((mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL &&
|
|
process_flags.nlibs > 0){
|
|
process_flags.lib_names = (char **)
|
|
malloc(sizeof(char *) * process_flags.nlibs);
|
|
j = 0;
|
|
lc = ofile->load_commands;
|
|
for(i = 0; i < ncmds; i++){
|
|
if(lc->cmd == LC_LOAD_DYLIB ||
|
|
lc->cmd == LC_LOAD_WEAK_DYLIB ||
|
|
lc->cmd == LC_REEXPORT_DYLIB ||
|
|
lc->cmd == LC_LOAD_UPWARD_DYLIB){
|
|
dl = (struct dylib_command *)lc;
|
|
process_flags.lib_names[j] =
|
|
savestr((char *)dl + dl->dylib.name.offset);
|
|
short_name = guess_short_name(process_flags.lib_names[j],
|
|
&is_framework, &has_suffix);
|
|
if(has_suffix)
|
|
free(has_suffix);
|
|
|
|
if(short_name != NULL)
|
|
process_flags.lib_names[j] = short_name;
|
|
j++;
|
|
}
|
|
lc = (struct load_command *)((char *)lc + lc->cmdsize);
|
|
}
|
|
nlibnames = j;
|
|
}
|
|
/* Correct the endianness of this ofile */
|
|
if(ofile->mh != NULL){
|
|
all_symbols = (struct nlist *)(ofile->object_addr + st->symoff);
|
|
all_symbols64 = NULL;
|
|
}
|
|
else{
|
|
all_symbols = NULL;
|
|
all_symbols64 = (struct nlist_64 *)(ofile->object_addr +st->symoff);
|
|
}
|
|
|
|
if(ofile->object_byte_sex != get_host_byte_sex()){
|
|
/*
|
|
* Cache the symbols whose endianness has been flipped so it doesn't
|
|
* have to be done again
|
|
*/
|
|
if(gInfo->cachedFileName &&
|
|
(strcmp(gInfo->cachedFileName,ofile->file_name) == 0) &&
|
|
gInfo->byteSex == (int)ofile->object_byte_sex &&
|
|
st->symoff == gInfo->st->symoff &&
|
|
st->nsyms == gInfo->st->nsyms &&
|
|
st->stroff == gInfo->st->stroff &&
|
|
st->strsize == gInfo->st->strsize){
|
|
all_symbols = gInfo->all_symbols;
|
|
all_symbols64 = gInfo->all_symbols64;
|
|
}
|
|
else{
|
|
if(ofile->mh != NULL)
|
|
swap_nlist(all_symbols, st->nsyms, get_host_byte_sex());
|
|
else
|
|
swap_nlist_64(all_symbols64, st->nsyms,get_host_byte_sex());
|
|
gInfo->byteSex = ofile->object_byte_sex;
|
|
if(gInfo->cachedFileName){
|
|
free(gInfo->cachedFileName);
|
|
gInfo->cachedFileName = NULL;
|
|
}
|
|
gInfo->cachedFileName = savestr(ofile->file_name);
|
|
gInfo->all_symbols = all_symbols;
|
|
gInfo->all_symbols64 = all_symbols64;
|
|
gInfo->st = st;
|
|
}
|
|
}
|
|
if(ofile->dylib_module != NULL){
|
|
m = *ofile->dylib_module;
|
|
refs = (struct dylib_reference *)(ofile->object_addr +
|
|
dyst->extrefsymoff);
|
|
if(ofile->object_byte_sex != get_host_byte_sex()){
|
|
swap_dylib_module(&m, 1, get_host_byte_sex());
|
|
swap_dylib_reference(refs + m.irefsym, m.nrefsym,
|
|
get_host_byte_sex());
|
|
}
|
|
}
|
|
else if(ofile->dylib_module64 != NULL){
|
|
m64 = *ofile->dylib_module64;
|
|
refs = (struct dylib_reference *)(ofile->object_addr +
|
|
dyst->extrefsymoff);
|
|
if(ofile->object_byte_sex != get_host_byte_sex()){
|
|
swap_dylib_module_64(&m64, 1, get_host_byte_sex());
|
|
swap_dylib_reference(refs + m64.irefsym, m64.nrefsym,
|
|
get_host_byte_sex());
|
|
}
|
|
}
|
|
|
|
/* select export symbols to return */
|
|
cmd_flags->g = TRUE;
|
|
cmd_flags->d = TRUE;
|
|
symbols = select_symbols(ofile, st, dyst, cmd_flags, &process_flags,
|
|
&nsymbols, all_symbols, all_symbols64);
|
|
strings = ofile->object_addr + st->stroff;
|
|
strsize = st->strsize;
|
|
set_symbol_names(symbols, nsymbols, strings, strsize);
|
|
|
|
self->nExports += nsymbols;
|
|
|
|
/* Store all this info so that it can be cleaned up later */
|
|
gInfo->mappedFile = ofile->file_addr;
|
|
gInfo->mappedFileSize = ofile->file_size;
|
|
|
|
/* Reallocate the array of SymInfoSymbol export structs in self */
|
|
self->exports = reallocate(self->exports,
|
|
sizeof(SymInfoSymbol *) * self->nExports);
|
|
|
|
/*
|
|
* Loop through saving the symbol information in SymInfoSymbol structs.
|
|
*/
|
|
for(i = self->nExports - nsymbols; i < self->nExports; i++){
|
|
const NXArchInfo *archInfo;
|
|
symbolIndex = i - (self->nExports - nsymbols);
|
|
self->exports[i] = malloc(sizeof(_SymInfoSymbol));
|
|
|
|
/* Save the symbol info */
|
|
archInfo = NXGetArchInfoFromCpuType(ofile->mh_cputype,
|
|
CPU_SUBTYPE_MULTIPLE);
|
|
self->exports[i]->name = savestr(symbols[symbolIndex].name);
|
|
/* If we don't know the arch name use the number */
|
|
if(archInfo == NULL){
|
|
char archString[10];
|
|
sprintf(archString, "%d", ofile->mh_cputype);
|
|
self->exports[i]->arch = savestr(archString);
|
|
}
|
|
else{
|
|
self->exports[i]->arch = savestr(archInfo->name);
|
|
}
|
|
self->exports[i]->ordinal = NULL;
|
|
}
|
|
free(symbols);
|
|
|
|
/* Unset the cmd_flags used to find exports */
|
|
cmd_flags->d = FALSE;
|
|
|
|
/* Set up the flags to get the symbol info for the imports */
|
|
cmd_flags->g = TRUE;
|
|
cmd_flags->u = TRUE;
|
|
cmd_flags->import = TRUE;
|
|
|
|
symbols = select_symbols(ofile, st, dyst, cmd_flags, &process_flags,
|
|
&nsymbols, all_symbols, all_symbols64);
|
|
strings = ofile->object_addr + st->stroff;
|
|
strsize = st->strsize;
|
|
set_symbol_names(symbols, nsymbols, strings, strsize);
|
|
|
|
self->nImports += nsymbols;
|
|
|
|
/* Reallocate the array of SymInfoSymbol imports structs in self */
|
|
self->imports = reallocate(self->imports,
|
|
sizeof(SymInfoSymbol *) * self->nImports);
|
|
|
|
/*
|
|
* Loop through saving the symbol information in SymInfoSymbol structs.
|
|
*/
|
|
for(i = self->nImports - nsymbols; i < self->nImports; i++){
|
|
const NXArchInfo *archInfo;
|
|
symbolIndex = i - (self->nImports - nsymbols);
|
|
self->imports[i] = malloc(sizeof(_SymInfoSymbol));
|
|
archInfo = NXGetArchInfoFromCpuType(ofile->mh_cputype,
|
|
CPU_SUBTYPE_MULTIPLE);
|
|
|
|
/* Save the name and arch */
|
|
self->imports[i]->name = savestr(symbols[symbolIndex].name);
|
|
if(archInfo == NULL){
|
|
char archString[10];
|
|
sprintf(archString, "%d", ofile->mh_cputype);
|
|
self->imports[i]->arch = savestr(archString);
|
|
}
|
|
else{
|
|
self->imports[i]->arch = savestr(archInfo->name);
|
|
}
|
|
|
|
/* Now extract the ordinal info and save the short library name */
|
|
library_ordinal =
|
|
GET_LIBRARY_ORDINAL(symbols[symbolIndex].nl.n_desc);
|
|
if(library_ordinal != 0){
|
|
if(library_ordinal == EXECUTABLE_ORDINAL)
|
|
self->imports[i]->ordinal = savestr("from executable");
|
|
else if(library_ordinal == DYNAMIC_LOOKUP_ORDINAL)
|
|
self->imports[i]->ordinal =savestr("dynamically looked up");
|
|
else if(library_ordinal-1 >= process_flags.nlibs)
|
|
self->imports[i]->ordinal = savestr("bad library ordinal");
|
|
else
|
|
/* Find the full path to the library */
|
|
self->imports[i]->ordinal =
|
|
get_full_path(process_flags.lib_names[library_ordinal-1],
|
|
ofile);
|
|
}
|
|
else{
|
|
self->imports[i]->ordinal = NULL;
|
|
}
|
|
}
|
|
free(symbols);
|
|
|
|
cmd_flags->g = FALSE;
|
|
cmd_flags->u = FALSE;
|
|
cmd_flags->import = FALSE;
|
|
|
|
/* Now get the dependency information from the load commands */
|
|
if(self->dependencies == NULL){
|
|
/* Allocate the memory */
|
|
self->dependencies = malloc(sizeof(_SymInfoDependencies));
|
|
bzero(self->dependencies, sizeof(_SymInfoDependencies));
|
|
lc = ofile->load_commands;
|
|
|
|
/* Now get the dependency info */
|
|
for(j = 0; j < ncmds; j++){
|
|
char *p;
|
|
if(lc->cmd == LC_SUB_UMBRELLA || lc->cmd == LC_SUB_LIBRARY){
|
|
struct sub_umbrella_command *usub = (struct sub_umbrella_command *)lc;
|
|
p = (char *)lc + usub->sub_umbrella.offset;
|
|
self->dependencies->subUmbrellas =
|
|
reallocate(self->dependencies->subUmbrellas,
|
|
(self->dependencies->nSubUmbrellas+1)*
|
|
sizeof(char **));
|
|
self->dependencies ->
|
|
subUmbrellas[self->dependencies->nSubUmbrellas] =
|
|
savestr(p);
|
|
self->dependencies->nSubUmbrellas++;
|
|
}
|
|
else if(lc->cmd == LC_SUB_FRAMEWORK){
|
|
struct sub_framework_command *subFramework = (struct sub_framework_command *)lc;
|
|
p = (char *)lc + subFramework->umbrella.offset;
|
|
self->dependencies-> subFrameworks =
|
|
reallocate(self->dependencies->subFrameworks,
|
|
(self->dependencies->nSubFrameworks+1) *
|
|
sizeof(char **));
|
|
self->dependencies->
|
|
subFrameworks[self->dependencies->nSubFrameworks] =
|
|
savestr(p);
|
|
self->dependencies->nSubFrameworks++;
|
|
}
|
|
lc = (struct load_command *)((char *)lc + lc->cmdsize);
|
|
}
|
|
|
|
/*
|
|
* Save the short name for this binary, to be used
|
|
* to map short name to full path
|
|
*/
|
|
short_name =
|
|
guess_short_name(ofile->file_name, &is_framework, &has_suffix);
|
|
if(has_suffix)
|
|
free(has_suffix);
|
|
if(short_name){
|
|
self->shortName = short_name;
|
|
}
|
|
}
|
|
|
|
/* Free the memory that was malloced in this function */
|
|
for(i = 0; i < process_flags.nlibs; i++)
|
|
free(process_flags.lib_names[i]);
|
|
if(process_flags.lib_names)
|
|
free(process_flags.lib_names);
|
|
if(ofile->arch_flag.name != NULL) {
|
|
free(ofile->arch_flag.name);
|
|
ofile->arch_flag.name = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* set_symbol_names() sets the name and the indr_name fields of the symbols
|
|
* passed to it from the symbol table pass to it.
|
|
*/
|
|
static
|
|
void
|
|
set_symbol_names(
|
|
struct symbol *symbols,
|
|
uint32_t nsymbols,
|
|
char *strings,
|
|
uint32_t strsize)
|
|
{
|
|
uint32_t i;
|
|
|
|
for(i = 0; i < nsymbols; i++){
|
|
if(symbols[i].nl.n_un.n_strx == 0)
|
|
symbols[i].name = "";
|
|
else if((int)symbols[i].nl.n_un.n_strx < -1 ||
|
|
(uint32_t)symbols[i].nl.n_un.n_strx > strsize){
|
|
symbols[i].name = "bad string index";
|
|
printf ("Setting bad string index in exports\n");
|
|
}
|
|
else
|
|
symbols[i].name = strings + symbols[i].nl.n_un.n_strx;
|
|
if((symbols[i].nl.n_type & N_TYPE) == N_INDR){
|
|
if(symbols[i].nl.n_value == 0)
|
|
symbols[i].indr_name = "";
|
|
else if(symbols[i].nl.n_value > strsize){
|
|
symbols[i].indr_name = "bad string index";
|
|
printf ("Setting bad string index in exports2\n");
|
|
}
|
|
else
|
|
symbols[i].indr_name = strings + symbols[i].nl.n_value;
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
char *
|
|
get_full_path(
|
|
char *short_name,
|
|
struct ofile *ofile)
|
|
{
|
|
uint32_t j;
|
|
struct dylib_command *dl;
|
|
struct load_command *lc;
|
|
char *has_suffix;
|
|
enum bool is_framework;
|
|
uint32_t ncmds;
|
|
|
|
lc = ofile->load_commands;
|
|
if(ofile->mh != NULL)
|
|
ncmds = ofile->mh->ncmds;
|
|
else
|
|
ncmds = ofile->mh64->ncmds;
|
|
|
|
for(j = 0; j < ncmds; j++) {
|
|
if(lc->cmd == LC_LOAD_DYLIB ||
|
|
lc->cmd == LC_LOAD_WEAK_DYLIB ||
|
|
lc->cmd == LC_REEXPORT_DYLIB ||
|
|
lc->cmd == LC_LOAD_UPWARD_DYLIB){
|
|
char *longName;
|
|
char *shortName;
|
|
char *returnLongName;
|
|
dl = (struct dylib_command *)lc;
|
|
longName = (char *)lc + dl->dylib.name.offset;
|
|
shortName = guess_short_name(longName, &is_framework,
|
|
&has_suffix);
|
|
if(shortName && strcmp(shortName, short_name) == 0){
|
|
free(shortName);
|
|
returnLongName = malloc(strlen(longName) + 2);
|
|
returnLongName[0] = '.';
|
|
returnLongName[1] = '\0';
|
|
strcat(returnLongName, longName);
|
|
return(returnLongName);
|
|
}
|
|
}
|
|
lc = (struct load_command *)((char *)lc + lc->cmdsize);
|
|
}
|
|
/*
|
|
fprintf(stderr,
|
|
"WARNING: Couldn't find full path for: %s\n", short_name);
|
|
*/
|
|
|
|
return(savestr(short_name));
|
|
}
|
|
|
|
static
|
|
struct symbol *
|
|
select_symbols(
|
|
struct ofile *ofile,
|
|
struct symtab_command *st,
|
|
struct dysymtab_command *dyst,
|
|
struct cmd_flags *cmd_flags,
|
|
struct process_flags *process_flags,
|
|
uint32_t *nsymbols,
|
|
struct nlist *all_symbols,
|
|
struct nlist_64 *all_symbols64)
|
|
{
|
|
uint32_t i, flags;
|
|
struct symbol *selected_symbols, symbol;
|
|
struct dylib_module m;
|
|
struct dylib_module_64 m64;
|
|
struct dylib_reference *refs;
|
|
uint32_t irefsym, nrefsym, nextdefsym, iextdefsym, nlocalsym, ilocalsym;
|
|
|
|
selected_symbols = allocate(sizeof(struct symbol) * st->nsyms);
|
|
*nsymbols = 0;
|
|
|
|
if(ofile->dylib_module != NULL){
|
|
if(ofile->mh != NULL){
|
|
m = *ofile->dylib_module;
|
|
if(ofile->object_byte_sex != get_host_byte_sex())
|
|
swap_dylib_module(&m, 1, get_host_byte_sex());
|
|
irefsym = m.irefsym;
|
|
nrefsym = m.nrefsym;
|
|
nextdefsym = m.nextdefsym;
|
|
iextdefsym = m.iextdefsym;
|
|
nlocalsym = m.nlocalsym;
|
|
ilocalsym = m.ilocalsym;
|
|
}
|
|
else{
|
|
m64 = *ofile->dylib_module64;
|
|
if(ofile->object_byte_sex != get_host_byte_sex())
|
|
swap_dylib_module_64(&m64, 1, get_host_byte_sex());
|
|
irefsym = m64.irefsym;
|
|
nrefsym = m64.nrefsym;
|
|
nextdefsym = m64.nextdefsym;
|
|
iextdefsym = m64.iextdefsym;
|
|
nlocalsym = m64.nlocalsym;
|
|
ilocalsym = m64.ilocalsym;
|
|
}
|
|
refs = (struct dylib_reference *)(ofile->object_addr +
|
|
dyst->extrefsymoff);
|
|
for(i = 0; i < nrefsym; i++){
|
|
flags = refs[i + irefsym].flags;
|
|
if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
|
|
flags == REFERENCE_FLAG_UNDEFINED_LAZY ||
|
|
flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
|
|
flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
|
|
if(ofile->mh != NULL)
|
|
make_symbol_32(&symbol,
|
|
all_symbols + refs[i + irefsym].isym);
|
|
else
|
|
make_symbol_64(&symbol,
|
|
all_symbols64 + refs[i + irefsym].isym);
|
|
if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
|
|
flags == REFERENCE_FLAG_UNDEFINED_LAZY)
|
|
symbol.nl.n_type = N_UNDF | N_EXT;
|
|
else
|
|
symbol.nl.n_type = N_UNDF;
|
|
symbol.nl.n_desc = (symbol.nl.n_desc &~ REFERENCE_TYPE) |
|
|
flags;
|
|
symbol.nl.n_value = 0;
|
|
if(select_symbol(&symbol, cmd_flags, process_flags))
|
|
selected_symbols[(*nsymbols)++] = symbol;
|
|
}
|
|
}
|
|
for(i = 0; i < nextdefsym && iextdefsym + i < st->nsyms; i++){
|
|
if(ofile->mh != NULL)
|
|
make_symbol_32(&symbol, all_symbols + iextdefsym + i);
|
|
else
|
|
make_symbol_64(&symbol, all_symbols64 + iextdefsym + i);
|
|
if(select_symbol(&symbol, cmd_flags, process_flags))
|
|
selected_symbols[(*nsymbols)++] = symbol;
|
|
}
|
|
for(i = 0; i < nlocalsym && ilocalsym + i < st->nsyms; i++){
|
|
if(ofile->mh != NULL)
|
|
make_symbol_32(&symbol, all_symbols + ilocalsym + i);
|
|
else
|
|
make_symbol_64(&symbol, all_symbols64 + ilocalsym + i);
|
|
if(select_symbol(&symbol, cmd_flags, process_flags))
|
|
selected_symbols[(*nsymbols)++] = symbol;
|
|
}
|
|
}
|
|
else{
|
|
for(i = 0; i < st->nsyms; i++){
|
|
if(ofile->mh != NULL)
|
|
make_symbol_32(&symbol, all_symbols + i);
|
|
else
|
|
make_symbol_64(&symbol, all_symbols64 + i);
|
|
if(select_symbol(&symbol, cmd_flags, process_flags))
|
|
selected_symbols[(*nsymbols)++] = symbol;
|
|
}
|
|
}
|
|
/*
|
|
* Could reallocate selected symbols to the exact size but it is more
|
|
* of a time waste than a memory savings.
|
|
*/
|
|
return(selected_symbols);
|
|
}
|
|
|
|
static
|
|
void
|
|
make_symbol_32(
|
|
struct symbol *symbol,
|
|
struct nlist *nl)
|
|
{
|
|
symbol->nl.n_un.n_strx = nl->n_un.n_strx;
|
|
symbol->nl.n_type = nl->n_type;
|
|
symbol->nl.n_sect = nl->n_sect;
|
|
symbol->nl.n_desc = nl->n_desc;
|
|
symbol->nl.n_value = nl->n_value;
|
|
}
|
|
|
|
static
|
|
void
|
|
make_symbol_64(
|
|
struct symbol *symbol,
|
|
struct nlist_64 *nl)
|
|
{
|
|
symbol->nl = *nl;
|
|
}
|
|
|
|
/*
|
|
* select_symbol() returns TRUE or FALSE if the specified symbol is to be
|
|
* select based on the flags.
|
|
*/
|
|
static
|
|
enum bool
|
|
select_symbol(
|
|
struct symbol *symbol,
|
|
struct cmd_flags *cmd_flags,
|
|
struct process_flags *process_flags)
|
|
{
|
|
if((cmd_flags->import == TRUE) &&
|
|
(process_flags->nlibs > 0) &&
|
|
GET_LIBRARY_ORDINAL(symbol->nl.n_desc) == 0)
|
|
return(FALSE);
|
|
|
|
if(cmd_flags->u == TRUE){
|
|
if((symbol->nl.n_type == (N_UNDF | N_EXT) &&
|
|
symbol->nl.n_value == 0) ||
|
|
symbol->nl.n_type == (N_PBUD | N_EXT))
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
if(cmd_flags->d == TRUE){
|
|
if((((symbol->nl.n_type & N_TYPE) != N_UNDF)
|
|
&& ((symbol->nl.n_type & N_EXT) != 0))
|
|
&& ((symbol->nl.n_type & N_TYPE) != N_PBUD))
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
if(cmd_flags->g == TRUE && (symbol->nl.n_type & N_EXT) == 0)
|
|
return(FALSE);
|
|
|
|
return(TRUE);
|
|
}
|