changeset 217:87c695673522

dynload darwin/mach-o update: - removed unnecessarily complex darwin loader interface, and sharing with dynload_unix now - mach-o symbol resolving refactored: * to handle symlinks, relative paths, paths with random casing * loading lib when not already loaded, for API consistency with ELF and PE implementations
author Tassilo Philipp
date Thu, 06 Apr 2017 12:00:36 +0200
parents 28bf0b231bce
children cb56f077fd37
files ChangeLog dynload/dynload.c dynload/dynload_darwin.c dynload/dynload_syms.c dynload/dynload_syms_mach-o.c
diffstat 5 files changed, 72 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Apr 06 11:40:15 2017 +0200
+++ b/ChangeLog	Thu Apr 06 12:00:36 2017 +0200
@@ -16,6 +16,11 @@
   o SPARC64 (v9) support
   o POSIX compliance: fallback for wx alloc on systems that don't have mmap()'s MAP_ANON
   o allocated space used for thunk now always W^X (req. for e.g. OpenBSD >= 6.0)
+dynload:
+  o simplifications of implemention on Darwin
+  o reliability/stability fixes for Mach-O dlSyms* lib to handle symlinks,
+    relative paths, paths with random casings
+  o allowing Mach-O dlSyms* lib to be used standalone (consistent with ELF and PE impls now)
 general:
   o marked assembly code as not needing an execstack, for safer/easier integration into other
     projects/builds, where needed; this is needed b/c of questionable default behaviours of some
--- a/dynload/dynload.c	Thu Apr 06 11:40:15 2017 +0200
+++ b/dynload/dynload.c	Thu Apr 06 12:00:36 2017 +0200
@@ -6,7 +6,7 @@
  Description: Auto-include delegate to windows/posix-based dynamic linker.
  License:
 
-   Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>, 
+   Copyright (c) 2007-2017 Daniel Adler <dadler@uni-goettingen.de>,
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -24,16 +24,10 @@
 */
 
 
-
 #include "../autovar/autovar_OSFAMILY.h"
 #if defined(OSFAMILY_Windows)
 #  include "dynload_windows.c"
 #elif defined(OSFAMILY_Unix)
-#  include "../autovar/autovar_OS.h"
-#  if defined(OS_Darwin)
-#    include "dynload_darwin.c"
-#  else
-#    include "dynload_unix.c"
-#  endif
+#  include "dynload_unix.c"
 #endif
 
--- a/dynload/dynload_darwin.c	Thu Apr 06 11:40:15 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
-
- Package: dyncall
- Library: dynload
- File: dynload/dynload_darwin.c
- Description: dynload module for .dylib (mach-o darwin/OS X) files
- License:
-
-   Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>
-                           Minor bug-fix modifications by Daniel Adler.
-
-   Permission to use, copy, modify, and distribute this software for any
-   purpose with or without fee is hereby granted, provided that the above
-   copyright notice and this permission notice appear in all copies.
-
-   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-*/
-
-
-
-/*
-
-  dynload_darwin.c
-
-  dynload module for .dylib (mach-o darwin/OS X) files
-
-*/
-
-
-#include "dynload.h"
-#include "dynload_alloc.h"
-#include <dlfcn.h>
-#include <string.h>
-
-struct DLLib_
-{
-	char* libPath;
-	void* handle;
-};
-
-
-DLLib* dlLoadLibrary(const char* libPath)
-{
-	void* handle;
-	size_t len;
-	DLLib* lib;
-	
-	handle = dlopen(libPath, RTLD_LAZY);
-	if (!handle)
-		return NULL;
-
-      
-        lib = (DLLib*)dlAllocMem(sizeof(DLLib));
-        lib->handle = handle;
-        /* libPath might be null (self reference on image) [Daniel] */
-        if (libPath != NULL) {
-                len = strlen(libPath);
-                lib->libPath = (char*)dlAllocMem(len + 1);
-                strcpy(lib->libPath, libPath);
-                lib->libPath[len] = '\0';
-        } else {
-                lib->libPath = NULL;
-        }
-        return lib;
-}
-
-void* dlFindSymbol(DLLib* libHandle, const char* symbol)
-{
-  return dlsym(libHandle && libHandle->handle ? libHandle->handle : RTLD_DEFAULT, symbol);
-}
-
-
-void  dlFreeLibrary(DLLib* libHandle)
-{
-	if (!libHandle)
-		return;
-	
-	dlclose(libHandle->handle);
-        if (libHandle->libPath)
-	        dlFreeMem(libHandle->libPath);
-	dlFreeMem(libHandle);
-}
-
--- a/dynload/dynload_syms.c	Thu Apr 06 11:40:15 2017 +0200
+++ b/dynload/dynload_syms.c	Thu Apr 06 12:00:36 2017 +0200
@@ -6,7 +6,7 @@
  Description: 
  License:
 
-   Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>, 
+   Copyright (c) 2007-2017 Daniel Adler <dadler@uni-goettingen.de>, 
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -33,7 +33,5 @@
 #include "dynload_syms_mach-o.c"
 #elif defined(ABI_ELF)
 #include "dynload_syms_elf.c"
-#else
-void dummy() { }
 #endif
 
--- a/dynload/dynload_syms_mach-o.c	Thu Apr 06 11:40:15 2017 +0200
+++ b/dynload/dynload_syms_mach-o.c	Thu Apr 06 12:00:36 2017 +0200
@@ -6,7 +6,9 @@
  Description: 
  License:
 
-   Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>
+   Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>,
+                      2017 refactored for stability, API consistency
+                           and portability by Tassilo Philipp.
 
    Permission to use, copy, modify, and distribute this software for any
    purpose with or without fee is hereby granted, provided that the above
