Esempio n. 1
0
void jl_getDylibFunctionInfo(const char **name, size_t *line, const char **filename, size_t pointer, int *fromC, int skipC)
{
#ifdef _OS_WINDOWS_
    DWORD fbase = SymGetModuleBase64(GetCurrentProcess(),(DWORD)pointer);
    char *fname = 0;
    if (fbase != 0) {
#else
    Dl_info dlinfo;
    const char *fname = 0;
    if ((dladdr((void*)pointer, &dlinfo) != 0) && dlinfo.dli_fname) {
        *fromC = !jl_is_sysimg(dlinfo.dli_fname);
        if (skipC && *fromC)
            return;
        // In case we fail with the debug info lookup, we at least still
        // have the function name, even if we don't have line numbers
        *name = dlinfo.dli_sname;
        *filename = dlinfo.dli_fname;
        uint64_t fbase = (uint64_t)dlinfo.dli_fbase;
#endif
        obfiletype::iterator it = objfilemap.find(fbase);
        llvm::object::ObjectFile *obj = NULL;
        DIContext *context = NULL;
        int64_t slide = 0;
#ifndef _OS_WINDOWS_
        fname = dlinfo.dli_fname;
#else
        IMAGEHLP_MODULE64 ModuleInfo;
        ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
        SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo);
        fname = ModuleInfo.LoadedImageName;
        *fromC = !jl_is_sysimg(fname);
        if (skipC && *fromC)
            return;
#endif
        if (it == objfilemap.end()) {
#ifdef _OS_DARWIN_
           // First find the uuid of the object file (we'll use this to make sure we find the
           // correct debug symbol file).
           uint8_t uuid[16], uuid2[16];
#ifdef LLVM36
	   std::unique_ptr<MemoryBuffer> membuf = MemoryBuffer::getMemBuffer(
                StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false);
	   auto origerrorobj = llvm::object::ObjectFile::createObjectFile(
	        membuf->getMemBufferRef(), sys::fs::file_magic::unknown);
#elif LLVM35
            MemoryBuffer *membuf = MemoryBuffer::getMemBuffer(
                StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false);
            std::unique_ptr<MemoryBuffer> buf(membuf);
            auto origerrorobj = llvm::object::ObjectFile::createObjectFile(
                buf, sys::fs::file_magic::unknown);
#else
            MemoryBuffer *membuf = MemoryBuffer::getMemBuffer(
	        StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false);
            llvm::object::ObjectFile *origerrorobj = llvm::object::ObjectFile::createObjectFile(
                membuf);
#endif
            if (!origerrorobj) {
                objfileentry_t entry = {obj,context,slide};
                objfilemap[fbase] = entry;
                goto lookup;
            }
#ifdef LLVM36
            llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get().release();
#elif LLVM35
            llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get();
#else
            llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj;
#endif
            if (!getObjUUID(morigobj,uuid)) {
                objfileentry_t entry = {obj,context,slide};
                objfilemap[fbase] = entry;
                goto lookup;
            }

            // On OS X debug symbols are not contained in the dynamic library and that's why
            // we can't have nice things (easily). For now we only support .dSYM files in the same directory
            // as the shared library. In the future we may use DBGCopyFullDSYMURLForUUID from CoreFoundation to make
            // use of spotlight to find the .dSYM file.
            char dsympath[PATH_MAX];
            strlcpy(dsympath, dlinfo.dli_fname, sizeof(dsympath));
            strlcat(dsympath, ".dSYM/Contents/Resources/DWARF/", sizeof(dsympath));
            strlcat(dsympath, strrchr(dlinfo.dli_fname,'/')+1, sizeof(dsympath));
#ifdef LLVM35
            auto errorobj = llvm::object::ObjectFile::createObjectFile(dsympath);
#else
            llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(dsympath);
#endif
#else
            // On non OS X systems we need to mmap another copy because of the permissions on the mmaped
            // shared library.
#ifdef LLVM35
            auto errorobj = llvm::object::ObjectFile::createObjectFile(fname);
#else
            llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(fname);
#endif
#endif
#ifdef LLVM36
            if (errorobj) {
                obj = errorobj.get().getBinary().release();
                errorobj.get().getBuffer().release();
#elif LLVM35
            if (errorobj) {
                obj = errorobj.get();
#else
            if (errorobj != NULL) {
                obj = errorobj;
#endif
#ifdef _OS_DARWIN_
                if (getObjUUID(morigobj,uuid2) && memcmp(uuid,uuid2,sizeof(uuid)) == 0) {
#endif
#ifdef LLVM36
                    context = DIContext::getDWARFContext(*obj);
#else
                    context = DIContext::getDWARFContext(obj);
#endif
                    slide = -(uint64_t)fbase;
#ifdef _OS_DARWIN_
                }
#endif
#ifdef _OS_WINDOWS_
                assert(obj->isCOFF());
                llvm::object::COFFObjectFile *coffobj = (llvm::object::COFFObjectFile *)obj;
                const llvm::object::pe32plus_header *pe32plus;
                coffobj->getPE32PlusHeader(pe32plus);
                if (pe32plus != NULL) {
                    slide = pe32plus->ImageBase-fbase;
                }
                else {
                    const llvm::object::pe32_header *pe32;
                    coffobj->getPE32Header(pe32); 
                    if (pe32 == NULL) {
                        obj = NULL;
                        context = NULL;
                    }
                    else {
                        slide = pe32->ImageBase-fbase;
                    }
                }
#endif

            }
            objfileentry_t entry = {obj,context,slide};
            objfilemap[fbase] = entry;
        }
        else {
            obj = it->second.obj;
            context = it->second.ctx;
            slide = it->second.slide;
        }
#ifdef _OS_DARWIN_
    lookup:
#endif
        lookup_pointer(context, name, line, filename, pointer+slide, jl_is_sysimg(fname), fromC);
        return;
    }
    *fromC = 1;
    return;
}
#endif

void jl_getFunctionInfo(const char **name, size_t *line, const char **filename, size_t pointer, int *fromC, int skipC)
{
    *name = NULL;
    *line = -1;
    *filename = "no file";
    *fromC = 0;

#if USE_MCJIT
// With MCJIT we can get function information directly from the ObjectFile
    std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap();
    std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(pointer);

    if (it == objmap.end())
        return jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC);
    if ((pointer - it->first) > it->second.size)
        return jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC);

#ifdef LLVM36
    DIContext *context = DIContext::getDWARFContext(*it->second.object);
#else
    DIContext *context = DIContext::getDWARFContext(it->second.object);
#endif
    lookup_pointer(context, name, line, filename, pointer, 1, fromC);

#else // !USE_MCJIT

// Without MCJIT we use the FuncInfo structure containing address maps
    std::map<size_t, FuncInfo, revcomp> &info = jl_jit_events->getMap();
    std::map<size_t, FuncInfo, revcomp>::iterator it = info.lower_bound(pointer);
    if (it != info.end() && (size_t)(*it).first + (*it).second.lengthAdr >= pointer) {
        // We do this to hide the jlcall wrappers when getting julia backtraces,
        // but it is still good to have them for regular lookup of C frames.
        if (skipC && (*it).second.lines.empty()) {
            // Technically not true, but we don't want them
            // in julia backtraces, so close enough
            *fromC = 1;
            return;
        }

        *name = (*it).second.name.c_str();
        *filename = (*it).second.filename.c_str();

        if ((*it).second.lines.empty()) {
            *fromC = 1;
            return;
        }

        std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit =
            (*it).second.lines.begin();
        JITEvent_EmittedFunctionDetails::LineStart prev = *vit;

        if ((*it).second.func) {
            DISubprogram debugscope =
                DISubprogram(prev.Loc.getScope((*it).second.func->getContext()));
            *filename = debugscope.getFilename().data();
            // the DISubprogram has the un-mangled name, so use that if
            // available. However, if the scope need not be the current
            // subprogram.
            if (debugscope.getName().data() != NULL)
                *name = debugscope.getName().data();
            else
                *name = jl_demangle(*name);
        }

        vit++;

        while (vit != (*it).second.lines.end()) {
            if (pointer <= (*vit).Address) {
                *line = prev.Loc.getLine();
                break;
            }
            prev = *vit;
            vit++;
        }
        if (*line == (size_t) -1) {
            *line = prev.Loc.getLine();
        }
    }
    else {
        jl_getDylibFunctionInfo(name,line,filename,pointer,fromC,skipC);
    }
#endif // USE_MCJIT
}
Esempio n. 2
0
void jl_getFunctionInfo(const char **name, int *line, const char **filename, size_t pointer, int skipC)
{
    *name = NULL;
    *line = -1;
    *filename = "no file";

#if USE_MCJIT
// With MCJIT we can get function information directly from the ObjectFile
    std::map<size_t, ObjectInfo, revcomp> &objmap = jl_jit_events->getObjectMap();
    std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(pointer);

    if (it == objmap.end())
        return jl_getDylibFunctionInfo(name,line,filename,pointer,skipC);
    if ((pointer - it->first) > it->second.size)
        return jl_getDylibFunctionInfo(name,line,filename,pointer,skipC);

    DIContext *context = DIContext::getDWARFContext(it->second.object);
    lookup_pointer(context, name, line, filename, pointer, 1);

#else // !USE_MCJIT

// Without MCJIT we use the FuncInfo structure containing address maps
    std::map<size_t, FuncInfo, revcomp> &info = jl_jit_events->getMap();
    std::map<size_t, FuncInfo, revcomp>::iterator it = info.lower_bound(pointer);
    if (it != info.end() && (size_t)(*it).first + (*it).second.lengthAdr >= pointer) {
        // commenting these lines out skips functions that don't
        // have explicit debug info. this is useful for hiding
        // the jlcall wrapper functions we generate.
#if LLVM_VERSION_MAJOR == 3
#if LLVM_VERSION_MINOR == 0
        //*name = &(*(*it).second.func).getNameStr()[0];
#elif LLVM_VERSION_MINOR >= 1
        //*name = (((*(*it).second.func).getName()).data());
#endif
#endif
        std::vector<JITEvent_EmittedFunctionDetails::LineStart>::iterator vit =
            (*it).second.lines.begin();
        JITEvent_EmittedFunctionDetails::LineStart prev = *vit;

        if ((*it).second.func) {
            DISubprogram debugscope =
                DISubprogram(prev.Loc.getScope((*it).second.func->getContext()));
            *filename = debugscope.getFilename().data();
            // the DISubprogram has the un-mangled name, so use that if
            // available.
            *name = debugscope.getName().data();
        }
        else {
            *name = (*it).second.name.c_str();
            *filename = (*it).second.filename.c_str();
        }

        vit++;

        while (vit != (*it).second.lines.end()) {
            if (pointer <= (*vit).Address) {
                *line = prev.Loc.getLine();
                break;
            }
            prev = *vit;
            vit++;
        }
        if (*line == -1) {
            *line = prev.Loc.getLine();
        }
    }
    else {
        jl_getDylibFunctionInfo(name,line,filename,pointer,skipC);
    }
#endif // USE_MCJIT
}