New function, DSO_pathbyaddr, to find pathname for loaded shared object
authorAndy Polyakov <appro@openssl.org>
Sun, 5 Jun 2005 18:13:38 +0000 (18:13 +0000)
committerAndy Polyakov <appro@openssl.org>
Sun, 5 Jun 2005 18:13:38 +0000 (18:13 +0000)
by an address within it. Tested on Linux, Solaris, IRIX, Tru64, Darwin,
HP-UX, Win32, few BSD flavors...

crypto/dso/dso.h
crypto/dso/dso_dl.c
crypto/dso/dso_dlfcn.c
crypto/dso/dso_err.c
crypto/dso/dso_lib.c
crypto/dso/dso_win32.c

index 3de99f5d00bddc23526037c5e995295ad5e1fc70..c9d736654ac54de3e712c8664d3febd55bba08f1 100644 (file)
@@ -170,6 +170,9 @@ typedef struct dso_meth_st
        /* [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 @@ DSO_METHOD *DSO_METHOD_win32(void);
 /* 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 @@ void ERR_load_DSO_strings(void);
 #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
index fd1c7582608c52c63de1854abf82fbaa9c4c2952..2de01b09e1cd93710a1e92ac4ad6c13c9d783866 100644 (file)
@@ -85,6 +85,7 @@ static int dl_ctrl(DSO *dso, int cmd, long larg, void *parg);
 #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 @@ static DSO_METHOD dso_meth_dl = {
        dl_name_converter,
        dl_merger,
        NULL, /* init */
-       NULL  /* finish */
+       NULL, /* finish */
+       dl_pathbyaddr
        };
 
 DSO_METHOD *DSO_METHOD_dl(void)
@@ -349,4 +351,27 @@ static char *dl_name_converter(DSO *dso, const char *filename)
        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 */
index 1fd10104c521ccbf29a798091faa078f0e1c81aa..67a0f3291c492511c338333cfe0bc0b91b445fbd 100644 (file)
@@ -68,6 +68,12 @@ DSO_METHOD *DSO_METHOD_dlfcn(void)
 #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 long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg);
 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 @@ static DSO_METHOD dso_meth_dlfcn = {
        dlfcn_name_converter,
        dlfcn_merger,
        NULL, /* init */
-       NULL  /* finish */
+       NULL, /* finish */
+       dlfcn_pathbyaddr
        };
 
 DSO_METHOD *DSO_METHOD_dlfcn(void)
@@ -366,4 +374,63 @@ static char *dlfcn_name_converter(DSO *dso, const char *filename)
        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 */
index aa91170b1be96ec2962175544422b4afd4743d40..a88db0dd80d9c58343f563318b071fd03a0f2d26 100644 (file)
@@ -107,6 +107,7 @@ static ERR_STRING_DATA DSO_str_functs[]=
 {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}
        };
 
index 49bdd7130976f254874f96bce0b2955995461d65..0869a646f650762f713814790cba2bff18b9f473 100644 (file)
@@ -464,3 +464,15 @@ const char *DSO_get_loaded_filename(DSO *dso)
                }
        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);
+       }
index e6eaa990052365112d4c163dc65b06e3c5961a97..96ccd4b7ee63ffdda36be8d9a79dcc370cdf3dbf 100644 (file)
@@ -85,6 +85,7 @@ static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
 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 @@ static DSO_METHOD dso_meth_win32 = {
        win32_name_converter,
        win32_merger,
        NULL, /* init */
-       NULL  /* finish */
+       NULL, /* finish */
+       win32_pathbyaddr
        };
 
 DSO_METHOD *DSO_METHOD_win32(void)
@@ -127,7 +129,7 @@ static int win32_load(DSO *dso)
                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 @@ static const char *openssl_strnchr(const char *string, int c, size_t len)
        return NULL;
        }
 
+#include <tlhelp32.h>
+#ifdef _WIN32_WCE
+# if _WIN32_WCE < 300
+static FARPROC GetProcAddressA(HMODULE hModule,LPCSTR lpProcName)
+       {
+       WCHAR lpProcNameW[64];
+       int i;
+
+       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 *);
 
-#endif /* OPENSSL_SYS_WIN32 */
+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 */