macosx-nat-dyld-path.c [plain text]
#include "macosx-nat-dyld-path.h"
#include <string.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include "defs.h"
#include "inferior.h"
#include "environ.h"
#include "gdbcore.h"
#define assert CHECK_FATAL
#define strsave(s) xstrdup (s)
static char *build_suffix_name (const char *name, const char *suffix);
static char *search_for_name_in_path (const char *name, const char *path,
const char *suffix);
static const char *look_back_for_slash (const char *name, const char *p);
static const char *get_framework_pathname (const char *name, const char *type, int with_suffix);
static const char *look_back_for_slash (const char *name, const char *p)
{
for (p = p - 1; p >= name; p--) {
if (*p == '/')
return p;
}
return NULL;
}
static char *
build_suffix_name (const char *name, const char *suffix)
{
size_t suffixlen = strlen (suffix);
size_t namelen = strlen(name);
char *name_with_suffix;
if (suffixlen > 0)
{
char *tmp;
name_with_suffix = xmalloc (namelen + suffixlen + 1);
if (namelen < 7)
tmp = NULL;
else
tmp = strrchr(name, '.');
if (tmp != NULL && strcmp (tmp, ".dylib") == 0)
{
int baselen = namelen - 6;
memcpy (name_with_suffix, name, baselen);
tmp = name_with_suffix + baselen;
memcpy (tmp, suffix, suffixlen);
tmp += suffixlen;
memcpy (tmp, ".dylib", 6);
*(tmp + 6) = '\0';
}
else
{
memcpy (name_with_suffix, name, namelen);
tmp = name_with_suffix + namelen;
memcpy (tmp, suffix, suffixlen);
*(tmp + suffixlen) = '\0';
}
return name_with_suffix;
}
else
{
return NULL;
}
}
static char *
search_for_name_in_path
(const char *name, const char *path, const char *suffix)
{
char *dylib_name;
char *name_with_suffix;
int name_with_suffix_len;
const char *p, *cur;
size_t curlen;
size_t namelen;
size_t pathlen;
struct stat stat_buf;
namelen = strlen (name);
pathlen = strlen (path);
if (suffix)
{
name_with_suffix = build_suffix_name (name, suffix);
name_with_suffix_len = strlen (name_with_suffix);
dylib_name = xmalloc (name_with_suffix_len + pathlen + 2);
}
else
{
name_with_suffix = NULL;
name_with_suffix_len = 0;
dylib_name = xmalloc (namelen + pathlen + 2);
}
cur = path;
for (;;) {
p = strchr (cur, ':');
if (p == NULL) {
p = strchr (cur, '\0');
}
assert (p != NULL);
curlen = p - cur;
if (curlen != 0) {
memcpy (dylib_name, cur, curlen);
dylib_name[curlen] = '/';
if (name_with_suffix != NULL)
{
memcpy (dylib_name + curlen + 1, name_with_suffix, name_with_suffix_len);
dylib_name[curlen + 1 + name_with_suffix_len] = '\0';
if (stat(dylib_name, &stat_buf) == 0)
{
xfree (name_with_suffix);
return dylib_name;
}
}
memcpy (dylib_name + curlen + 1, name, namelen);
dylib_name[curlen + 1 + namelen] = '\0';
if (stat (dylib_name, &stat_buf) == 0)
{
if (name_with_suffix)
xfree (name_with_suffix);
return dylib_name;
}
}
if (*p == '\0') {
break;
}
cur = p + 1;
if (*cur == '\0') {
break;
}
}
xfree (dylib_name);
if (name_with_suffix)
xfree (name_with_suffix);
return NULL;
}
static const char *
get_framework_pathname (const char *name, const char *type, int with_suffix)
{
const char *foo, *a, *b, *c, *d, *suffix;
unsigned long l, s;
a = strrchr(name, '/');
if(a == NULL)
return(NULL);
if(a == name)
return(NULL);
foo = a + 1;
l = strlen(foo);
if(with_suffix){
suffix = strrchr(foo, '_');
if(suffix != NULL){
s = strlen(suffix);
if(suffix == foo || s < 2)
suffix = NULL;
else
l -= s;
}
}
b = look_back_for_slash(name, a);
if(b == NULL){
if(strncmp(name, foo, l) == 0 &&
strncmp(name + l, type, sizeof(type)-1 ) == 0)
return(name);
else
return(NULL);
}
else{
if(strncmp(b+1, foo, l) == 0 &&
strncmp(b+1 + l, type, sizeof(type)-1 ) == 0)
return(b+1);
}
if(b == name)
return(NULL);
c = look_back_for_slash(name, b);
if(c == NULL ||
c == name ||
strncmp(c+1, "Versions/", sizeof("Versions/")-1) != 0)
return(NULL);
d = look_back_for_slash(name, c);
if(d == NULL){
if(strncmp(name, foo, l) == 0 &&
strncmp(name + l, type, sizeof(type)-1 ) == 0)
return(name);
else
return(NULL);
}
else{
if(strncmp(d+1, foo, l) == 0 &&
strncmp(d+1 + l, type, sizeof(type)-1 ) == 0)
return(d+1);
else
return(NULL);
}
}
void dyld_library_basename (const char *path, const char **s, unsigned int *len, int *is_framework, int *is_bundle)
{
const char *p = NULL;
const char *q = NULL;
if (is_framework != NULL) {
*is_framework = 0;
}
if (is_bundle != NULL) {
*is_bundle = 0;
}
p = get_framework_pathname (path, ".framework/", 1);
if (p != NULL) {
q = strrchr (path, '/');
assert (q != NULL);
assert (*q++ == '/');
*s = q;
*len = strlen (q);
if (is_framework != NULL) {
*is_framework = 1;
}
if (is_bundle != NULL) {
*is_bundle = 0;
}
return;
}
p = get_framework_pathname (path, ".bundle/", 1);
if (p != NULL) {
q = strrchr (path, '/');
assert (q != NULL);
assert (*q++ == '/');
*s = q;
*len = strlen (q);
if (is_framework != NULL) {
*is_framework = 0;
}
if (is_bundle != NULL) {
*is_bundle = 1;
}
return;
}
q = strrchr (path, '/');
if (q != NULL) {
assert (*q++ == '/');
*s = q;
*len = strlen (q);
return;
}
*s = path;
*len = strlen (path);
return;
}
char *dyld_resolve_image (const struct dyld_path_info *d, const char *dylib_name)
{
struct stat stat_buf;
const char *framework_name = NULL;
const char *framework_name_suffix = NULL;
const char *library_name = NULL;
char *framework_path = NULL;
if (dylib_name == NULL)
return NULL;
if (dylib_name[0] == '@' && strstr (dylib_name, "@executable_path") == dylib_name)
{
int cookie_len = strlen ("@executable_path");
const char *relative_name = dylib_name + cookie_len;
if ((exec_bfd != NULL) && (exec_bfd->filename != NULL))
{
int relative_name_len = strlen (relative_name);
char *executable_path_end = strrchr (exec_bfd->filename, '/');
if (executable_path_end != NULL)
{
int executable_path_len = executable_path_end - exec_bfd->filename;
char *final_name = xmalloc (relative_name_len + executable_path_len + 1);
memcpy (final_name, exec_bfd->filename, executable_path_len);
memcpy (final_name + executable_path_len, relative_name, relative_name_len);
final_name[executable_path_len + relative_name_len] = '\0';
if (stat (final_name, &stat_buf) == 0)
return final_name;
else
xfree (final_name);
}
else
{
warning ("Executable filename not a path, "
"can't resolve \"@executable_path load command.");
return NULL;
}
}
else
{
warning ("Couldn't find executable filename while trying to"
" resolve \"@executable_path\" load command.");
}
}
framework_name = get_framework_pathname (dylib_name, ".framework/", 0);
framework_name_suffix = get_framework_pathname (dylib_name, ".framework/", 1);
library_name = strrchr (dylib_name, '/');
if ((library_name != NULL) && (library_name[1] != '\0')) {
library_name++;
} else {
library_name = dylib_name;
}
if (d->framework_path != NULL)
{
if (framework_name != NULL)
{
framework_path = search_for_name_in_path
(framework_name, d->framework_path, d->image_suffix);
if (framework_path != NULL)
return framework_path;
}
if (framework_name_suffix != NULL)
{
framework_path = search_for_name_in_path
(framework_name_suffix, d->framework_path, d->image_suffix);
if (framework_path != NULL)
return framework_path;
}
}
if (d->library_path != NULL)
{
framework_path = search_for_name_in_path
(library_name, d->library_path, d->image_suffix);
if (framework_path != NULL)
return framework_path;
}
if (d->image_suffix)
{
char *suffix_name;
suffix_name = build_suffix_name (dylib_name, d->image_suffix);
if (stat (suffix_name, &stat_buf) == 0)
{
return suffix_name;
}
else
{
xfree (suffix_name);
}
}
if (stat (dylib_name, &stat_buf) == 0)
{
return strsave (dylib_name);
}
if (d->fallback_framework_path != NULL) {
if (framework_name != NULL)
{
framework_path = search_for_name_in_path (framework_name,
d->fallback_framework_path,
d->image_suffix);
if (framework_path != NULL)
{
return framework_path;
}
}
if (framework_name_suffix != NULL)
{
framework_path = search_for_name_in_path (framework_name_suffix,
d->fallback_framework_path,
d->image_suffix);
if (framework_path != NULL)
{
return framework_path;
}
}
}
if (d->fallback_library_path != NULL)
{
framework_path = search_for_name_in_path (library_name,
d->fallback_library_path,
d->image_suffix);
if (framework_path != NULL)
{
return framework_path;
}
}
return NULL;
}
void dyld_init_paths (dyld_path_info *d)
{
char *home;
const char *default_fallback_framework_path =
"%s/Library/Frameworks:"
"/Local/Library/Frameworks:"
"/Network/Library/Frameworks:"
"/System/Library/Frameworks";
const char *default_fallback_library_path =
"%s/lib:"
"/usr/local/lib:"
"/lib:"
"/usr/lib";
if ((getuid() == geteuid()) && (getgid() == getegid()))
{
d->framework_path =
get_in_environ (inferior_environ, "DYLD_FRAMEWORK_PATH");
if (d->framework_path != NULL)
d->framework_path = strsave (d->framework_path);
d->library_path =
get_in_environ (inferior_environ, "DYLD_LIBRARY_PATH");
if (d->library_path != NULL)
d->library_path = strsave (d->library_path);
d->fallback_framework_path =
get_in_environ (inferior_environ, "DYLD_FALLBACK_FRAMEWORK_PATH");
if (d->fallback_framework_path != NULL)
d->fallback_framework_path = strsave (d->fallback_framework_path);
d->fallback_library_path =
get_in_environ (inferior_environ, "DYLD_FALLBACK_LIBRARY_PATH");
if (d->fallback_library_path != NULL)
d->fallback_library_path = strsave (d->fallback_library_path);
d->image_suffix =
get_in_environ (inferior_environ, "DYLD_IMAGE_SUFFIX");
if (d->image_suffix != NULL)
d->image_suffix = strsave (d->image_suffix);
d->insert_libraries =
get_in_environ (inferior_environ, "DYLD_INSERT_LIBRARIES");
if (d->insert_libraries != NULL)
d->insert_libraries = strsave (d->insert_libraries);
}
home = get_in_environ (inferior_environ, "HOME");
if (home != NULL)
home = strsave (home);
if (home == NULL)
home = strsave ("/");
if (d->fallback_framework_path == NULL)
{
d->fallback_framework_path =
xmalloc (strlen (default_fallback_framework_path)
+ strlen (home) + 1);
sprintf (d->fallback_framework_path, default_fallback_framework_path,
home);
}
if (d->fallback_library_path == NULL)
{
d->fallback_library_path =
xmalloc (strlen (default_fallback_library_path)
+ strlen (home) + 1);
sprintf (d->fallback_library_path, default_fallback_library_path, home);
}
}