gee
oldstatus
2005-09-19, Nathan Walp
* BinReloc - a library for creating relocatable executables * Written by: Mike Hearn <mike@theoretic.com> * Hongli Lai <h.lai@chello.nl> * http://autopackage.org/ * This source code is public domain. You can relicense this code * under whatever license you want. * NOTE: if you're using C++ and are getting "undefined reference * to br_*", try renaming prefix.c to prefix.cpp /* WARNING, BEFORE YOU MODIFY PREFIX.C: * If you make changes to any of the functions in prefix.c, you MUST * change the BR_NAMESPACE macro (in prefix.h). * This way you can avoid symbol table conflicts with other libraries * that also happen to use BinReloc. * #define BR_NAMESPACE(funcName) foobar_ ## funcName * --> expands br_locate to foobar_br_locate /* Change 1 to 0 if you don't want pthread support */ #define NULL ((void *) 0) #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} #define br_return_val_if_fail(expr,val) if (!(expr)) return val static br_locate_fallback_func fallback_func = NULL; static void *fallback_data = NULL; * symbol: A symbol that belongs to the app/library you want to locate. * Returns: A newly allocated string containing the full path of the * app/library that func belongs to, or NULL on error. This * string should be freed when not when no longer needed. * Finds out to which application or library symbol belongs, then locate * the full path of that application or library. * Note that symbol cannot be a pointer to a function. That will not work. * int main (int argc, char *argv[]) { * printf ("Full path of this app: %s\n", br_locate (&argc)); * --> libfoo.c starts here * --> "" is a symbol that belongs to libfoo (because it's called * --> from libfoo_start()); that's why this works. * printf ("libfoo is located in: %s\n", br_locate ("")); br_return_val_if_fail (symbol != NULL, NULL); f = fopen ("/proc/self/maps", "r"); return fallback_func(symbol, fallback_data); unsigned long start, end; if (!fgets (line, sizeof (line), f)) if (!strstr (line, " r-xp ") || !strchr (line, '/')) sscanf (line, "%lx-%lx ", &start, &end); if (symbol >= (void *) start && symbol < (void *) end) /* Extract the filename; it is always an absolute path */ path = strchr (line, '/'); /* Get rid of the newline */ tmp = strrchr (path, '\n'); /* Get rid of "(deleted)" */ if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) * symbol: A symbol that belongs to the app/library you want to locate. * Returns: A prefix. This string should be freed when no longer needed. * Locates the full path of the app/library that symbol belongs to, and return * the prefix of that path, or NULL on error. * Note that symbol cannot be a pointer to a function. That will not work. * --> This application is located in /usr/bin/foo * br_locate_prefix (&argc); --> returns: "/usr" br_locate_prefix (void *symbol) br_return_val_if_fail (symbol != NULL, NULL); path = br_locate (symbol); prefix = br_extract_prefix (path); * symbol: A symbol that belongs to the app/library you want to locate. * path: The path that you want to prepend the prefix to. * Returns: The new path, or NULL on error. This string should be freed when no * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path. * Note that symbol cannot be a pointer to a function. That will not work. * --> The application is /usr/bin/foo * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png" br_prepend_prefix (void *symbol, char *path) br_return_val_if_fail (symbol != NULL, NULL); br_return_val_if_fail (path != NULL, NULL); tmp = br_locate_prefix (symbol); if (strcmp (tmp, "/") == 0) newpath = br_strcat (tmp, path); /* Get rid of compiler warning ("br_prepend_prefix never used") */ if (0) br_prepend_prefix (NULL, NULL); #endif /* ENABLE_BINRELOC */ /* Pthread stuff for thread safetiness */ static pthread_key_t br_thread_key; static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT; br_thread_local_store_fini () specific = (char *) pthread_getspecific (br_thread_key); pthread_setspecific (br_thread_key, NULL); pthread_key_delete (br_thread_key); br_thread_local_store_init () if (pthread_key_create (&br_thread_key, br_str_free) == 0) atexit (br_thread_local_store_fini); static char *br_last_value = (char *) NULL; * str: A dynamically allocated string. * Returns: str. This return value must not be freed. * Store str in a thread-local variable and return str. The next * you run this function, that variable is freed too. * This function is created so you don't have to worry about freeing * strings. Just be careful about doing this sort of thing: * some_function( BR_DATADIR("/one.png"), BR_DATADIR("/two.png") ) * foo = br_thread_local_store (strdup ("hello")); --> foo == "hello" * foo = br_thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed. br_thread_local_store (char *str) pthread_once (&br_thread_key_once, br_thread_local_store_init); specific = (char *) pthread_getspecific (br_thread_key); pthread_setspecific (br_thread_key, str); static int initialized = 0; atexit (br_free_last_value); return (const char *) str; * Returns: A newly-allocated string. This string should be freed when no longer needed. * Concatenate str1 and str2 to a newly allocated string. br_strcat (const char *str1, const char *str2) result = (char *) malloc (len1 + len2 + 1); memcpy (result, str1, len1); memcpy (result + len1, str2, len2); result[len1 + len2] = '\0'; /* Emulates glibc's strndup() */ br_strndup (char *str, size_t size) char *result = (char *) NULL; br_return_val_if_fail (str != (char *) NULL, (char *) NULL); if (!len) return strdup (""); if (size > len) size = len; result = (char *) calloc (sizeof (char), len + 1); memcpy (result, str, size); * Returns: A directory name. This string should be freed when no longer needed. * Extracts the directory component of path. Similar to g_dirname() or the dirname * commandline application. * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local" br_extract_dir (const char *path) br_return_val_if_fail (path != (char *) NULL, (char *) NULL); end = strrchr (path, '/'); if (!end) return strdup ("."); while (end > path && *end == '/') result = br_strndup ((char *) path, end - path + 1); * path: The full path of an executable or library. * Returns: The prefix, or NULL on error. This string should be freed when no longer needed. * Extracts the prefix from path. This function assumes that your executable * or library is installed in an LSB-compatible directory structure. * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr" * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local" * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr" br_extract_prefix (const char *path) char *end, *tmp, *result; br_return_val_if_fail (path != (char *) NULL, (char *) NULL); if (!*path) return strdup ("/"); end = strrchr (path, '/'); if (!end) return strdup (path); tmp = br_strndup ((char *) path, end - path); end = strrchr (tmp, '/'); result = br_strndup (tmp, end - tmp); * br_set_fallback_function: * func: A function to call to find the binary. * data: User data to pass to func. * Sets a function to call to find the path to the binary, in * case "/proc/self/maps" can't be opened. The function set should * return a string that is safe to free with free(). br_set_locate_fallback_func (br_locate_fallback_func func, void *data)