diff dynload/dynload_syms_mach-o.c @ 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 3e629dc19168
children 912efa3cfd4b
line wrap: on
line diff
--- 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;
 }
+