New function, DSO_pathbyaddr, to find pathname for loaded shared object
by an address within it. Tested on Linux, Solaris, IRIX, Tru64, Darwin,
HP-UX, Win32, few BSD flavors...
diff --git a/crypto/dso/dso.h b/crypto/dso/dso.h
index 3de99f5..c9d7366 100644
--- a/crypto/dso/dso.h
+++ b/crypto/dso/dso.h
@@ -170,6 +170,9 @@
 	/* [De]Initialisation handlers. */
 	int (*init)(DSO *dso);
 	int (*finish)(DSO *dso);
+
+	/* Return pathname of the module containing location */
+	int (*pathbyaddr)(void *addr,char *path,int sz);
 	} DSO_METHOD;
 
 /**********************************************************************/
@@ -296,6 +299,17 @@
 /* If VMS is defined, use shared images. If not, return NULL. */
 DSO_METHOD *DSO_METHOD_vms(void);
 
+/* This function writes null-terminated pathname of DSO module
+ * containing 'addr' into 'sz' large caller-provided 'path' and
+ * returns the number of characters [including trailing zero]
+ * written to it. If 'sz' is 0 or negative, 'path' is ignored and
+ * required amount of charachers [including trailing zero] to
+ * accomodate pathname is returned. If 'addr' is NULL, then
+ * pathname of cryptolib itself is returned. Negative or zero
+ * return value denotes error.
+ */
+int DSO_pathbyaddr(void *addr,char *path,int sz);
+
 /* BEGIN ERROR CODES */
 /* The following lines are auto generated by the script mkerr.pl. Any changes
  * made after this point may be overwritten when the script is next run.
@@ -342,6 +356,7 @@
 #define DSO_F_WIN32_NAME_CONVERTER			 125
 #define DSO_F_WIN32_SPLITTER				 136
 #define DSO_F_WIN32_UNLOAD				 121
+#define DSO_F_PATHBYADDR				 137
 
 /* Reason codes. */
 #define DSO_R_CTRL_FAILED				 100
diff --git a/crypto/dso/dso_dl.c b/crypto/dso/dso_dl.c
index fd1c758..2de01b0 100644
--- a/crypto/dso/dso_dl.c
+++ b/crypto/dso/dso_dl.c
@@ -85,6 +85,7 @@
 #endif
 static char *dl_name_converter(DSO *dso, const char *filename);
 static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2);
+static int dl_pathbyaddr(void *addr,char *path,int sz);
 
 static DSO_METHOD dso_meth_dl = {
 	"OpenSSL 'dl' shared library method",
@@ -101,7 +102,8 @@
 	dl_name_converter,
 	dl_merger,
 	NULL, /* init */
-	NULL  /* finish */
+	NULL, /* finish */
+	dl_pathbyaddr
 	};
 
 DSO_METHOD *DSO_METHOD_dl(void)
@@ -349,4 +351,27 @@
 	return(translated);
 	}
 
+static int dl_pathbyaddr(void *addr,char *path,int sz)
+	{
+	struct shl_descriptor inf;
+	int i,len;
+
+	if (addr == NULL) addr = dl_pathbyaddr;
+
+	for (i=-1;shl_get_r(i,&inf)==0;i++)
+		{
+		if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) ||
+		    ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend))
+			{
+			len = (int)strlen(inf.filename);
+			if (sz <= 0) return len+1;
+			if (len >= sz) len=sz-1;
+			memcpy(path,inf.filename,len);
+			path[len++] = 0;
+			return len;
+			}
+		}
+
+	return -1;
+	}
 #endif /* DSO_DL */
diff --git a/crypto/dso/dso_dlfcn.c b/crypto/dso/dso_dlfcn.c
index 1fd1010..67a0f32 100644
--- a/crypto/dso/dso_dlfcn.c
+++ b/crypto/dso/dso_dlfcn.c
@@ -68,6 +68,12 @@
 #else
 
 #ifdef HAVE_DLFCN_H
+
+#ifdef __linux
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE	/* make sure dladdr is declared */
+# endif
+#endif
 #include <dlfcn.h>
 #endif
 
@@ -87,6 +93,7 @@
 static char *dlfcn_name_converter(DSO *dso, const char *filename);
 static char *dlfcn_merger(DSO *dso, const char *filespec1,
 	const char *filespec2);
+static int dlfcn_pathbyaddr(void *addr,char *path,int sz);
 
 static DSO_METHOD dso_meth_dlfcn = {
 	"OpenSSL 'dlfcn' shared library method",
@@ -103,7 +110,8 @@
 	dlfcn_name_converter,
 	dlfcn_merger,
 	NULL, /* init */
-	NULL  /* finish */
+	NULL, /* finish */
+	dlfcn_pathbyaddr
 	};
 
 DSO_METHOD *DSO_METHOD_dlfcn(void)
