return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib));
PR_IMPLEMENT(char *)PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr){#if defined(SOLARIS) || defined(LINUX) || defined(FREEBSD)    Dl_info dli;    char *result;    if (dladdr((void *)addr, &dli) == 0) {        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());        DLLErrorInternal(_MD_ERRNO());        return NULL;    }    result = PR_Malloc(strlen(dli.dli_fname)+1);    if (result != NULL) {        strcpy(result, dli.dli_fname);    }    return result;#elif defined(USE_MACH_DYLD)    char *result;    char *image_name;    int i, count = _dyld_image_count();    for (i = 0; i < count; i++) {        image_name = _dyld_get_image_name(i);        if (strstr(image_name, name) != NULL) {            result = PR_Malloc(strlen(image_name)+1);            if (result != NULL) {                strcpy(result, image_name);            }            return result;        }    }    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);    return NULL;#elif defined(AIX)    char *result;#define LD_INFO_INCREMENT 64    struct ld_info *info;    unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info);    struct ld_info *infop;    for (;;) {        info = PR_Malloc(info_length);        if (info == NULL) {            return NULL;        }        /* If buffer is too small, loadquery fails with ENOMEM. */        if (loadquery(L_GETINFO, info, info_length) != -1) {            break;        }        PR_Free(info);        if (errno != ENOMEM) {            /* should not happen */            _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());            return NULL;        }        /* retry with a larger buffer */        info_length += LD_INFO_INCREMENT * sizeof(struct ld_info);    }    for (infop = info;         ;         infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) {        if (strstr(infop->ldinfo_filename, name) != NULL) {            result = PR_Malloc(strlen(infop->ldinfo_filename)+1);            if (result != NULL) {                strcpy(result, infop->ldinfo_filename);            }            break;        }        if (!infop->ldinfo_next) {            PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);            result = NULL;            break;        }    }    PR_Free(info);    return result;#elif defined(OSF1)    /* Contributed by Steve Streeter of HP */    ldr_process_t process, ldr_my_process();    ldr_module_t mod_id;    ldr_module_info_t info;    ldr_region_t regno;    ldr_region_info_t reginfo;    size_t retsize;    int rv;    char *result;    /* Get process for which dynamic modules will be listed */    process = ldr_my_process();    /* Attach to process */    rv = ldr_xattach(process);    if (rv) {        /* should not happen */        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());        return NULL;    }    /* Print information for list of modules */    mod_id = LDR_NULL_MODULE;    for (;;) {        /* Get information for the next module in the module list. */        ldr_next_module(process, &mod_id);        if (ldr_inq_module(process, mod_id, &info, sizeof(info),                           &retsize) != 0) {            /* No more modules */            break;        }        if (retsize < sizeof(info)) {            continue;        }        /*         * Get information for each region in the module and check if any         * contain the address of this function.         */        for (regno = 0; ; regno++) {            if (ldr_inq_region(process, mod_id, regno, &reginfo,                               sizeof(reginfo), &retsize) != 0) {                /* No more regions */                break;            }            if (((unsigned long)reginfo.lri_mapaddr <=                (unsigned long)addr) &&                (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) >                (unsigned long)addr)) {                /* Found it. */                result = PR_Malloc(strlen(info.lmi_name)+1);                if (result != NULL) {                    strcpy(result, info.lmi_name);                }                return result;            }        }    }    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);    return NULL;#elif defined(VMS)    /* Contributed by Colin Blake of HP */    struct _imcb	*icb;    ulong_t 		status;    char                device_name[MAX_DEVNAM];    int                 device_name_len;    $DESCRIPTOR         (device_name_desc, device_name);    struct fibdef	fib;    struct dsc$descriptor_s fib_desc = 	{ sizeof(struct fibdef), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&fib } ;    IOSB		iosb;    ITMLST		devlst[2] = {            		{MAX_DEVNAM, DVI$_ALLDEVNAM, device_name, &device_name_len},            		{0,0,0,0}};    short               file_name_len;    char                file_name[MAX_FILNAM+1];    char		*result = NULL;    struct dsc$descriptor_s file_name_desc = 	{ MAX_FILNAM, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &file_name[0] } ;    /*    ** The address for the process image list could change in future versions    ** of the operating system. 7FFD0688 is valid for V7.2 and V7.3 releases,    ** so we use that for the default, but allow an environment variable    ** (logical name) to override.    */    if (IAC$GL_IMAGE_LIST == NULL) {        char *p = getenv("MOZILLA_IAC_GL_IMAGE_LIST");        if (p)            IAC$GL_IMAGE_LIST = (struct _imcb *) strtol(p,NULL,0);        else            IAC$GL_IMAGE_LIST = (struct _imcb *) 0x7FFD0688;    }    for (icb = IAC$GL_IMAGE_LIST->imcb$l_flink;         icb != IAC$GL_IMAGE_LIST;         icb = icb->imcb$l_flink) {        if (((void *)addr >= icb->imcb$l_starting_address) && 	    ((void *)addr <= icb->imcb$l_end_address)) {	    /*	    ** This is the correct image.	    ** Get the device name.	    */	    status = sys$getdviw(0,icb->imcb$w_chan,0,&devlst,0,0,0,0);	    if ($VMS_STATUS_SUCCESS(status))		device_name_desc.dsc$w_length = device_name_len;	    /*	    ** Get the FID.	    */	    memset(&fib,0,sizeof(struct fibdef));	    status = sys$qiow(0,icb->imcb$w_chan,IO$_ACCESS,&iosb,                		0,0,&fib_desc,0,0,0,0,0);	    /*	    ** If we got the FID, now look up its name (if for some reason	    ** we didn't get the device name, this call will fail).	    */	    if (($VMS_STATUS_SUCCESS(status)) && ($VMS_STATUS_SUCCESS(iosb.cond))) {		status = lib$fid_to_name (                    &device_name_desc,                    &fib.fib$w_fid,                    &file_name_desc,                    &file_name_len,                    0, 0);		/*		** If we succeeded then remove the version number and		** return a copy of the UNIX format version of the file name.		*/		if ($VMS_STATUS_SUCCESS(status)) {		    char *p, *result;		    file_name[file_name_len] = 0;		    p = strrchr(file_name,';');		    if (p) *p = 0;		    p = decc$translate_vms(&file_name[0]);		    result = PR_Malloc(strlen(p)+1);		    if (result != NULL) {			strcpy(result, p);		    }		    return result;		}            }	}    }    /* Didn't find it */    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);    return NULL;#elif defined(HPUX) && defined(USE_HPSHL)    int index;    struct shl_descriptor desc;    char *result;    for (index = 0; shl_get_r(index, &desc) == 0; index++) {        if (strstr(desc.filename, name) != NULL) {            result = PR_Malloc(strlen(desc.filename)+1);            if (result != NULL) {                strcpy(result, desc.filename);            }            return result;        }    }    /*     * Since the index value of a library is decremented if     * a library preceding it in the shared library search     * list was unloaded, it is possible that we missed some     * libraries as we went up the list.  So we should go     * down the list to be sure that we not miss anything.     */    for (index--; index >= 0; index--) {        if ((shl_get_r(index, &desc) == 0)                && (strstr(desc.filename, name) != NULL)) {            result = PR_Malloc(strlen(desc.filename)+1);            if (result != NULL) {                strcpy(result, desc.filename);            }            return result;        }    }    PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0);    return NULL;#elif defined(HPUX) && defined(USE_DLFCN)    struct load_module_desc desc;    char *result;    const char *module_name;    if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) {        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());        DLLErrorInternal(_MD_ERRNO());        return NULL;    }    module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0);    if (module_name == NULL) {        /* should not happen */        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());        DLLErrorInternal(_MD_ERRNO());        return NULL;    }    result = PR_Malloc(strlen(module_name)+1);    if (result != NULL) {        strcpy(result, module_name);    }    return result;#elif defined(WIN32)    HMODULE handle;    char module_name[MAX_PATH];    char *result;    handle = GetModuleHandle(name);    if (handle == NULL) {        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());        DLLErrorInternal(_MD_ERRNO());        return NULL;    }    if (GetModuleFileName(handle, module_name, sizeof module_name) == 0) {        /* should not happen */        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());        return NULL;    }    result = PR_Malloc(strlen(module_name)+1);    if (result != NULL) {        strcpy(result, module_name);    }    return result;#elif defined(XP_OS2)    HMODULE module = NULL;    char module_name[_MAX_PATH];    char *result;    APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr);    if ((NO_ERROR != ulrc) || (NULL == module) ) {        PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO());        DLLErrorInternal(_MD_ERRNO());        return NULL;    }    ulrc = DosQueryModuleName(module, sizeof module_name, module_name);    if (NO_ERROR != ulrc) {        /* should not happen */        _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO());        return NULL;    }    result = PR_Malloc(strlen(module_name)+1);    if (result != NULL) {        strcpy(result, module_name);    }    return result;#else    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);    return NULL;#endif}