binreloc.cpp

来自「Source code (C++) of the Amoebax game fo」· C++ 代码 · 共 767 行 · 第 1/2 页

CPP
767
字号
/* * BinReloc - a library for creating relocatable executables * Written by: 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. * * See http://autopackage.org/docs/binreloc/ for * more information and how to use this. */#ifndef __BINRELOC_C__#define __BINRELOC_C__#ifdef ENABLE_BINRELOC	#include <sys/types.h>	#include <sys/stat.h>	#include <unistd.h>#endif /* ENABLE_BINRELOC */#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <string.h>#include "binreloc.h"#ifdef __cplusplusextern "C" {#endif /* __cplusplus *//** @internal * Find the canonical filename of the executable. Returns the filename * (which must be freed) or NULL on error. If the parameter 'error' is * not NULL, the error code will be stored there, if an error occured. */static char *_br_find_exe (BrInitError *error){#ifndef ENABLE_BINRELOC	if (error)		*error = BR_INIT_ERROR_DISABLED;	return NULL;#else	char *path, *path2, *line, *result;	size_t buf_size;	ssize_t size;	struct stat stat_buf;	FILE *f;	/* Read from /proc/self/exe (symlink) */	if (sizeof (path) > SSIZE_MAX)		buf_size = SSIZE_MAX - 1;	else		buf_size = PATH_MAX - 1;	path = (char *) malloc (buf_size);	if (path == NULL) {		/* Cannot allocate memory. */		if (error)			*error = BR_INIT_ERROR_NOMEM;		return NULL;	}	path2 = (char *) malloc (buf_size);	if (path2 == NULL) {		/* Cannot allocate memory. */		if (error)			*error = BR_INIT_ERROR_NOMEM;		free (path);		return NULL;	}	strncpy (path2, "/proc/self/exe", buf_size - 1);	while (1) {		int i;		size = readlink (path2, path, buf_size - 1);		if (size == -1) {			/* Error. */			free (path2);			break;		}		/* readlink() success. */		path[size] = '\0';		/* Check whether the symlink's target is also a symlink.		 * We want to get the final target. */		i = stat (path, &stat_buf);		if (i == -1) {			/* Error. */			free (path2);			break;		}		/* stat() success. */		if (!S_ISLNK (stat_buf.st_mode)) {			/* path is not a symlink. Done. */			free (path2);			return path;		}		/* path is a symlink. Continue loop and resolve this. */		strncpy (path, path2, buf_size - 1);	}	/* readlink() or stat() failed; this can happen when the program is	 * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */	buf_size = PATH_MAX + 128;	line = (char *) realloc (path, buf_size);	if (line == NULL) {		/* Cannot allocate memory. */		free (path);		if (error)			*error = BR_INIT_ERROR_NOMEM;		return NULL;	}	f = fopen ("/proc/self/maps", "r");	if (f == NULL) {		free (line);		if (error)			*error = BR_INIT_ERROR_OPEN_MAPS;		return NULL;	}	/* The first entry should be the executable name. */	result = fgets (line, (int) buf_size, f);	if (result == NULL) {		fclose (f);		free (line);		if (error)			*error = BR_INIT_ERROR_READ_MAPS;		return NULL;	}	/* Get rid of newline character. */	buf_size = strlen (line);	if (buf_size <= 0) {		/* Huh? An empty string? */		fclose (f);		free (line);		if (error)			*error = BR_INIT_ERROR_INVALID_MAPS;		return NULL;	}	if (line[buf_size - 1] == 10)		line[buf_size - 1] = 0;	/* Extract the filename; it is always an absolute path. */	path = strchr (line, '/');	/* Sanity check. */	if (strstr (line, " r-xp ") == NULL || path == NULL) {		fclose (f);		free (line);		if (error)			*error = BR_INIT_ERROR_INVALID_MAPS;		return NULL;	}	path = strdup (path);	free (line);	fclose (f);	return path;#endif /* ENABLE_BINRELOC */}/** @internal * Find the canonical filename of the executable which owns symbol. * Returns a filename which must be freed, or NULL on error. */static char *_br_find_exe_for_symbol (const void *symbol, BrInitError *error){#ifndef ENABLE_BINRELOC	if (error)		*error = BR_INIT_ERROR_DISABLED;	return (char *) NULL;#else	#define SIZE PATH_MAX + 100	FILE *f;	size_t address_string_len;	char *address_string, line[SIZE], *found;	if (symbol == NULL)		return (char *) NULL;	f = fopen ("/proc/self/maps", "r");	if (f == NULL)		return (char *) NULL;	address_string_len = 4;	address_string = (char *) malloc (address_string_len);	found = (char *) NULL;	while (!feof (f)) {		char *start_addr, *end_addr, *end_addr_end, *file;		void *start_addr_p, *end_addr_p;		size_t len;		if (fgets (line, SIZE, f) == NULL)			break;		/* Sanity check. */		if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)			continue;		/* Parse line. */		start_addr = line;		end_addr = strchr (line, '-');		file = strchr (line, '/');		/* More sanity check. */		if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))			continue;		end_addr[0] = '\0';		end_addr++;		end_addr_end = strchr (end_addr, ' ');		if (end_addr_end == NULL)			continue;		end_addr_end[0] = '\0';		len = strlen (file);		if (len == 0)			continue;		if (file[len - 1] == '\n')			file[len - 1] = '\0';		/* Get rid of "(deleted)" from the filename. */		len = strlen (file);		if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)			file[len - 10] = '\0';		/* I don't know whether this can happen but better safe than sorry. */		len = strlen (start_addr);		if (len != strlen (end_addr))			continue;		/* Transform the addresses into a string in the form of 0xdeadbeef,		 * then transform that into a pointer. */		if (address_string_len < len + 3) {			address_string_len = len + 3;			address_string = (char *) realloc (address_string, address_string_len);		}		memcpy (address_string, "0x", 2);		memcpy (address_string + 2, start_addr, len);		address_string[2 + len] = '\0';		sscanf (address_string, "%p", &start_addr_p);		memcpy (address_string, "0x", 2);		memcpy (address_string + 2, end_addr, len);		address_string[2 + len] = '\0';		sscanf (address_string, "%p", &end_addr_p);		if (symbol >= start_addr_p && symbol < end_addr_p) {			found = file;			break;		}	}	free (address_string);	fclose (f);	if (found == NULL)		return (char *) NULL;	else		return strdup (found);#endif /* ENABLE_BINRELOC */}#ifndef BINRELOC_RUNNING_DOXYGEN	#undef NULL	#define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */#endifstatic char *exe = (char *) NULL;/** Initialize the BinReloc library (for applications). * * This function must be called before using any other BinReloc functions. * It attempts to locate the application's canonical filename. * * @note If you want to use BinReloc for a library, then you should call *       br_init_lib() instead. * * @param error  If BinReloc failed to initialize, then the error code will *               be stored in this variable. Set to NULL if you want to *               ignore this. See #BrInitError for a list of error codes. * * @returns 1 on success, 0 if BinReloc failed to initialize. */intbr_init (BrInitError *error){	exe = _br_find_exe (error);	return exe != NULL;}/** Initialize the BinReloc library (for libraries). * * This function must be called before using any other BinReloc functions. * It attempts to locate the calling library's canonical filename. * * @note The BinReloc source code MUST be included in your library, or this *       function won't work correctly. * * @param error  If BinReloc failed to initialize, then the error code will *               be stored in this variable. Set to NULL if you want to *               ignore this. See #BrInitError for a list of error codes. * * @returns 1 on success, 0 if a filename cannot be found. */intbr_init_lib (BrInitError *error){	exe = _br_find_exe_for_symbol ((const void *) "", error);	return exe != NULL;}/** Find the canonical filename of the current application. * * @param default_exe  A default filename which will be used as fallback. * @returns A string containing the application's canonical filename, *          which must be freed when no longer necessary. If BinReloc is *          not initialized, or if br_init() failed, then a copy of *          default_exe will be returned. If default_exe is NULL, then *          NULL will be returned. */char *br_find_exe (const char *default_exe){	if (exe == (char *) NULL) {		/* BinReloc is not initialized. */		if (default_exe != (const char *) NULL)			return strdup (default_exe);		else			return (char *) NULL;	}	return strdup (exe);}/** Locate the directory in which the current application is installed. * * The prefix is generated by the following pseudo-code evaluation: * \code * dirname(exename) * \endcode * * @param default_dir  A default directory which will used as fallback. * @return A string containing the directory, which must be freed when no *         longer necessary. If BinReloc is not initialized, or if the *         initialization function failed, then a copy of default_dir *         will be returned. If default_dir is NULL, then NULL will be *         returned. */char *br_find_exe_dir (const char *default_dir){	if (exe == NULL) {		/* BinReloc not initialized. */		if (default_dir != NULL)			return strdup (default_dir);		else			return 0;	}	return br_dirname (exe);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?