macosx-nat-dyld-path.c [plain text]
#include "macosx-nat-dyld-path.h"
#include "macosx-nat-dyld-info.h"
#include "macosx-nat-dyld.h"
#include "macosx-nat-inferior.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"
extern macosx_inferior_status *macosx_status;
#define assert CHECK_FATAL
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 *basename, *a, *b, *c, *d, *suffix;
int baselen, s;
a = strrchr (name, '/');
if (a == NULL)
return (NULL);
if (a == name)
return (NULL);
basename = a + 1;
baselen = strlen (basename);
if (with_suffix)
{
suffix = strrchr (basename, '_');
if (suffix != NULL)
{
s = strlen (suffix);
if (suffix == basename || s < 2)
suffix = NULL;
else
baselen -= s;
}
}
b = look_back_for_slash (name, a);
if (b == NULL)
{
if (strncmp (name, basename, baselen) == 0 &&
strncmp (name + baselen, type, sizeof (type) - 1) == 0)
return (name);
else
return (NULL);
}
else
{
if (strncmp (b + 1, basename, baselen) == 0 &&
strncmp (b + 1 + baselen, 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)
{
if (c == NULL)
return (NULL);
if (strncmp (c + 1, "Versions/", sizeof ("Versions/") - 1) != 0)
{
if (strncmp (c + 1, "Contents/MacOS/",
sizeof ("Contents/MacOS/") - 1) == 0)
{
if (strncmp (c + 1, basename, baselen) == 0 &&
strncmp (c + 1 + baselen, type, sizeof (type) - 1) == 0)
return (c + 1);
}
return (NULL);
}
}
d = look_back_for_slash (name, c);
if (d == NULL)
{
if (strncmp (name, basename, baselen) == 0 &&
strncmp (name + baselen, type, sizeof (type) - 1) == 0)
return (name);
else
return (NULL);
}
else
{
if (strncmp (d + 1, basename, baselen) == 0 &&
strncmp (d + 1 + baselen, type, sizeof (type) - 1) == 0)
return (d + 1);
else
return (NULL);
}
}
void
dyld_library_basename (const char *path, const char **s, int *len,
int *is_framework, int *is_bundle)
{
const char *p = NULL;
const char *q = NULL;
const char *dyld_image_suffix = NULL;
if (macosx_status != NULL
&& macosx_status->dyld_status.path_info.image_suffix != NULL)
{
dyld_image_suffix = macosx_status->dyld_status.path_info.image_suffix;
}
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 = xstrdup (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 = xstrdup (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)
path = ++q;
char *newstr = xstrdup (path);
if (dyld_image_suffix != NULL)
{
char *suffixptr = strstr (newstr, dyld_image_suffix);
if (suffixptr != NULL)
{
char *tmpbuf = xstrdup (suffixptr + strlen (dyld_image_suffix));
strcpy (suffixptr, tmpbuf);
xfree (tmpbuf);
}
}
*s = (const char *) newstr;
*len = strlen (newstr);
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 xstrdup (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_zero_path_info (dyld_path_info *d)
{
d->framework_path = NULL;
d->library_path = NULL;
d->image_suffix = NULL;
d->fallback_framework_path = NULL;
d->fallback_library_path = NULL;
d->insert_libraries = 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 ())
{
if (d->framework_path != NULL)
xfree (d->framework_path);
if (d->library_path != NULL)
xfree (d->library_path);
if (d->fallback_framework_path != NULL)
xfree (d->fallback_framework_path);
if (d->fallback_library_path != NULL)
xfree (d->fallback_library_path);
if (d->image_suffix != NULL)
xfree (d->image_suffix);
if (d->insert_libraries != NULL)
xfree (d->insert_libraries);
d->framework_path =
get_in_environ (inferior_environ, "DYLD_FRAMEWORK_PATH");
if (d->framework_path != NULL)
d->framework_path = xstrdup (d->framework_path);
d->library_path =
get_in_environ (inferior_environ, "DYLD_LIBRARY_PATH");
if (d->library_path != NULL)
d->library_path = xstrdup (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 = xstrdup (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 = xstrdup (d->fallback_library_path);
d->image_suffix =
get_in_environ (inferior_environ, "DYLD_IMAGE_SUFFIX");
if (d->image_suffix != NULL)
d->image_suffix = xstrdup (d->image_suffix);
d->insert_libraries =
get_in_environ (inferior_environ, "DYLD_INSERT_LIBRARIES");
if (d->insert_libraries != NULL)
d->insert_libraries = xstrdup (d->insert_libraries);
}
home = get_in_environ (inferior_environ, "HOME");
if (home != NULL)
home = xstrdup (home);
if (home == NULL)
home = xstrdup ("/");
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);
}
xfree (home);
}