4
0
mirror of https://github.com/QuasarApp/macdependency.git synced 2025-05-11 02:39:34 +00:00

Add uuid, dylinker commands, file size > 32bit accepted, fix user home directory detection, add file type for kernel extension, some refactorings

This commit is contained in:
konrad_w 2011-04-24 19:31:31 +00:00
parent 56090db6ad
commit 0d586e75f0
22 changed files with 310 additions and 131 deletions

@ -264,7 +264,11 @@
};
buildConfigurationList = C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "MacDependency" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
en,
);
mainGroup = 2A37F4AAFDCFA73011CA2CEA /* MacDependency */;
projectDirPath = "";
projectReferences = (
@ -400,6 +404,7 @@
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_NAME = MacDependency;
SDKROOT = macosx10.6;
};
name = Debug;
};
@ -419,7 +424,7 @@
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_NAME = MacDependency;
SDKROOT = macosx10.5;
SDKROOT = macosx10.6;
};
name = Release;
};
@ -430,6 +435,7 @@
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_VERSION = "";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
@ -445,6 +451,7 @@
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.5;
ONLY_ACTIVE_ARCH = YES;
PREBINDING = NO;
SDKROOT = macosx10.5;
@ -456,8 +463,10 @@
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_VERSION = "";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.5;
PREBINDING = NO;
SDKROOT = macosx10.5;
};