@@ -366,4 +374,63 @@
 	return(translated);
 	}
 
+#ifdef __sgi
+#if 0
+This is a quote from IRIX manual for dladdr(3c):
+
+     <dlfcn.h> does not contain a prototype for dladdr or definition of
+     Dl_info.  The #include <dlfcn.h>  in the SYNOPSIS line is traditional,
+     but contains no dladdr prototype and no IRIX library contains an
+     implementation.  Write your own declaration based on the code below.
+
+     The following code is dependent on internal interfaces that are not
+     part of the IRIX compatibility guarantee; however, there is no future
+     intention to change this interface, so on a practical level, the code
+     below is safe to use on IRIX.
+#endif
+#include <rld_interface.h>
+#ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
+#define _RLD_INTERFACE_DLFCN_H_DLADDR
+typedef struct Dl_info {
+    const char * dli_fname;
+    void       * dli_fbase;
+    const char * dli_sname;
+    void       * dli_saddr;
+    int          dli_version;
+    int          dli_reserved1;
+    long         dli_reserved[4];
+} Dl_info;
+#else
+typedef struct Dl_info Dl_info;
+#endif
+#define _RLD_DLADDR             14
+
+static int dladdr(void *address, Dl_info *dl)
+{
+	void *v;
+	v = _rld_new_interface(_RLD_DLADDR,address,dl);
+	return (int)v;
+}
+#endif
+
+static int dlfcn_pathbyaddr(void *addr,char *path,int sz)
+	{
+	Dl_info dli;
+	int len;
+
+	if (addr == NULL) addr = dlfcn_pathbyaddr;
+
+	if (dladdr(addr,&dli))
+		{
+		len = (int)strlen(dli.dli_fname);
+		if (sz <= 0) return len+1;
+		if (len >= sz) len=sz-1;
+		memcpy(path,dli.dli_fname,len);
+		path[len++]=0;
+		return len;
+		}
+
+	ERR_add_error_data(4, "dlfcn_pathbyaddr(): ", dlerror());
+	return -1;
+	}
 #endif /* DSO_DLFCN */
diff --git a/crypto/dso/dso_err.c b/crypto/dso/dso_err.c
index aa91170..a88db0d 100644
--- a/crypto/dso/dso_err.c
+++ b/crypto/dso/dso_err.c
@@ -107,6 +107,7 @@
 {ERR_FUNC(DSO_F_WIN32_NAME_CONVERTER),	"WIN32_NAME_CONVERTER"},
 {ERR_FUNC(DSO_F_WIN32_SPLITTER),	"WIN32_SPLITTER"},
 {ERR_FUNC(DSO_F_WIN32_UNLOAD),	"WIN32_UNLOAD"},
+{ERR_FUNC(DSO_F_PATHBYADDR),	"DSO_pathbyaddr"},
 {0,NULL}
 	};
 
diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c
index 49bdd71..0869a64 100644
--- a/crypto/dso/dso_lib.c
+++ b/crypto/dso/dso_lib.c
@@ -464,3 +464,15 @@
 		}
 	return(dso->loaded_filename);
 	}
+
+int DSO_pathbyaddr(void *addr,char *path,int sz)
+	{
+	DSO_METHOD *meth = default_DSO_meth;
+	if (meth == NULL) meth = DSO_METHOD_openssl();
+	if (meth->pathbyaddr == NULL)
+		{
+		DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
+		return(NULL);
+		}
+	return (*meth->pathbyaddr)(addr,path,sz);
+	}
diff --git a/crypto/dso/dso_win32.c b/crypto/dso/dso_win32.c
index e6eaa99..96ccd4b 100644
--- a/crypto/dso/dso_win32.c
+++ b/crypto/dso/dso_win32.c
@@ -85,6 +85,7 @@
 static char *win32_name_converter(DSO *dso, const char *filename);
 static char *win32_merger(DSO *dso, const char *filespec1,
 	const char *filespec2);
+static int win32_pathbyaddr(void *addr,char *path,int sz);
 
 static const char *openssl_strnchr(const char *string, int c, size_t len);
 
@@ -103,7 +104,8 @@
 	win32_name_converter,
 	win32_merger,
 	NULL, /* init */
-	NULL  /* finish */
+	NULL, /* finish */
+	win32_pathbyaddr
 	};
 
 DSO_METHOD *DSO_METHOD_win32(void)
@@ -127,7 +129,7 @@
 		DSOerr(DSO_F_WIN32_LOAD,DSO_R_NO_FILENAME);
 		goto err;
 		}
