From 7ed876533aa7c8e721836c25cef737c3643f5e55 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Sun, 5 Jun 2005 18:13:38 +0000 Subject: [PATCH] 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... --- crypto/dso/dso.h | 15 +++++ crypto/dso/dso_dl.c | 27 ++++++++- crypto/dso/dso_dlfcn.c | 69 ++++++++++++++++++++++- crypto/dso/dso_err.c | 1 + crypto/dso/dso_lib.c | 12 ++++ crypto/dso/dso_win32.c | 125 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 244 insertions(+), 5 deletions(-) diff --git a/crypto/dso/dso.h b/crypto/dso/dso.h index 3de99f5d00..c9d736654a 100644 --- a/crypto/dso/dso.h +++ b/crypto/dso/dso.h @@ -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 diff --git a/crypto/dso/dso_dl.c b/crypto/dso/dso_dl.c index fd1c758260..2de01b09e1 100644 --- a/crypto/dso/dso_dl.c +++ b/crypto/dso/dso_dl.c @@ -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 */ diff --git a/crypto/dso/dso_dlfcn.c b/crypto/dso/dso_dlfcn.c index 1fd10104c5..67a0f3291c 100644 --- a/crypto/dso/dso_dlfcn.c +++ b/crypto/dso/dso_dlfcn.c @@ -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 #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): + + does not contain a prototype for dladdr or definition of + Dl_info. The #include 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 +#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 aa91170b1b..a88db0dd80 100644 --- a/crypto/dso/dso_err.c +++ b/crypto/dso/dso_err.c @@ -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} }; diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c index 49bdd71309..0869a646f6 100644 --- a/crypto/dso/dso_lib.c +++ b/crypto/dso/dso_lib.c @@ -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); + } diff --git a/crypto/dso/dso_win32.c b/crypto/dso/dso_win32.c index e6eaa99005..96ccd4b7ee 100644 --- a/crypto/dso/dso_win32.c +++ b/crypto/dso/dso_win32.c @@ -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 +#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= 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 */ -- 2.25.1