@ -50,6 +50,10 @@
8E49393F100AA468004B7E53 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E49393E100AA468004B7E53 /* CoreFoundation.framework */; };
8E8C73E1106AA95D0037CF19 /* libboost_filesystem.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E8C73DF106AA95D0037CF19 /* libboost_filesystem.a */; };
8E8C73E2106AA95D0037CF19 /* libboost_system.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E8C73E0106AA95D0037CF19 /* libboost_system.a */; };
8EA3DFF411AFD3790093CD87 /* uuidcommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EA3DFF211AFD3790093CD87 /* uuidcommand.cpp */; };
8EA3DFF511AFD3790093CD87 /* uuidcommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EA3DFF311AFD3790093CD87 /* uuidcommand.h */; };
8EA3E17A11B12B5A0093CD87 /* dylinkercommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EA3E17811B12B5A0093CD87 /* dylinkercommand.cpp */; };
8EA3E17B11B12B5A0093CD87 /* dylinkercommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EA3E17911B12B5A0093CD87 /* dylinkercommand.h */; };
8ED32FDE100B99EC00EBF623 /* machocache.h in Headers */ = {isa = PBXBuildFile; fileRef = 8ED32FDC100B99EC00EBF623 /* machocache.h */; settings = {ATTRIBUTES = (Public, ); }; };
8ED32FDF100B99EC00EBF623 /* machocache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8ED32FDD100B99EC00EBF623 /* machocache.cpp */; };
/* End PBXBuildFile section */
@ -103,6 +107,10 @@
8E49393E100AA468004B7E53 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
8E8C73DF106AA95D0037CF19 /* libboost_filesystem.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libboost_filesystem.a; path = /usr/local/lib/static/libboost_filesystem.a; sourceTree = "<absolute>"; };
8E8C73E0106AA95D0037CF19 /* libboost_system.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libboost_system.a; path = /usr/local/lib/static/libboost_system.a; sourceTree = "<absolute>"; };
8EA3DFF211AFD3790093CD87 /* uuidcommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = uuidcommand.cpp; sourceTree = "<group>"; };
8EA3DFF311AFD3790093CD87 /* uuidcommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uuidcommand.h; sourceTree = "<group>"; };
8EA3E17811B12B5A0093CD87 /* dylinkercommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dylinkercommand.cpp; sourceTree = "<group>"; };
8EA3E17911B12B5A0093CD87 /* dylinkercommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dylinkercommand.h; sourceTree = "<group>"; };
8ED32FDC100B99EC00EBF623 /* machocache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = machocache.h; sourceTree = "<group>"; };
8ED32FDD100B99EC00EBF623 /* machocache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = machocache.cpp; sourceTree = "<group>"; };
D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
@ -163,6 +171,10 @@
08FB77AEFE84172EC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
8EA3E17811B12B5A0093CD87 /* dylinkercommand.cpp */,
8EA3E17911B12B5A0093CD87 /* dylinkercommand.h */,
8EA3DFF211AFD3790093CD87 /* uuidcommand.cpp */,
8EA3DFF311AFD3790093CD87 /* uuidcommand.h */,
8E131512100F7C6B00367510 /* demangler.cpp */,
8E131513100F7C6B00367510 /* demangler.h */,
8E131514100F7C6B00367510 /* dylibcommand.cpp */,
@ -264,6 +276,8 @@
8E131557100F7C6B00367510 /* symboltableentry32.h in Headers */,
8E131572100F7DB600367510 /* symboltableentry64.h in Headers */,
8E212E93101237A50078924A /* machodemangleexception.h in Headers */,
8EA3DFF511AFD3790093CD87 /* uuidcommand.h in Headers */,
8EA3E17B11B12B5A0093CD87 /* dylinkercommand.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -296,7 +310,11 @@
isa = PBXProject;
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "MachO" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
en,
);
mainGroup = 0867D691FE84028FC02AAC07 /* MachO */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
@ -343,6 +361,8 @@
8E131556100F7C6B00367510 /* symboltableentry32.cpp in Sources */,
8E131571100F7DB600367510 /* symboltableentry64.cpp in Sources */,
8E212E94101237A50078924A /* machodemangleexception.cpp in Sources */,
8EA3DFF411AFD3790093CD87 /* uuidcommand.cpp in Sources */,
8EA3E17A11B12B5A0093CD87 /* dylinkercommand.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -387,6 +407,7 @@
LIBRARY_SEARCH_PATHS = /usr/local/lib/static;
OTHER_LDFLAGS = "-Wl,-search_paths_first";
PRODUCT_NAME = MachO;
SDKROOT = macosx10.6;
WRAPPER_EXTENSION = framework;
};
name = Debug;
@ -409,6 +430,7 @@
LIBRARY_SEARCH_PATHS = /usr/local/lib/static;
OTHER_LDFLAGS = "-Wl,-search_paths_first";
PRODUCT_NAME = MachO;
SDKROOT = macosx10.6;
WRAPPER_EXTENSION = framework;
};
name = Release;
@ -419,6 +441,7 @@
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
DEPLOYMENT_LOCATION = NO;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
@ -433,7 +456,6 @@
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;

21
MachO/dylinkercommand.cpp Normal file

@ -0,0 +1,21 @@
#include "dylinkercommand.h"
#include "machofile.h"
#include "machoheader.h"
#include <sstream>
DylinkerCommand::DylinkerCommand(MachOHeader* header) :
LoadCommand(header) {
file.readBytes((char*)&command, sizeof(command));
}
DylinkerCommand::~DylinkerCommand() {
}
unsigned int DylinkerCommand::getSize() const {
return file.getUint32(command.cmdsize);
}
string DylinkerCommand::getName() const {
return string(getLcDataString(command.name.offset));
}

19
MachO/dylinkercommand.h Normal file

@ -0,0 +1,19 @@
#ifndef DYLINKERCOMMAND_H
#define DYLINKERCOMMAND_H
#include "macho_global.h"
#include "loadcommand.h"
class EXPORT DylinkerCommand : public LoadCommand
{
public:
DylinkerCommand(MachOHeader* header);
virtual ~DylinkerCommand();
virtual unsigned int getSize() const;
virtual unsigned int getStructureSize() const { return sizeof(command); }
string getName() const;
private:
dylinker_command command;
};
#endif // DYLINKERCOMMAND_H

@ -3,29 +3,31 @@
#include "machoarchitecture.h"
#include <boost/filesystem.hpp>
#include <pwd.h>
#include <stdlib.h>
/*
This class emulates the search path mechanism of dyld
http://developer.apple.com/documentation/Darwin/Reference/Manpages/man1/dyld.1.html
Unfortunately the several documents from apple contradict each other. Therefore I analyzed the source of the original dyld
http://www.opensource.apple.com/source/dyld/dyld-97.1/src/dyld.cpp
*/
This class emulates the search path mechanism of dyld
http://developer.apple.com/documentation/Darwin/Reference/Manpages/man1/dyld.1.html
Unfortunately the several documents from apple contradict each other. Therefore I analyzed the source of the original dyld
http://www.opensource.apple.com/source/dyld/dyld-97.1/src/dyld.cpp
*/
const char* DynamicLoader::EnvironmentPathVariable::PATHS_SEPARATOR = ";";
const char* DynamicLoader::EnvironmentPathVariable::HOME_PATH = getenv("HOME");
const char DynamicLoader::EnvironmentPathVariable::PATHS_SEPARATOR[] = ":";
DynamicLoader::EnvironmentPathVariable::EnvironmentPathVariable() {
// default constructor (should not be used explicitly)
// never call that explicitly
}
DynamicLoader::EnvironmentPathVariable::EnvironmentPathVariable(const string& name, const StringList& defaultValues)
DynamicLoader::EnvironmentPathVariable::EnvironmentPathVariable(const char* homePath, const string& name, const StringList& defaultValues)
{
this->homePath = homePath;
const char* envValue = getenv(name.c_str());
string values;
if (envValue) {
values = envValue;
}
if (!values.empty()) {
size_t start = 0;
size_t end;
@ -40,7 +42,7 @@ DynamicLoader::EnvironmentPathVariable::EnvironmentPathVariable(const string& na
void DynamicLoader::EnvironmentPathVariable::setPaths(const StringList& paths) {
this->paths = paths;
for (StringList::iterator it = this->paths.begin(); it!=this->paths.end(); ++it) {
replaceHomeDirectory(*it);
}
@ -52,12 +54,12 @@ void DynamicLoader::EnvironmentPathVariable::addPath(const string& path) {
}
bool DynamicLoader::EnvironmentPathVariable::replaceHomeDirectory(string& path) {
size_t homePos = path.find("~");
if (homePos != string::npos) {
path.replace(homePos, 1, HOME_PATH);
return true;
}
return false;
size_t homePos = path.find("~/");
if (homePos != string::npos) {
path.replace(homePos, 1, homePath);
return true;
}
return false;
}
bool DynamicLoader::EnvironmentPathVariable::isEmpty() const {
@ -86,10 +88,10 @@ const char* DynamicLoader::PLACEHOLDERS[DynamicLoader::NumPlaceholders] = {
const char* DynamicLoader::PATH_SEPARATOR = "/";
const char* DynamicLoader::DEFAULT_FRAMEWORK_PATH[] = {
"~/Library/Frameworks",
"/Library/Frameworks",
"/Network/Library/Frameworks",
"/System/Library/Frameworks"
"~/Library/Frameworks",
"/Library/Frameworks",
"/Network/Library/Frameworks",
"/System/Library/Frameworks"
};
const char* DynamicLoader::DEFAULT_LIBRARY_PATH[] = {
@ -111,9 +113,28 @@ const StringList DynamicLoader::ENVIRONMENT_VARIABLE_DEFAULT_VALUES[DynamicLoade
DynamicLoader::DynamicLoader()
{
homePath = strdup(getUserHomeDirectory());
// init/read out some variables
for (unsigned int i=0; i < NumEnvironmentVariables; i++) {
environmentVariables[i] = EnvironmentPathVariable(ENVIRONMENT_VARIABLE_NAMES[i], ENVIRONMENT_VARIABLE_DEFAULT_VALUES[i]);
environmentVariables[i] = EnvironmentPathVariable(homePath, ENVIRONMENT_VARIABLE_NAMES[i], ENVIRONMENT_VARIABLE_DEFAULT_VALUES[i]);
}
}
DynamicLoader::~DynamicLoader() {
free((void*)homePath);
}
const char* DynamicLoader::getUserHomeDirectory() const {
struct passwd* pwd = getpwuid(getuid());
if (pwd)
{
return pwd->pw_dir;
}
else
{
// try the $HOME environment variable
return getenv("HOME");
}
}
@ -123,8 +144,6 @@ string DynamicLoader::replacePlaceholder(const string& name, const MachOArchitec
resolvedName.replace(0, strlen(PLACEHOLDERS[ExecutablePath]), architecture->getFile()->getExecutablePath());
} else if (name.find(PLACEHOLDERS[LoaderPath]) == 0) {
resolvedName.replace(0, strlen(PLACEHOLDERS[LoaderPath]), architecture->getFile()->getPath());
} else {
return string();
}
return resolvedName;
}
@ -138,75 +157,73 @@ string DynamicLoader::getPathname(const string& name, const MachOArchitecture* a
} else {
simpleName = name;
}
// try LD_LIBRARY_PATH
string pathName;
pathName = getExistingPathname(simpleName, environmentVariables[LdLibraryPath]);
pathName = getExistingPathname(simpleName, environmentVariables[LdLibraryPath], workingPath);
if (!pathName.empty())
return pathName;
string frameworkName = getFrameworkName(name);
if (!frameworkName.empty()) {
// strip the already contained suffix
pathName = getExistingPathname(frameworkName, environmentVariables[DyldFrameworkPath]);
pathName = getExistingPathname(frameworkName, environmentVariables[DyldFrameworkPath], workingPath);
if (!pathName.empty())
return pathName;
}
pathName = getExistingPathname(simpleName, environmentVariables[DyldLibraryPath]);
pathName = getExistingPathname(simpleName, environmentVariables[DyldLibraryPath], workingPath);
if (!pathName.empty())
return pathName;
// resolve placeholder
string resolvedName = replacePlaceholder(name, architecture);
if (!resolvedName.empty()) {
pathName = getExistingPathname(resolvedName);
pathName = getExistingPathname(resolvedName, workingPath);
if (!pathName.empty())
return pathName;
}
if (name.find(PLACEHOLDERS[RPath]) == 0) {
if (name.find(PLACEHOLDERS[Rpath]) == 0) {
// substitute @rpath with all -rpath paths up the load chain
std::vector<string*> rPaths = architecture->getRPaths();
for (std::vector<string*>::iterator it = rPaths.begin(); it != rPaths.end(); ++it) {
std::vector<string*> rpaths = architecture->getRpaths();
for (std::vector<string*>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
// rpath may contain @loader_path or @executable_path
string rpath = replacePlaceholder((**it), architecture);
resolvedName = name;
resolvedName.replace(0, strlen(PLACEHOLDERS[RPath]), (**it));
pathName = getExistingPathname(resolvedName);
resolvedName.replace(0, strlen(PLACEHOLDERS[Rpath]), rpath);
pathName = getExistingPathname(resolvedName, workingPath);
if (!pathName.empty())
return pathName;
}
// after checking against all stored rpaths substitute @rpath with LD_LIBRARY_PATH (if it is set)
EnvironmentPathVariable ldLibraryPaths = environmentVariables[LdLibraryPath];
if (!ldLibraryPaths.isEmpty()) {
for (StringList::const_iterator it = ldLibraryPaths.getPaths().begin(); it != ldLibraryPaths.getPaths().end(); ++it) {
resolvedName = name;
resolvedName.replace(0, strlen(PLACEHOLDERS[RPath]), (*it));
pathName = getExistingPathname(resolvedName);
resolvedName.replace(0, strlen(PLACEHOLDERS[Rpath]), (*it));
pathName = getExistingPathname(resolvedName, workingPath);
if (!pathName.empty())
return pathName;
}
}
}
// check pure path (either absolute or relative to working directory)
if (name.find(PATH_SEPARATOR) == 0) {
pathName = getExistingPathname(name);
} else {
pathName = getExistingPathname(name, workingPath);
}
pathName = getExistingPathname(name, workingPath);
if (!pathName.empty())
return pathName;
// try fallbacks (or its defaults)
if (!frameworkName.empty()) {
pathName = getExistingPathname(frameworkName, environmentVariables[DyldFallbackFrameworkPath]);
pathName = getExistingPathname(frameworkName, environmentVariables[DyldFallbackFrameworkPath], workingPath);
if (!pathName.empty())
return pathName;
}
return getExistingPathname(name, environmentVariables[DyldFallbackLibraryPath]);
return getExistingPathname(name, environmentVariables[DyldFallbackLibraryPath], workingPath);
}
// returns the name is of a framework without any preceeding path information if name specifies a framework, otherwise an invalid string
@ -215,21 +232,21 @@ string DynamicLoader::getFrameworkName(const string& name, const bool strippedSu
if (name.find(".framework/") == string::npos) {
return string();
}
/* first look for the form Foo.framework/Foo
next look for the form Foo.framework/Versions/A/Foo
A and Foo are arbitrary strings without a slash */
next look for the form Foo.framework/Versions/A/Foo
A and Foo are arbitrary strings without a slash */
// get Foo (part after last slash)
size_t lastSlashPosition = name.rfind(PATH_SEPARATOR);
if (lastSlashPosition == string::npos || lastSlashPosition == name.length() -1) {
return false;
}
const string foo = name.substr(lastSlashPosition+1);
const string frameworkPart = foo+".framework/";
const string framework = frameworkPart + foo;
if (endsWith(name, framework)) {
// strip first part
return framework;
@ -257,18 +274,18 @@ string DynamicLoader::getFrameworkName(const string& name, const bool strippedSu
return string();
}
string DynamicLoader::getExistingPathname(const string& name, const EnvironmentPathVariable& environmentPathVariable) const {
string DynamicLoader::getExistingPathname(const string& name, const EnvironmentPathVariable& environmentPathVariable, const string& workingPath) const {
string result;
const StringList directories = environmentPathVariable.getPaths();
for (StringList::const_iterator it = directories.begin(); it != directories.end(); ++it) {
result = getExistingPathname(name, *it);
result = getExistingPathname(name, *it, workingPath);
if (!result.empty())
return result;
}
return result;
}
string DynamicLoader::getExistingPathname(const string& file, const string& directory) const {
string DynamicLoader::getExistingPathname(const string& file, const string& directory, const string& workingPath) const {
string name = file;
if (!directory.empty()) {
if (!endsWith(directory, "/")) {
@ -277,34 +294,42 @@ string DynamicLoader::getExistingPathname(const string& file, const string& dire
name = directory + file;
}
}
return getExistingPathname(name);
return getExistingPathname(name, workingPath);
}
string DynamicLoader::getExistingPathname(const string& name) const {
string DynamicLoader::getExistingPathname(const string& name, const string& workingPath, bool withSuffix) const {
boost::filesystem::path path;
// complete path
string usedName = name;
bool tryAgainWithoutSuffix = false;
// first try with suffix
if (!environmentVariables[DyldImageSuffix].isEmpty()) {
if (withSuffix && !environmentVariables[DyldImageSuffix].isEmpty()) {
// only one suffix is considered
const string suffix = environmentVariables[DyldImageSuffix].getPaths().front();
string nameWithSuffix = name;
// where should we append suffix?
if (endsWith(name, ".dylib")) {
nameWithSuffix.insert(name.rfind("."), suffix);
usedName.insert(name.rfind("."), suffix);
} else {
nameWithSuffix += suffix;
usedName += suffix;
}
path = nameWithSuffix;
if (boost::filesystem::exists(path)) {
return nameWithSuffix;
}
}
// then without suffix
path = name;
if (boost::filesystem::exists(path)) {
return name;
}
tryAgainWithoutSuffix = true;
}
path = usedName;
// complete path (with working directory)
path = boost::filesystem::complete(path, workingPath);
if (boost::filesystem::exists(path)) {
return path.file_string();
} else {
// try without suffix
if (tryAgainWithoutSuffix) {
return getExistingPathname(name, workingPath, false);
}
}
return string();
}

@ -12,7 +12,7 @@ class DynamicLoader
{
public:
DynamicLoader();
virtual ~DynamicLoader() {}
virtual ~DynamicLoader();
string replacePlaceholder(const string& name, const MachOArchitecture* architecture) const;
string getPathname(const string& name, const MachOArchitecture* architecture, const string& workingDirectory) const;
@ -20,21 +20,21 @@ public:
private:
class EnvironmentPathVariable
{
public:
EnvironmentPathVariable();
EnvironmentPathVariable(const string& name, const StringList& defaultValues = StringList());
EnvironmentPathVariable(const char* homePath, const string& name, const StringList& defaultValues = StringList());
bool isEmpty() const;
const StringList& getPaths() const { return paths; }
private:
void setPaths(const StringList& paths);
void addPath(const string& path);
bool replaceHomeDirectory(string& path);
StringList paths;
static const char* PATHS_SEPARATOR;
static const char* HOME_PATH;
static const char PATHS_SEPARATOR[];
const char* homePath;
};
enum {
@ -50,7 +50,7 @@ private:
enum Placeholder {
ExecutablePath,
LoaderPath,
RPath,
Rpath,
NumPlaceholders
};
@ -61,13 +61,16 @@ private:
static const char* DEFAULT_FRAMEWORK_PATH[];
static const char* DEFAULT_LIBRARY_PATH[];
const char* homePath;
EnvironmentPathVariable environmentVariables[NumEnvironmentVariables];
string getFrameworkName(const string& name, const bool strippedSuffix = false) const;
string getExistingPathname(const string& name, const EnvironmentPathVariable& environmentPathVariable) const;
string getExistingPathname(const string& name, const string& directory) const;
string getExistingPathname(const string& name) const;
const char* getUserHomeDirectory() const;
string getExistingPathname(const string& name, const EnvironmentPathVariable& environmentPathVariable, const string& workingPath) const;
string getExistingPathname(const string& name, const string& directory, const string& workingPath) const;
string getExistingPathname(const string& name, const string& workingPath, bool withSuffix=true) const;
static bool endsWith(const string& str, const string& substr);
};

@ -65,7 +65,7 @@ string InternalFile::getTitle() const {
return filename.filename();
}
long long int InternalFile::getSize() const {
unsigned long long InternalFile::getSize() const {
return file_size(filename);
}

@ -16,7 +16,7 @@ public:
string getPath() const;
string getName() const;
string getTitle() const;
long long int getSize() const;
unsigned long long getSize() const;
bool seek(long long int position);
streamsize read(char* buffer, streamsize size);
long long int getPosition();

@ -3,6 +3,8 @@
#include "genericcommand.h"
#include "symboltablecommand.h"
#include "rpathcommand.h"
#include "uuidcommand.h"
#include "dylinkercommand.h"
#include "machoexception.h"
#include "machoheader.h"
#include "/usr/include/mach-o/loader.h"
@ -11,6 +13,12 @@ LoadCommand* LoadCommand::getLoadCommand(unsigned int cmd, MachOHeader* header)
LoadCommand* loadCommand;
switch(cmd) {
case LC_LOAD_DYLINKER:
loadCommand = new DylinkerCommand(header);
break;
case LC_UUID:
loadCommand = new UuidCommand(header);
break;
case LC_LAZY_LOAD_DYLIB: // dependency is loaded when it is needed
loadCommand = new DylibCommand(header, DylibCommand::DependencyDelayed);
break;
@ -28,7 +36,7 @@ LoadCommand* LoadCommand::getLoadCommand(unsigned int cmd, MachOHeader* header)
loadCommand = new SymbolTableCommand(header);
break;
case LC_RPATH:
loadCommand = new RPathCommand(header);
loadCommand = new RpathCommand(header);
break;
default:
loadCommand = new GenericCommand(header);

@ -8,6 +8,8 @@
#include <mach-o/fat.h>
// see http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
// for MachO specification
// static variables
Demangler* MachO::demangler = 0;
@ -143,7 +145,7 @@ MachOArchitecture* MachO::getHostCompatibleArchitecture() const {
return 0;
}
long long int MachO::getSize() const {
unsigned long long MachO::getSize() const {
return file->getSize();
}

@ -25,7 +25,7 @@ public:
MachOArchitecturesIterator getArchitecturesEnd();
MachOArchitecture* getCompatibleArchitecture(MachOArchitecture* destArchitecture) const;
MachOArchitecture* getHostCompatibleArchitecture() const;
long long int getSize() const;
unsigned long long getSize() const;
time_t getLastModificationTime() const;
string getVersion() const;
string getName() const;

@ -5,12 +5,14 @@
#include "dylibcommand.h"
#include "machoexception.h"
#include "rpathcommand.h"
#include "uuidcommand.h"
#include "dylinkercommand.h"
#include "macho.h"
#include "dynamicloader.h"
MachOArchitecture::MachOArchitecture(MachOFile& file, uint32_t magic, unsigned int size) :
header(MachOHeader::getHeader(file, magic)), file(header->getFile()), size(size), hasReadLoadCommands(false), parent(0), dynamicLibIdCommand(0)
header(MachOHeader::getHeader(file, magic)), file(header->getFile()), size(size), hasReadLoadCommands(false), parent(0), dynamicLibIdCommand(0), uuid(0)
{
}
@ -26,12 +28,17 @@ string MachOArchitecture::getResolvedName(const string& name, const string& work
return name;
}
std::vector<string*> MachOArchitecture::getRPaths() const {
std::vector<string*> MachOArchitecture::getRpaths(bool recursively) const {
// try to get it from the parent (recursively)
std::vector<string*> prevRPaths = parent?(std::vector<string*>(parent->getRPaths())):(std::vector<string*>());
std::vector<string*> prevRpaths;
if (recursively && parent) {
prevRpaths = parent->getRpaths(recursively);
} else {
prevRpaths = std::vector<string*>();
}
// add own rpaths to the end
prevRPaths.insert(prevRPaths.end(), rPaths.begin(), rPaths.end());
return prevRPaths;
prevRpaths.insert(prevRpaths.end(), rpaths.begin(), rpaths.end());
return prevRpaths;
}
void MachOArchitecture::readLoadCommands() const {
@ -44,21 +51,37 @@ void MachOArchitecture::readLoadCommands() const {
file.seek(commandOffset);
LoadCommand* loadCommand = LoadCommand::getLoadCommand(cmd, header);
DylibCommand* dylibCommand = dynamic_cast<DylibCommand*>(loadCommand);
// for dylibCommand...
DylibCommand* dylibCommand = dynamic_cast<DylibCommand*>(loadCommand);
if (dylibCommand != 0 && dylibCommand->isId()) {
dynamicLibIdCommand = dylibCommand;
}
RPathCommand* rPathCommand = dynamic_cast<RPathCommand*>(loadCommand);
if (rPathCommand != 0) {
// for rpath command...
RpathCommand* rpathCommand = dynamic_cast<RpathCommand*>(loadCommand);
if (rpathCommand != 0) {
// try to replace placeholder
string resolvedRPath = MachO::dynamicLoader->replacePlaceholder(rPathCommand->getPath(), this);
if (resolvedRPath.empty()) {
resolvedRPath = rPathCommand->getPath();
string resolvedRpath = MachO::dynamicLoader->replacePlaceholder(rpathCommand->getPath(), this);
if (resolvedRpath.empty()) {
resolvedRpath = rpathCommand->getPath();
}
rPaths.push_back(new string(resolvedRPath));
rpaths.push_back(new string(resolvedRpath));
}
loadCommands.push_back(loadCommand);
// for uuid command...
UuidCommand* uuidCommand = dynamic_cast<UuidCommand*>(loadCommand);
if (uuidCommand != 0) {
uuid = uuidCommand->getUuid();
}
// for dylinker command
DylinkerCommand* dylinkerCommand = dynamic_cast<DylinkerCommand*>(loadCommand);
if (dylinkerCommand != 0) {
dylinker = dylinkerCommand->getName();
}
loadCommands.push_back(loadCommand);
file.seek(commandOffset + loadCommand->getSize());
}
hasReadLoadCommands = true;
@ -74,8 +97,8 @@ MachOArchitecture::~MachOArchitecture() {
delete *it;
}
for (std::vector<string*>::iterator it2 = rPaths.begin();
it2 != rPaths.end();
for (std::vector<string*>::iterator it2 = rpaths.begin();
it2 != rpaths.end();
++it2)
{
delete *it2;
@ -86,5 +109,9 @@ unsigned int MachOArchitecture::getSize() const {
return size;
}
const uint8_t* MachOArchitecture::getUuid() const {
return uuid;
}

@ -28,10 +28,11 @@ public:
unsigned int getSize() const;
void initParentArchitecture(const MachOArchitecture* parent);
const MachOFile* getFile() const { return &file; }
std::vector<string*> getRPaths() const;
std::string getDynamicLinker() const { return dylinker; }
std::vector<string*> getRpaths(bool recursively = true) const;
string getResolvedName(const string& name, const string& workingPath) const;
const uint8_t* getUuid() const;
private:
MachOHeader* header;
MachOFile& file;
@ -40,9 +41,12 @@ private:
void readLoadCommands() const;
const MachOArchitecture* parent; // architecture from which this architecture was loaded
// all those are mutable, because they are initialized not in the constructor, but in the readLoadCommands method
mutable LoadCommands loadCommands;
mutable DylibCommand* dynamicLibIdCommand;
mutable std::vector<string*> rPaths;
mutable std::vector<string*> rpaths;
mutable const uint8_t* uuid;
mutable std::string dylinker;
};
#endif // MACHOARCHITECTURE_H

@ -30,7 +30,7 @@ string MachOFile::getName() const {
return filename;
}
string MachOFile::getTitle() const { return file->getTitle(); }
long long int MachOFile::getSize() const { return file->getSize(); }
unsigned long long MachOFile::getSize() const { return file->getSize(); }
time_t MachOFile::getLastModificationTime() const { return file->getLastModificationTime(); }
uint32_t MachOFile::readUint32() {

@ -23,7 +23,7 @@ public:
string getPath() const;
string getName() const;
string getTitle() const;
long long int getSize() const;
unsigned long long getSize() const;
void seek(long long int offset) { position = offset; }
long long int getPosition() const { return position; }
const string& getExecutablePath() const { return executablePath; }

@ -43,7 +43,7 @@ MachOHeader::CpuType MachOHeader::getHostCpuType() {
mach_port_t hostPort = mach_host_self();
kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
mach_port_deallocate(mach_task_self(), hostPort);
if ( result != KERN_SUCCESS )
if (result != KERN_SUCCESS)
throw "host_info() failed";
//sHostCPUsubtype = info.cpu_subtype;
return getCpuType(info.cpu_type);
@ -73,8 +73,7 @@ MachOHeader::CpuType MachOHeader::getCpuType(unsigned int cpu) {
MachOHeader::FileType MachOHeader::getFileType() const {
unsigned int fileType = getInternalFileType();
if (fileType > NumFileTypes || fileType < 1) {
throw MachOException("Invalid file type");
return NumFileTypes;
}
return static_cast<FileType>(fileType-1);
}

@ -32,7 +32,8 @@ public:
FileTypeBundle, /* dynamically bound bundle file */
FileTypeDylibStub, /* shared library stub for static linking only, no section contents */
FileTypeDsym, /* companion file with only debug sections */
NumFileTypes
FileTypeKextBundle, /* x86 64 kext bundle */
NumFileTypes /* stands also for unknown types */
};
FileType getFileType() const;
virtual CpuType getCpuType() const = 0;

@ -2,19 +2,19 @@
#include "machofile.h"
#include "machoheader.h"
RPathCommand::RPathCommand(MachOHeader* header) :
RpathCommand::RpathCommand(MachOHeader* header) :
LoadCommand(header)
{
file.readBytes((char*)&command, sizeof(command));
}
RPathCommand::~RPathCommand() {
RpathCommand::~RpathCommand() {
}
unsigned int RPathCommand::getSize() const {
unsigned int RpathCommand::getSize() const {
return file.getUint32(command.cmdsize);
}
const char* RPathCommand::getPath() const {
const char* RpathCommand::getPath() const {
return getLcDataString(command.path.offset);
}

@ -4,11 +4,11 @@
#include "MachO_global.h"
#include "loadcommand.h"
class EXPORT RPathCommand : public LoadCommand
class EXPORT RpathCommand : public LoadCommand
{
public:
RPathCommand(MachOHeader* header);
virtual ~RPathCommand();
RpathCommand(MachOHeader* header);
virtual ~RpathCommand();
virtual unsigned int getSize() const;
virtual unsigned int getStructureSize() const { return sizeof(command); }

@ -30,7 +30,4 @@ protected:
char* stringTable;
};
//QDebug &operator<<(QDebug &dbg, const SymbolTableEntry &symbolTable);
#endif // SYMBOLTABLEENTRY_H

22
MachO/uuidcommand.cpp Normal file

@ -0,0 +1,22 @@
#include "uuidcommand.h"
#include "machofile.h"
#include "machoheader.h"
#include <sstream>
UuidCommand::UuidCommand(MachOHeader* header) :
LoadCommand(header)
{
file.readBytes((char*)&command, sizeof(command));
}
UuidCommand::~UuidCommand() {
}
unsigned int UuidCommand::getSize() const {
return file.getUint32(command.cmdsize);
}
const uint8_t* UuidCommand::getUuid() const {
return command.uuid;
}

20
MachO/uuidcommand.h Normal file

@ -0,0 +1,20 @@
#ifndef UUIDCOMMAND_H
#define UUIDCOMMAND_H
#include "macho_global.h"
#include "loadcommand.h"
class EXPORT UuidCommand : public LoadCommand
{
public:
UuidCommand(MachOHeader* header);
virtual ~UuidCommand();
virtual unsigned int getSize() const;
virtual unsigned int getStructureSize() const { return sizeof(command); }
const uint8_t* getUuid() const;
private:
uuid_command command;
};
#endif // UUIDCOMMAND_H