changeset 219:912efa3cfd4b

- mach-o symbol iteration stability fixes
author Tassilo Philipp
date Tue, 11 Apr 2017 09:37:14 +0200
parents cb56f077fd37
children 94dc0bdd7dbe
files dynload/dynload_syms_mach-o.c
diffstat 1 files changed, 73 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/dynload/dynload_syms_mach-o.c	Thu Apr 06 13:35:50 2017 +0200
+++ b/dynload/dynload_syms_mach-o.c	Tue Apr 11 09:37:14 2017 +0200
@@ -3,12 +3,12 @@
  Package: dyncall
  Library: dynload
  File: dynload/dynload_syms_mach-o.c
- Description: 
+ Description:
  License:
 
    Copyright (c) 2007-2015 Olivier Chafik <olivier.chafik@gmail.com>,
-                      2017 refactored for stability, API consistency
-                           and portability by Tassilo Philipp.
+                      2017 refactored completely 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
@@ -27,7 +27,7 @@
 
 
 /*
- 
+
  dynamic symbol resolver for Mach-O
 
 */
@@ -44,10 +44,12 @@
 
 #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 NLIST_TYPE nlist
+#define SEGMENT_COMMAND segment_command
 #endif
 
 
@@ -64,8 +66,9 @@
 {
 	DLLib* pLib;
 	DLSyms* pSyms;
-	uint32_t iImage, nImages;
+	uint32_t i, n;
 	struct stat st0;
+	const struct MACH_HEADER_TYPE* pHeader = NULL;
 
 	if(stat(libPath, &st0) == -1)
 		return NULL;
@@ -74,51 +77,62 @@
 	if(!pLib)
 		return NULL;
 
-	// Loop over all dynamically linked images.
-	for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++)
+	// Loop over all dynamically linked images to find ours.
+	for(i = 0, n = _dyld_image_count(); i < n; ++i)
 	{
 		struct stat st1;
-		const char* name = _dyld_get_image_name(iImage);
+		const char* name = _dyld_get_image_name(i);
 
 		if(name && (stat(name, &st1) != -1))
 		{
-			// Don't rely on name comparison alone, as libPath might be relative, symlink, differently 
+			// 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)*/)
+			if(st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/)
 			{
-				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)
-				{
-					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++) 
-					{
-						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);
-					}
-				}
-				break;
+				pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i);
+				break; // found header
 			}
 		}
 	}
+
+	if(pHeader && (pHeader->filetype == MH_DYLIB) && !(pHeader->flags & MH_SPLIT_SEGS))
+	{
+		const char* pBase = (const char*)pHeader;
+		uintptr_t slide = 0;
+		const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE));
+
+		for(i = 0, n = pHeader->ncmds; i < n; ++i, cmd = (const struct load_command*)((const char*)cmd + cmd->cmdsize))
+		{
+			if(cmd->cmd == LC_SEGMENT)
+			{
+				const struct SEGMENT_COMMAND* seg = (struct SEGMENT_COMMAND*)cmd;
+				if((seg->fileoff == 0) && (seg->filesize != 0)) // Count segment sizes to slide over...@@@?
+					slide = (uintptr_t)pHeader - seg->vmaddr;
+				if(strcmp(seg->segname, "__LINKEDIT") == 0)
+					pBase = (const char*)(seg->vmaddr - seg->fileoff + slide); // Adjust pBase depending on __LINKEDIT segment
+			}
+			else if(cmd->cmd == LC_SYMTAB)
+			{
+				const struct symtab_command* scmd = (const struct symtab_command*)cmd;
+
+				// cmd->cmdsize must be size of struct, otherwise something is off; abort
+				if(cmd->cmdsize != sizeof(struct symtab_command))
+					break;
+
+				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;
+			}
+            //@@@ handle also LC_DYSYMTAB
+		}
+	}
+
+	// Couldn't init syms, so free lib and return error.
+	dlFreeLibrary(pLib);
 	return NULL;
 }
 
@@ -136,25 +150,33 @@
 	return pSyms ? pSyms->symbolCount : 0;
 }
 
-static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index)
+
+const char* dlSymsName(DLSyms* pSyms, int index)
 {
 	const struct NLIST_TYPE* nl;
-	if (!pSyms)
+	unsigned char t;
+
+//@@@ mach-o ref: http://www.cilinder.be/docs/next/NeXTStep/3.3/nd/DevTools/14_MachO/MachO.htmld/index.html
+
+	if(!pSyms)
 		return NULL;
 
 	nl = pSyms->pSymbolTable + index;
-	if (nl->n_un.n_strx <= 1)
-		return NULL; // would be empty string anyway
+
+	// Mach-O manual: Symbols with an index into the string table of zero
+	// (n_un.n_strx == 0) are defined to have a null ("") name.
+	if(nl->n_un.n_strx == 0)
+		return NULL; //@@@ have return pointer to some static "" string?
+
+	// Skip undefined symbols. @@@ should we?
+	t = nl->n_type & N_TYPE;
+	if(t == N_UNDF || t == N_PBUD) // @@@ check if N_PBUD is defined, it's not in the NeXT manual, but on Darwin 8.0.1
+		return NULL;
 
 	//TODO skip more symbols based on nl->n_desc and nl->n_type ?
-	return nl;
-}
 
-
-const char* dlSymsName(DLSyms* pSyms, int index)
-{
-	const struct NLIST_TYPE* nl = get_nlist(pSyms, index);
-	return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL;
+	// Return name - handles lookup of indirect names.
+	return &pSyms->pStringTable[t == N_INDR ? nl->n_value : nl->n_un.n_strx];
 }