-	h = LoadLibrary(filename);
+	h = LoadLibraryA(filename);
 	if(h == NULL)
 		{
 		DSOerr(DSO_F_WIN32_LOAD,DSO_R_LOAD_FAILED);
@@ -593,5 +595,122 @@
 	return NULL;
 	}
 
+#include <tlhelp32.h>
+#ifdef _WIN32_WCE
+# if _WIN32_WCE < 300
+static FARPROC GetProcAddressA(HMODULE hModule,LPCSTR lpProcName)
+	{
+	WCHAR lpProcNameW[64];
+	int i;
 
-#endif /* OPENSSL_SYS_WIN32 */
+	for (i=0;lpProcName[i] && i<64;i++)
+		lpProcNameW[i] = (WCHAR)lpProcName[i];
+	if (i==64) return NULL;
+	lpProcNameW[i] = 0;
+
+	return GetProcAddressW(hModule,lpProcNameW);
+	}
+# endif
+# undef GetProcAddress
+# define GetProcAddress GetProcAddressA
+# define DLLNAME "TOOLHELP.DLL"
+#else
+# ifdef MODULEENTRY32
+# undef MODULEENTRY32	/* unmask the ASCII version! */
+# endif
+# define DLLNAME "KERNEL32.DLL"
+#endif
+
+typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
+typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
+typedef BOOL (WINAPI *MODULE32)(HANDLE, MODULEENTRY32 *);
+
+static int win32_pathbyaddr(void *addr,char *path,int sz)
+	{
+	HMODULE dll;
+	HANDLE hModuleSnap = INVALID_HANDLE_VALUE; 
+	MODULEENTRY32 me32; 
+	CREATETOOLHELP32SNAPSHOT create_snap;
+	CLOSETOOLHELP32SNAPSHOT  close_snap;
+	MODULE32 module_first, module_next;
+	int len;
+ 
+	if (addr == NULL) addr = win32_pathbyaddr;
+
+	dll = LoadLibrary(TEXT(DLLNAME));
+	if (dll == NULL)
+		{
+		DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
+		return -1;
+		}
+
+	create_snap = (CREATETOOLHELP32SNAPSHOT)
+		GetProcAddress(dll,"CreateToolhelp32Snapshot");
+	if (create_snap == NULL)
+		{
+		DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
+		return -1;
+		}
+	/* We take the rest for granted... */
+#ifdef _WIN32_WCE
+	close_snap = (CLOSETOOLHELP32SNAPSHOT)
+		GetProcAddress(dll,"CloseToolhelp32Snapshot");
+#else
+	close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle;
+#endif
+	module_first = (MODULE32)GetProcAddress(dll,"Module32First");
+	module_next  = (MODULE32)GetProcAddress(dll,"Module32Next");
+
+	hModuleSnap = (*create_snap)(TH32CS_SNAPMODULE,0); 
+	if( hModuleSnap == INVALID_HANDLE_VALUE ) 
+		{ 
+		FreeLibrary(dll);
+		DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
+		return -1;
+		} 
+ 
+	me32.dwSize = sizeof(me32); 
+ 
+	if(!(*module_first)(hModuleSnap,&me32)) 
+		{ 
+		(*close_snap)(hModuleSnap);
+		FreeLibrary(dll);
+		DSOerr(DSO_F_PATHBYADDR,DSO_R_FAILURE);
+		return -1;
+		}
+ 
+	do	{ 
+		if ((BYTE *)addr >= me32.modBaseAddr &&
+		    (BYTE *)addr <  me32.modBaseAddr+me32.modBaseSize)
+			{
+			(*close_snap)(hModuleSnap);
+			FreeLibrary(dll);
+#ifdef _WIN32_WCE
+# if _WIN32_WCE >= 101
+			return WideCharToMultiByte(CP_ACP,0,me32.szExePath,-1,
+							path,sz,NULL,NULL);
+# else
+			len = (int)wcslen(me32.szExePath);
+			if (sz <= 0) return len+1;
+			if (len >= sz) len=sz-1;
+			for(i=0;i<len;i++)
+				path[i] = (char)me32.szExePath[i];
+			path[len++] = 0;
+			return len;
+# endif
+#else
+			len = (int)strlen(me32.szExePath);
+			if (sz <= 0) return len+1;
+			if (len >= sz) len=sz-1;
+			memcpy(path,me32.szExePath,len);
+			path[len++] = 0;
+			return len;
+#endif
+			} 
+		} while((*module_next)(hModuleSnap, &me32)); 
+ 
+	(*close_snap)(hModuleSnap); 
+	FreeLibrary(dll);
+	return 0;
+	}
+#endif /* DSO_WIN32 */