@@ -32,76 +34,89 @@
 
 #include "dynload.h"
 #include "dynload_alloc.h"
+#include "../autovar/autovar_ARCH.h"
 
 #include <mach-o/dyld.h>
 #include <mach-o/nlist.h>
+#include <sys/stat.h>
 #include <dlfcn.h>
 #include <string.h>
 
-#if defined(ARCH_X64) //@@@ use dyncall_macros.h
+#if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h
 #define MACH_HEADER_TYPE mach_header_64
-#define SEGMENT_COMMAND segment_command_64
 #define NLIST_TYPE nlist_64
 #else
 #define MACH_HEADER_TYPE mach_header
-#define SEGMENT_COMMAND segment_command
 #define NLIST_TYPE nlist
 #endif
 
 
-struct DLLib_
-{
-	char* libPath;
-	void* handle;
-};
-
-
 struct DLSyms_
 {
-	const char* pStringTable;
+	DLLib*                   pLib;
+	const char*              pStringTable;
 	const struct NLIST_TYPE* pSymbolTable;
-	uint32_t symbolCount;
+	uint32_t                 symbolCount;
 };
 
 
-DLSyms* dlSymsInit(const char* libPath) 
+DLSyms* dlSymsInit(const char* libPath)
 {
-	DLSyms* pSyms = NULL;
+	DLLib* pLib;
+	DLSyms* pSyms;
 	uint32_t iImage, nImages;
+	struct stat st0;
+
+	if(stat(libPath, &st0) == -1)
+		return NULL;
+
+	pLib = dlLoadLibrary(libPath);
+	if(!pLib)
+		return NULL;
+
+	// Loop over all dynamically linked images.
 	for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++)
 	{
+		struct stat st1;
 		const char* name = _dyld_get_image_name(iImage);
-		if (name && !strcmp(name, libPath))
+
+		if(name && (stat(name, &st1) != -1))
 		{
-			const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage);
-			const char* pBase = ((const char*)pHeader);
-			if (pHeader->filetype != MH_DYLIB)
-				return NULL;
-			if (pHeader->flags & MH_SPLIT_SEGS)
-				return NULL;
-
-			if (pHeader)
+			// Don't rely on name comparison alone, as libPath might be relative, symlink, differently 
+			// cased, etc., but compare inode number with the one of the mapped dyld image.
+			if (st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/)
 			{
-				uint32_t iCmd, nCmds = pHeader->ncmds;
-				const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE));
-				
-				for (iCmd = 0; iCmd < nCmds; iCmd++) 
+				const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage);
+				const char* pBase = ((const char*)pHeader);
+				if (pHeader->filetype != MH_DYLIB)
+					return NULL;
+				if (pHeader->flags & MH_SPLIT_SEGS)
+					return NULL;
+
+				if (pHeader)
 				{
-					if (cmd->cmd == LC_SYMTAB) 
+					uint32_t iCmd, nCmds = pHeader->ncmds;
+					const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE));
+
+					for (iCmd = 0; iCmd < nCmds; iCmd++) 
 					{
-						const struct symtab_command* scmd = (const struct symtab_command*)cmd;
-					
-						pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) );
-						pSyms->symbolCount = scmd->nsyms;
-						pSyms->pStringTable = pBase + scmd->stroff;
-						pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff);
-						
-						return pSyms;
+						if (cmd->cmd == LC_SYMTAB) 
+						{
+							const struct symtab_command* scmd = (const struct symtab_command*)cmd;
+
+							pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) );
+							pSyms->symbolCount  = scmd->nsyms;
+							pSyms->pStringTable = pBase + scmd->stroff;
+							pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff);
+							pSyms->pLib         = pLib;
+
+							return pSyms;
+						}
+						cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize);
 					}
-					cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize);
 				}
+				break;
 			}
-			break;
 		}
 	}
 	return NULL;
@@ -110,17 +125,15 @@
 
 void dlSymsCleanup(DLSyms* pSyms)
 {
-	if (!pSyms)
-		return;
-	
-	dlFreeMem(pSyms);
+	if(pSyms) {
+		dlFreeLibrary(pSyms->pLib);
+		dlFreeMem(pSyms);
+	}
 }
 
 int dlSymsCount(DLSyms* pSyms)
 {
-	if (!pSyms)
-		return 0;
-	return pSyms->symbolCount;
+	return pSyms ? pSyms->symbolCount : 0;
 }
 
 static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index)
@@ -128,11 +141,11 @@
 	const struct NLIST_TYPE* nl;
 	if (!pSyms)
 		return NULL;
-	
+
 	nl = pSyms->pSymbolTable + index;
 	if (nl->n_un.n_strx <= 1)
 		return NULL; // would be empty string anyway
-	
+
 	//TODO skip more symbols based on nl->n_desc and nl->n_type ?
 	return nl;
 }
@@ -141,20 +154,7 @@
 const char* dlSymsName(DLSyms* pSyms, int index)
 {
 	const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
-	if (!nl)
-		return NULL;
-	
-	return pSyms->pStringTable + nl->n_un.n_strx;
-}
-
-
-void* dlSymsValue(DLSyms* pSyms, int index)
-{
-	const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
-	if (!nl)
-		return NULL;
-	
-	return (void*) (ptrdiff_t) (nl->n_value);
+	return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL;
 }
 
 
@@ -163,6 +163,7 @@
 	Dl_info info;
 	if (!dladdr(value, &info) || (value != info.dli_saddr))
 		return NULL;
-	
+
 	return info.dli_sname;
 }
+