From 2cf85b615ef3a3264b670e0ef2bff8a64532a0e8 Mon Sep 17 00:00:00 2001 From: pchintalapudi <34727397+pchintalapudi@users.noreply.github.com> Date: Tue, 24 May 2022 23:12:07 +0200 Subject: [PATCH] Fix use-after-free bugs in debuginfo (#45016) Co-authored-by: Dilum Aluthge --- src/Makefile | 8 +- src/codegen.cpp | 3 - src/debug-registry.h | 183 ++++++++++++ src/debuginfo.cpp | 670 +++++++++++++++++++++---------------------- src/jitlayers.h | 7 + src/processor.h | 5 + 6 files changed, 529 insertions(+), 347 deletions(-) create mode 100644 src/debug-registry.h diff --git a/src/Makefile b/src/Makefile index b7235597fd08c..e0ab9568fd242 100644 --- a/src/Makefile +++ b/src/Makefile @@ -279,12 +279,12 @@ $(BUILDDIR)/julia_flisp.boot: $(addprefix $(SRCDIR)/,jlfrontend.scm flisp/aliase # additional dependency links $(BUILDDIR)/codegen-stubs.o $(BUILDDIR)/codegen-stubs.dbg.obj: $(SRCDIR)/intrinsics.h -$(BUILDDIR)/aotcompile.o $(BUILDDIR)/aotcompile.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h +$(BUILDDIR)/aotcompile.o $(BUILDDIR)/aotcompile.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h $(SRCDIR)/debug-registry.h $(BUILDDIR)/ast.o $(BUILDDIR)/ast.dbg.obj: $(BUILDDIR)/julia_flisp.boot.inc $(SRCDIR)/flisp/*.h $(BUILDDIR)/builtins.o $(BUILDDIR)/builtins.dbg.obj: $(SRCDIR)/iddict.c $(SRCDIR)/builtin_proto.h $(BUILDDIR)/codegen.o $(BUILDDIR)/codegen.dbg.obj: $(addprefix $(SRCDIR)/,\ - intrinsics.cpp jitlayers.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h) -$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h) + intrinsics.cpp jitlayers.h debug-registry.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h) +$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h jitlayers.h debug-registry.h) $(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h $(BUILDDIR)/dump.o $(BUILDDIR)/dump.dbg.obj: $(addprefix $(SRCDIR)/,common_symbols1.inc common_symbols2.inc builtin_proto.h serialize.h) $(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc.h @@ -292,7 +292,7 @@ $(BUILDDIR)/gc-pages.o $(BUILDDIR)/gc-pages.dbg.obj: $(SRCDIR)/gc.h $(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-alloc-profiler.h $(BUILDDIR)/init.o $(BUILDDIR)/init.dbg.obj: $(SRCDIR)/builtin_proto.h $(BUILDDIR)/interpreter.o $(BUILDDIR)/interpreter.dbg.obj: $(SRCDIR)/builtin_proto.h -$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h +$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h $(SRCDIR)/debug-registry.h $(BUILDDIR)/jltypes.o $(BUILDDIR)/jltypes.dbg.obj: $(SRCDIR)/builtin_proto.h $(build_shlibdir)/libllvmcalltest.$(SHLIB_EXT): $(SRCDIR)/codegen_shared.h $(BUILDDIR)/julia_version.h $(BUILDDIR)/llvm-alloc-helpers.o $(BUILDDIR)/llvm-alloc-helpers.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/llvm-alloc-helpers.h diff --git a/src/codegen.cpp b/src/codegen.cpp index cccb4b12cfc1d..517577df0f324 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8155,8 +8155,6 @@ char jl_using_oprofile_jitevents = 0; // Non-zero if running under OProfile char jl_using_perf_jitevents = 0; #endif -void jl_init_debuginfo(void); - extern "C" void jl_init_llvm(void) { builtin_func_map = @@ -8199,7 +8197,6 @@ extern "C" void jl_init_llvm(void) jl_default_debug_info_kind = (int) DICompileUnit::DebugEmissionKind::FullDebug; imaging_mode = jl_options.image_codegen || (jl_generating_output() && !jl_options.incremental); jl_default_cgparams.generic_context = jl_nothing; - jl_init_debuginfo(); InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); diff --git a/src/debug-registry.h b/src/debug-registry.h new file mode 100644 index 0000000000000..dfdb09ca84519 --- /dev/null +++ b/src/debug-registry.h @@ -0,0 +1,183 @@ +#include +#include +#include + +#include "julia_internal.h" +#include "processor.h" + +#include +#include +#include + +typedef struct { + const llvm::object::ObjectFile *obj; + llvm::DIContext *ctx; + int64_t slide; +} objfileentry_t; + + +// Central registry for resolving function addresses to `jl_method_instance_t`s and +// originating `ObjectFile`s (for the DWARF debug info). +// +// A global singleton instance is notified by the JIT whenever a new object is emitted, +// and later queried by the various function info APIs. We also use the chance to handle +// some platform-specific unwind info registration (which is unrelated to the query +// functionality). +class JITDebugInfoRegistry +{ +public: + template + struct Locked { + + template + struct Lock { + std::unique_lock lock; + CResourceT &resource; + + Lock(std::mutex &mutex, CResourceT &resource) JL_NOTSAFEPOINT : lock(mutex), resource(resource) {} + Lock(Lock &&) JL_NOTSAFEPOINT = default; + Lock &operator=(Lock &&) JL_NOTSAFEPOINT = default; + + CResourceT &operator*() JL_NOTSAFEPOINT { + return resource; + } + + const CResourceT &operator*() const JL_NOTSAFEPOINT { + return resource; + } + + CResourceT *operator->() JL_NOTSAFEPOINT { + return &**this; + } + + const CResourceT *operator->() const JL_NOTSAFEPOINT { + return &**this; + } + + operator const CResourceT &() const JL_NOTSAFEPOINT { + return resource; + } + + ~Lock() JL_NOTSAFEPOINT = default; + }; + private: + + mutable std::mutex mutex; + ResourceT resource; + public: + typedef Lock LockT; + typedef Lock ConstLockT; + + Locked(ResourceT resource = ResourceT()) JL_NOTSAFEPOINT : mutex(), resource(std::move(resource)) {} + + LockT operator*() JL_NOTSAFEPOINT { + return LockT(mutex, resource); + } + + ConstLockT operator*() const JL_NOTSAFEPOINT { + return ConstLockT(mutex, resource); + } + + ~Locked() JL_NOTSAFEPOINT = default; + }; + + template + struct jl_pthread_key_t { + static_assert(std::is_trivially_default_constructible::value, "Invalid datatype for pthread key!"); + static_assert(std::is_trivially_destructible::value, "Expected datatype to be trivially destructible!"); + static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!"); + pthread_key_t key; + + void init() JL_NOTSAFEPOINT { + if (pthread_key_create(&key, NULL)) + jl_error("fatal: pthread_key_create failed"); + } + + operator datatype() JL_NOTSAFEPOINT { + return reinterpret_cast(pthread_getspecific(key)); + } + + jl_pthread_key_t &operator=(datatype val) JL_NOTSAFEPOINT { + pthread_setspecific(key, reinterpret_cast(val)); + return *this; + } + + void destroy() JL_NOTSAFEPOINT { + pthread_key_delete(key); + } + }; + + struct sysimg_info_t { + uint64_t jl_sysimage_base; + jl_sysimg_fptrs_t sysimg_fptrs; + jl_method_instance_t **sysimg_fvars_linfo; + size_t sysimg_fvars_n; + }; + + struct libc_frames_t { +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + std::atomic libc_register_frame_{nullptr}; + std::atomic libc_deregister_frame_{nullptr}; + + void libc_register_frame(const char *Entry) JL_NOTSAFEPOINT; + + void libc_deregister_frame(const char *Entry) JL_NOTSAFEPOINT; +#endif + }; +private: + + struct ObjectInfo { + const llvm::object::ObjectFile *object = nullptr; + size_t SectionSize = 0; + ptrdiff_t slide = 0; + llvm::object::SectionRef Section{}; + llvm::DIContext *context = nullptr; + }; + + template + using rev_map = std::map>; + + typedef rev_map objectmap_t; + typedef rev_map objfilemap_t; + + objectmap_t objectmap{}; + rev_map> linfomap{}; + + // Maintain a mapping of unrealized function names -> linfo objects + // so that when we see it get emitted, we can add a link back to the linfo + // that it came from (providing name, type signature, file info, etc.) + Locked> codeinst_in_flight{}; + + Locked sysimg_info{}; + + Locked objfilemap{}; + + static std::string mangle(llvm::StringRef Name, const llvm::DataLayout &DL) JL_NOTSAFEPOINT; + +public: + + JITDebugInfoRegistry() JL_NOTSAFEPOINT; + ~JITDebugInfoRegistry() JL_NOTSAFEPOINT = default; + + // Any function that acquires this lock must be either a unmanaged thread + // or in the GC safe region and must NOT allocate anything through the GC + // while holding this lock. + // Certain functions in this file might be called from an unmanaged thread + // and cannot have any interaction with the julia runtime + // They also may be re-entrant, and operating while threads are paused, so we + // separately manage the re-entrant count behavior for safety across platforms + // Note that we cannot safely upgrade read->write + uv_rwlock_t debuginfo_asyncsafe{}; + jl_pthread_key_t debuginfo_asyncsafe_held{}; + libc_frames_t libc_frames{}; + + void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT; + jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; + void registerJITObject(const llvm::object::ObjectFile &Object, + std::function getLoadAddress, + std::function lookupWriteAddress) JL_NOTSAFEPOINT; + objectmap_t& getObjectMap() JL_NOTSAFEPOINT; + void set_sysimg_info(sysimg_info_t info) JL_NOTSAFEPOINT; + Locked::ConstLockT get_sysimg_info() const JL_NOTSAFEPOINT; + Locked::LockT get_objfile_map() JL_NOTSAFEPOINT; +}; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 0e246160a3c16..76a203eead0db 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -34,47 +34,129 @@ using namespace llvm; #include #include #include +#include #include "julia_assert.h" #ifdef _OS_DARWIN_ #include #endif -typedef object::SymbolRef SymRef; +#include "jitlayers.h" -// Any function that acquires this lock must be either a unmanaged thread -// or in the GC safe region and must NOT allocate anything through the GC -// while holding this lock. -// Certain functions in this file might be called from an unmanaged thread -// and cannot have any interaction with the julia runtime -// They also may be re-entrant, and operating while threads are paused, so we -// separately manage the re-entrant count behavior for safety across platforms -// Note that we cannot safely upgrade read->write -static uv_rwlock_t debuginfo_asyncsafe; -static pthread_key_t debuginfo_asyncsafe_held; +static JITDebugInfoRegistry &getJITDebugRegistry() JL_NOTSAFEPOINT { + return jl_ExecutionEngine->getDebugInfoRegistry(); +} + +struct debug_link_info { + StringRef filename; + uint32_t crc32; +}; + +extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT; +extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT; + +template +static void jl_profile_atomic(T f); + +#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB))) +extern "C" void __register_frame(void*); +extern "C" void __deregister_frame(void*); + +template +static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) +{ + const char *P = EHFrameAddr; + const char *End = P + EHFrameSize; + do { + const char *Entry = P; + P += 4; + assert(P <= End); + uint32_t Length = *(const uint32_t*)Entry; + // Length == 0: Terminator + if (Length == 0) + break; + assert(P + Length <= End); + uint32_t Offset = *(const uint32_t*)P; + // Offset == 0: CIE + if (Offset != 0) + f(Entry); + P += Length; + } while (P != End); +} +#endif + +std::string JITDebugInfoRegistry::mangle(StringRef Name, const DataLayout &DL) JL_NOTSAFEPOINT +{ + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + } + return MangledName; +} + +void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) JL_NOTSAFEPOINT { + (**codeinst_in_flight)[mangle(name, DL)] = codeinst; +} + +jl_method_instance_t *JITDebugInfoRegistry::lookupLinfo(size_t pointer) JL_NOTSAFEPOINT +{ + jl_lock_profile_impl(); + auto region = linfomap.lower_bound(pointer); + jl_method_instance_t *linfo = NULL; + if (region != linfomap.end() && pointer < region->first + region->second.first) + linfo = region->second.second; + jl_unlock_profile_impl(); + return linfo; +} -void jl_init_debuginfo(void) +//Protected by debuginfo_asyncsafe +JITDebugInfoRegistry::objectmap_t & +JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT { + return objectmap; +} + +void JITDebugInfoRegistry::set_sysimg_info(sysimg_info_t info) JL_NOTSAFEPOINT { + (**this->sysimg_info) = info; +} + +JITDebugInfoRegistry::Locked::ConstLockT +JITDebugInfoRegistry::get_sysimg_info() const JL_NOTSAFEPOINT { + return *this->sysimg_info; +} + +JITDebugInfoRegistry::Locked::LockT +JITDebugInfoRegistry::get_objfile_map() JL_NOTSAFEPOINT { + return *this->objfilemap; +} + +JITDebugInfoRegistry::JITDebugInfoRegistry() JL_NOTSAFEPOINT { uv_rwlock_init(&debuginfo_asyncsafe); - if (pthread_key_create(&debuginfo_asyncsafe_held, NULL)) - jl_error("fatal: pthread_key_create failed"); + debuginfo_asyncsafe_held.init(); } -extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) +struct unw_table_entry +{ + int32_t start_ip_offset; + int32_t fde_offset; +}; + +extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); + uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; if (held++ == 0) - uv_rwlock_rdlock(&debuginfo_asyncsafe); - pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); + uv_rwlock_rdlock(&getJITDebugRegistry().debuginfo_asyncsafe); + getJITDebugRegistry().debuginfo_asyncsafe_held = held; } -extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) +extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT { - uintptr_t held = (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held); + uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held; assert(held); if (--held == 0) - uv_rwlock_rdunlock(&debuginfo_asyncsafe); - pthread_setspecific(debuginfo_asyncsafe_held, (void*)held); + uv_rwlock_rdunlock(&getJITDebugRegistry().debuginfo_asyncsafe); + getJITDebugRegistry().debuginfo_asyncsafe_held = held; } // some actions aren't signal (especially profiler) safe so we acquire a lock @@ -82,8 +164,8 @@ extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) template static void jl_profile_atomic(T f) { - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); - uv_rwlock_wrlock(&debuginfo_asyncsafe); + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); #ifndef _OS_WINDOWS_ sigset_t sset; sigset_t oset; @@ -94,36 +176,14 @@ static void jl_profile_atomic(T f) #ifndef _OS_WINDOWS_ pthread_sigmask(SIG_SETMASK, &oset, NULL); #endif - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); } // --- storing and accessing source location metadata --- - -struct ObjectInfo { - const object::ObjectFile *object; - size_t SectionSize; - ptrdiff_t slide; - object::SectionRef Section; - DIContext *context; -}; - -// Maintain a mapping of unrealized function names -> linfo objects -// so that when we see it get emitted, we can add a link back to the linfo -// that it came from (providing name, type signature, file info, etc.) -static StringMap codeinst_in_flight; -static std::string mangle(StringRef Name, const DataLayout &DL) -{ - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; -} void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) { - codeinst_in_flight[mangle(name, DL)] = codeinst; + getJITDebugRegistry().add_code_in_flight(name, codeinst, DL); } @@ -181,218 +241,184 @@ static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnnam } #endif -struct revcomp { - bool operator() (const size_t& lhs, const size_t& rhs) const - { return lhs>rhs; } -}; - - -// Central registry for resolving function addresses to `jl_method_instance_t`s and -// originating `ObjectFile`s (for the DWARF debug info). -// -// A global singleton instance is notified by the JIT whenever a new object is emitted, -// and later queried by the various function info APIs. We also use the chance to handle -// some platform-specific unwind info registration (which is unrelated to the query -// functionality). -class JITObjectRegistry +void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, + std::function getLoadAddress, + std::function lookupWriteAddress) { - std::map objectmap; - std::map, revcomp> linfomap; + jl_ptls_t ptls = jl_current_task->ptls; + // This function modify codeinst->fptr in GC safe region. + // This should be fine since the GC won't scan this field. + int8_t gc_state = jl_gc_safe_enter(ptls); -public: - jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT - { - jl_lock_profile_impl(); - auto region = linfomap.lower_bound(pointer); - jl_method_instance_t *linfo = NULL; - if (region != linfomap.end() && pointer < region->first + region->second.first) - linfo = region->second.second; - jl_unlock_profile_impl(); - return linfo; - } - - void registerJITObject(const object::ObjectFile &Object, - std::function getLoadAddress, - std::function lookupWriteAddress) - { - jl_ptls_t ptls = jl_current_task->ptls; - // This function modify codeinst->fptr in GC safe region. - // This should be fine since the GC won't scan this field. - int8_t gc_state = jl_gc_safe_enter(ptls); - - object::section_iterator EndSection = Object.section_end(); + object::section_iterator EndSection = Object.section_end(); #ifdef _CPU_ARM_ - // ARM does not have/use .eh_frame - uint64_t arm_exidx_addr = 0; - size_t arm_exidx_len = 0; - uint64_t arm_text_addr = 0; - size_t arm_text_len = 0; - for (auto §ion: Object.sections()) { - bool istext = false; - if (section.isText()) { - istext = true; - } - else { - auto sName = section.getName(); - if (!sName) - continue; - if (sName.get() != ".ARM.exidx") { - continue; - } + // ARM does not have/use .eh_frame + uint64_t arm_exidx_addr = 0; + size_t arm_exidx_len = 0; + uint64_t arm_text_addr = 0; + size_t arm_text_len = 0; + for (auto §ion: Object.sections()) { + bool istext = false; + if (section.isText()) { + istext = true; + } + else { + auto sName = section.getName(); + if (!sName) + continue; + if (sName.get() != ".ARM.exidx") { + continue; } - uint64_t loadaddr = getLoadAddress(section.getName().get()); - size_t seclen = section.getSize(); - if (istext) { - arm_text_addr = loadaddr; - arm_text_len = seclen; - if (!arm_exidx_addr) { - continue; - } + } + uint64_t loadaddr = getLoadAddress(section.getName().get()); + size_t seclen = section.getSize(); + if (istext) { + arm_text_addr = loadaddr; + arm_text_len = seclen; + if (!arm_exidx_addr) { + continue; } - else { - arm_exidx_addr = loadaddr; - arm_exidx_len = seclen; - if (!arm_text_addr) { - continue; - } + } + else { + arm_exidx_addr = loadaddr; + arm_exidx_len = seclen; + if (!arm_text_addr) { + continue; } - unw_dyn_info_t *di = new unw_dyn_info_t; - di->gp = 0; - di->format = UNW_INFO_FORMAT_ARM_EXIDX; - di->start_ip = (uintptr_t)arm_text_addr; - di->end_ip = (uintptr_t)(arm_text_addr + arm_text_len); - di->u.rti.name_ptr = 0; - di->u.rti.table_data = arm_exidx_addr; - di->u.rti.table_len = arm_exidx_len; - jl_profile_atomic([&]() { - _U_dyn_register(di); - }); - break; } + unw_dyn_info_t *di = new unw_dyn_info_t; + di->gp = 0; + di->format = UNW_INFO_FORMAT_ARM_EXIDX; + di->start_ip = (uintptr_t)arm_text_addr; + di->end_ip = (uintptr_t)(arm_text_addr + arm_text_len); + di->u.rti.name_ptr = 0; + di->u.rti.table_data = arm_exidx_addr; + di->u.rti.table_len = arm_exidx_len; + jl_profile_atomic([&]() { + _U_dyn_register(di); + }); + break; + } #endif #if defined(_OS_WINDOWS_) - uint64_t SectionAddrCheck = 0; - uint64_t SectionLoadCheck = 0; (void)SectionLoadCheck; - uint64_t SectionWriteCheck = 0; (void)SectionWriteCheck; - uint8_t *UnwindData = NULL; + uint64_t SectionAddrCheck = 0; + uint64_t SectionLoadCheck = 0; (void)SectionLoadCheck; + uint64_t SectionWriteCheck = 0; (void)SectionWriteCheck; + uint8_t *UnwindData = NULL; #if defined(_CPU_X86_64_) - uint8_t *catchjmp = NULL; - for (const object::SymbolRef &sym_iter : Object.symbols()) { - StringRef sName = cantFail(sym_iter.getName()); - if (sName.equals("__UnwindData") || sName.equals("__catchjmp")) { - uint64_t Addr = cantFail(sym_iter.getAddress()); - auto Section = cantFail(sym_iter.getSection()); - assert(Section != EndSection && Section->isText()); - uint64_t SectionAddr = Section->getAddress(); - StringRef secName = cantFail(Section->getName()); - uint64_t SectionLoadAddr = getLoadAddress(secName); - assert(SectionLoadAddr); - if (SectionAddrCheck) // assert that all of the Sections are at the same location - assert(SectionAddrCheck == SectionAddr && - SectionLoadCheck == SectionLoadAddr); - SectionAddrCheck = SectionAddr; - SectionLoadCheck = SectionLoadAddr; - SectionWriteCheck = SectionLoadAddr; - if (lookupWriteAddress) - SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr); - Addr += SectionWriteCheck - SectionLoadCheck; - if (sName.equals("__UnwindData")) { - UnwindData = (uint8_t*)Addr; - } - else if (sName.equals("__catchjmp")) { - catchjmp = (uint8_t*)Addr; - } - } - } - assert(catchjmp); - assert(UnwindData); - assert(SectionAddrCheck); - assert(SectionLoadCheck); - assert(!memcmp(catchjmp, "\0\0\0\0\0\0\0\0\0\0\0\0", 12) && - !memcmp(UnwindData, "\0\0\0\0\0\0\0\0\0\0\0\0", 12)); - catchjmp[0] = 0x48; - catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&__julia_personality] - *(uint64_t*)(&catchjmp[2]) = (uint64_t)&__julia_personality; - catchjmp[10] = 0xff; - catchjmp[11] = 0xe0; // jmp RAX - UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER - UnwindData[1] = 4; // size of prolog (bytes) - UnwindData[2] = 2; // count of unwind codes (slots) - UnwindData[3] = 0x05; // frame register (rbp) = rsp - UnwindData[4] = 4; // second instruction - UnwindData[5] = 0x03; // mov RBP, RSP - UnwindData[6] = 1; // first instruction - UnwindData[7] = 0x50; // push RBP - *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionWriteCheck); // relative location of catchjmp - UnwindData -= SectionWriteCheck - SectionLoadCheck; -#endif // defined(_OS_X86_64_) -#endif // defined(_OS_WINDOWS_) - - auto symbols = object::computeSymbolSizes(Object); - bool first = true; - for (const auto &sym_size : symbols) { - const object::SymbolRef &sym_iter = sym_size.first; - object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType()); - if (SymbolType != object::SymbolRef::ST_Function) continue; + uint8_t *catchjmp = NULL; + for (const object::SymbolRef &sym_iter : Object.symbols()) { + StringRef sName = cantFail(sym_iter.getName()); + if (sName.equals("__UnwindData") || sName.equals("__catchjmp")) { uint64_t Addr = cantFail(sym_iter.getAddress()); auto Section = cantFail(sym_iter.getSection()); - if (Section == EndSection) continue; - if (!Section->isText()) continue; + assert(Section != EndSection && Section->isText()); uint64_t SectionAddr = Section->getAddress(); StringRef secName = cantFail(Section->getName()); uint64_t SectionLoadAddr = getLoadAddress(secName); - Addr -= SectionAddr - SectionLoadAddr; - StringRef sName = cantFail(sym_iter.getName()); - uint64_t SectionSize = Section->getSize(); - size_t Size = sym_size.second; -#if defined(_OS_WINDOWS_) - if (SectionAddrCheck) + assert(SectionLoadAddr); + if (SectionAddrCheck) // assert that all of the Sections are at the same location assert(SectionAddrCheck == SectionAddr && - SectionLoadCheck == SectionLoadAddr); + SectionLoadCheck == SectionLoadAddr); SectionAddrCheck = SectionAddr; SectionLoadCheck = SectionLoadAddr; - create_PRUNTIME_FUNCTION( - (uint8_t*)(uintptr_t)Addr, (size_t)Size, sName, - (uint8_t*)(uintptr_t)SectionLoadAddr, (size_t)SectionSize, UnwindData); + SectionWriteCheck = SectionLoadAddr; + if (lookupWriteAddress) + SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr); + Addr += SectionWriteCheck - SectionLoadCheck; + if (sName.equals("__UnwindData")) { + UnwindData = (uint8_t*)Addr; + } + else if (sName.equals("__catchjmp")) { + catchjmp = (uint8_t*)Addr; + } + } + } + assert(catchjmp); + assert(UnwindData); + assert(SectionAddrCheck); + assert(SectionLoadCheck); + assert(!memcmp(catchjmp, "\0\0\0\0\0\0\0\0\0\0\0\0", 12) && + !memcmp(UnwindData, "\0\0\0\0\0\0\0\0\0\0\0\0", 12)); + catchjmp[0] = 0x48; + catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&__julia_personality] + *(uint64_t*)(&catchjmp[2]) = (uint64_t)&__julia_personality; + catchjmp[10] = 0xff; + catchjmp[11] = 0xe0; // jmp RAX + UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER + UnwindData[1] = 4; // size of prolog (bytes) + UnwindData[2] = 2; // count of unwind codes (slots) + UnwindData[3] = 0x05; // frame register (rbp) = rsp + UnwindData[4] = 4; // second instruction + UnwindData[5] = 0x03; // mov RBP, RSP + UnwindData[6] = 1; // first instruction + UnwindData[7] = 0x50; // push RBP + *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionWriteCheck); // relative location of catchjmp + UnwindData -= SectionWriteCheck - SectionLoadCheck; +#endif // defined(_OS_X86_64_) +#endif // defined(_OS_WINDOWS_) + + auto symbols = object::computeSymbolSizes(Object); + bool first = true; + for (const auto &sym_size : symbols) { + const object::SymbolRef &sym_iter = sym_size.first; + object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType()); + if (SymbolType != object::SymbolRef::ST_Function) continue; + uint64_t Addr = cantFail(sym_iter.getAddress()); + auto Section = cantFail(sym_iter.getSection()); + if (Section == EndSection) continue; + if (!Section->isText()) continue; + uint64_t SectionAddr = Section->getAddress(); + StringRef secName = cantFail(Section->getName()); + uint64_t SectionLoadAddr = getLoadAddress(secName); + Addr -= SectionAddr - SectionLoadAddr; + StringRef sName = cantFail(sym_iter.getName()); + uint64_t SectionSize = Section->getSize(); + size_t Size = sym_size.second; +#if defined(_OS_WINDOWS_) + if (SectionAddrCheck) + assert(SectionAddrCheck == SectionAddr && + SectionLoadCheck == SectionLoadAddr); + SectionAddrCheck = SectionAddr; + SectionLoadCheck = SectionLoadAddr; + create_PRUNTIME_FUNCTION( + (uint8_t*)(uintptr_t)Addr, (size_t)Size, sName, + (uint8_t*)(uintptr_t)SectionLoadAddr, (size_t)SectionSize, UnwindData); #endif + jl_code_instance_t *codeinst = NULL; + { + auto lock = *this->codeinst_in_flight; + auto &codeinst_in_flight = *lock; StringMap::iterator codeinst_it = codeinst_in_flight.find(sName); - jl_code_instance_t *codeinst = NULL; if (codeinst_it != codeinst_in_flight.end()) { codeinst = codeinst_it->second; codeinst_in_flight.erase(codeinst_it); } - jl_profile_atomic([&]() { - if (codeinst) - linfomap[Addr] = std::make_pair(Size, codeinst->def); - if (first) { - ObjectInfo tmp = {&Object, - (size_t)SectionSize, - (ptrdiff_t)(SectionAddr - SectionLoadAddr), - *Section, - nullptr, - }; - objectmap[SectionLoadAddr] = tmp; - first = false; - } - }); } - jl_gc_safe_leave(ptls, gc_state); - } - - std::map& getObjectMap() JL_NOTSAFEPOINT - { - return objectmap; + jl_profile_atomic([&]() { + if (codeinst) + linfomap[Addr] = std::make_pair(Size, codeinst->def); + if (first) { + objectmap[SectionLoadAddr] = {&Object, + (size_t)SectionSize, + (ptrdiff_t)(SectionAddr - SectionLoadAddr), + *Section, + nullptr, + }; + first = false; + } + }); } -}; + jl_gc_safe_leave(ptls, gc_state); +} -static JITObjectRegistry jl_jit_object_registry; void jl_register_jit_object(const object::ObjectFile &Object, std::function getLoadAddress, std::function lookupWriteAddress) { - jl_jit_object_registry.registerJITObject(Object, getLoadAddress, lookupWriteAddress); + getJITDebugRegistry().registerJITObject(Object, getLoadAddress, lookupWriteAddress); } // TODO: convert the safe names from aotcomile.cpp:makeSafeName back into symbols @@ -462,10 +488,10 @@ static int lookup_pointer( // DWARFContext/DWARFUnit update some internal tables during these queries, so // a lock is needed. - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); - uv_rwlock_wrlock(&debuginfo_asyncsafe); + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); int fromC = (*frames)[0].fromC; int n_frames = inlineInfo.getNumberOfFrames(); @@ -488,9 +514,9 @@ static int lookup_pointer( info = inlineInfo.getFrame(i); } else { - uv_rwlock_wrlock(&debuginfo_asyncsafe); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); info = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec); - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); } jl_frame_t *frame = &(*frames)[i]; @@ -534,13 +560,37 @@ static int lookup_pointer( #ifndef _OS_WINDOWS_ #include #endif -typedef struct { - const llvm::object::ObjectFile *obj; - DIContext *ctx; - int64_t slide; -} objfileentry_t; -typedef std::map obfiletype; -static obfiletype objfilemap; + + + +#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) + +void JITDebugInfoRegistry::libc_frames_t::libc_register_frame(const char *Entry) { + auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_); + if (!libc_register_frame_) { + libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); + jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_); + } + assert(libc_register_frame_); + jl_profile_atomic([&]() { + libc_register_frame_(const_cast(Entry)); + __register_frame(const_cast(Entry)); + }); +} + +void JITDebugInfoRegistry::libc_frames_t::libc_deregister_frame(const char *Entry) { + auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_); + if (!libc_deregister_frame_) { + libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); + jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_); + } + assert(libc_deregister_frame_); + jl_profile_atomic([&]() { + libc_deregister_frame_(const_cast(Entry)); + __deregister_frame(const_cast(Entry)); + }); +} +#endif static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) JL_NOTSAFEPOINT { @@ -553,11 +603,6 @@ static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) JL_ } return false; } - -struct debug_link_info { - StringRef filename; - uint32_t crc32; -}; static debug_link_info getDebuglink(const object::ObjectFile &Obj) JL_NOTSAFEPOINT { debug_link_info info = {}; @@ -668,19 +713,11 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info) std::move(error_splitobj.get()), std::move(SplitFile.get())); } - -static uint64_t jl_sysimage_base; -static jl_sysimg_fptrs_t sysimg_fptrs; -static jl_method_instance_t **sysimg_fvars_linfo; -static size_t sysimg_fvars_n; extern "C" JL_DLLEXPORT void jl_register_fptrs_impl(uint64_t sysimage_base, const jl_sysimg_fptrs_t *fptrs, jl_method_instance_t **linfos, size_t n) { - jl_sysimage_base = (uintptr_t)sysimage_base; - sysimg_fptrs = *fptrs; - sysimg_fvars_linfo = linfos; - sysimg_fvars_n = n; + getJITDebugRegistry().set_sysimg_info({(uintptr_t) sysimage_base, *fptrs, linfos, n}); } template @@ -695,7 +732,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t void **saddr, char **name, bool untrusted_dladdr) JL_NOTSAFEPOINT { // Assume we only need base address for sysimg for now - if (!insysimage || !sysimg_fptrs.base) + if (!insysimage || !getJITDebugRegistry().get_sysimg_info()->sysimg_fptrs.base) saddr = nullptr; bool needs_saddr = saddr && (!*saddr || untrusted_dladdr); bool needs_name = name && (!*name || untrusted_dladdr); @@ -721,7 +758,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t } if (Section.getObject() && (needs_saddr || needs_name)) { size_t distance = (size_t)-1; - SymRef sym_found; + object::SymbolRef sym_found; for (auto sym : Section.getObject()->symbols()) { if (!Section.containsSymbol(sym)) continue; @@ -796,7 +833,7 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t #endif } -static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTSAFEPOINT +static objfileentry_t find_object_file(uint64_t fbase, StringRef fname) JL_NOTSAFEPOINT { int isdarwin = 0, islinux = 0, iswindows = 0; #if defined(_OS_DARWIN_) @@ -809,12 +846,11 @@ static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTS (void)iswindows; // GOAL: Read debuginfo from file - // TODO: need read/write lock here for objfilemap synchronization - obfiletype::iterator it = objfilemap.find(fbase); - if (it != objfilemap.end()) + objfileentry_t entry{nullptr, nullptr, 0}; + auto success = getJITDebugRegistry().get_objfile_map()->emplace(fbase, entry); + if (!success.second) // Return cached value - return it->second; - auto &entry = objfilemap[fbase]; // default initialized + return success.first->second; // GOAL: Assign errorobj StringRef objpath; @@ -984,8 +1020,9 @@ static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTS auto binary = errorobj->takeBinary(); binary.first.release(); binary.second.release(); - // update cache entry = {debugobj, context, slide}; + // update cache + (*getJITDebugRegistry().get_objfile_map())[fbase] = entry; } else { // TODO: report the error instead of silently consuming it? @@ -1043,7 +1080,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * if (fname.empty()) // empirically, LoadedImageName might be missing fname = ModuleInfo.ImageName; DWORD64 fbase = ModuleInfo.BaseOfImage; - bool insysimage = (fbase == jl_sysimage_base); + bool insysimage = (fbase == getJITDebugRegistry().get_sysimg_info()->jl_sysimage_base); if (isSysImg) *isSysImg = insysimage; if (onlySysImg && !insysimage) @@ -1083,7 +1120,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * fbase = (uintptr_t)dlinfo.dli_fbase; #endif StringRef fname; - bool insysimage = (fbase == jl_sysimage_base); + bool insysimage = (fbase == getJITDebugRegistry().get_sysimg_info()->jl_sysimage_base); if (saddr && !(insysimage && untrusted_dladdr)) *saddr = dlinfo.dli_saddr; if (isSysImg) @@ -1098,7 +1135,7 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * jl_copy_str(filename, dlinfo.dli_fname); fname = dlinfo.dli_fname; #endif // ifdef _OS_WINDOWS_ - auto &entry = find_object_file(fbase, fname); + auto entry = find_object_file(fbase, fname); *slide = entry.slide; *context = entry.ctx; if (entry.obj) @@ -1139,20 +1176,23 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip return 1; } frame0->fromC = !isSysImg; - if (isSysImg && sysimg_fptrs.base && saddr) { - intptr_t diff = (uintptr_t)saddr - (uintptr_t)sysimg_fptrs.base; - for (size_t i = 0; i < sysimg_fptrs.nclones; i++) { - if (diff == sysimg_fptrs.clone_offsets[i]) { - uint32_t idx = sysimg_fptrs.clone_idxs[i] & jl_sysimg_val_mask; - if (idx < sysimg_fvars_n) // items after this were cloned but not referenced directly by a method (such as our ccall PLT thunks) - frame0->linfo = sysimg_fvars_linfo[idx]; - break; + { + auto sysimg_locked = getJITDebugRegistry().get_sysimg_info(); + if (isSysImg && sysimg_locked->sysimg_fptrs.base && saddr) { + intptr_t diff = (uintptr_t)saddr - (uintptr_t)sysimg_locked->sysimg_fptrs.base; + for (size_t i = 0; i < sysimg_locked->sysimg_fptrs.nclones; i++) { + if (diff == sysimg_locked->sysimg_fptrs.clone_offsets[i]) { + uint32_t idx = sysimg_locked->sysimg_fptrs.clone_idxs[i] & jl_sysimg_val_mask; + if (idx < sysimg_locked->sysimg_fvars_n) // items after this were cloned but not referenced directly by a method (such as our ccall PLT thunks) + frame0->linfo = sysimg_locked->sysimg_fvars_linfo[idx]; + break; + } } - } - for (size_t i = 0; i < sysimg_fvars_n; i++) { - if (diff == sysimg_fptrs.offsets[i]) { - frame0->linfo = sysimg_fvars_linfo[i]; - break; + for (size_t i = 0; i < sysimg_locked->sysimg_fvars_n; i++) { + if (diff == sysimg_locked->sysimg_fptrs.offsets[i]) { + frame0->linfo = sysimg_locked->sysimg_fvars_linfo[i]; + break; + } } } } @@ -1163,13 +1203,13 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT { int found = 0; - assert(0 == (uintptr_t)pthread_getspecific(debuginfo_asyncsafe_held)); - uv_rwlock_wrlock(&debuginfo_asyncsafe); - std::map &objmap = jl_jit_object_registry.getObjectMap(); - std::map::iterator fit = objmap.lower_bound(fptr); - + assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held); + uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe); if (symsize) *symsize = 0; + + auto &objmap = getJITDebugRegistry().getObjectMap(); + auto fit = objmap.lower_bound(fptr); if (fit != objmap.end() && fptr < fit->first + fit->second.SectionSize) { *slide = fit->second.slide; *Section = fit->second.Section; @@ -1180,7 +1220,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide, } found = 1; } - uv_rwlock_wrunlock(&debuginfo_asyncsafe); + uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe); return found; } @@ -1199,7 +1239,7 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz int64_t slide; uint64_t symsize; if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) { - frames[0].linfo = jl_jit_object_registry.lookupLinfo(pointer); + frames[0].linfo = getJITDebugRegistry().lookupLinfo(pointer); int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline); return nf; } @@ -1208,36 +1248,9 @@ extern "C" JL_DLLEXPORT int jl_getFunctionInfo_impl(jl_frame_t **frames_out, siz extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT { - return jl_jit_object_registry.lookupLinfo((size_t)p); + return getJITDebugRegistry().lookupLinfo((size_t)p); } -#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB))) -extern "C" void __register_frame(void*); -extern "C" void __deregister_frame(void*); - -template -static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) -{ - const char *P = EHFrameAddr; - const char *End = P + EHFrameSize; - do { - const char *Entry = P; - P += 4; - assert(P <= End); - uint32_t Length = *(const uint32_t*)Entry; - // Length == 0: Terminator - if (Length == 0) - break; - assert(P + Length <= End); - uint32_t Offset = *(const uint32_t*)P; - // Offset == 0: CIE - if (Offset != 0) - f(Entry); - P += Length; - } while (P != End); -} -#endif - #if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) /* @@ -1248,37 +1261,20 @@ static void processFDEs(const char *EHFrameAddr, size_t EHFrameSize, callback f) * ourselves to ensure the right one gets picked. */ -static void (*libc_register_frame)(void*) = NULL; -static void (*libc_deregister_frame)(void*) = NULL; - // This implementation handles frame registration for local targets. void register_eh_frames(uint8_t *Addr, size_t Size) { // On OS X OS X __register_frame takes a single FDE as an argument. // See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html processFDEs((char*)Addr, Size, [](const char *Entry) { - if (!libc_register_frame) { - libc_register_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame"); - } - assert(libc_register_frame); - jl_profile_atomic([&]() { - libc_register_frame(const_cast(Entry)); - __register_frame(const_cast(Entry)); - }); + getJITDebugRegistry().libc_frames.libc_register_frame(Entry); }); } void deregister_eh_frames(uint8_t *Addr, size_t Size) { processFDEs((char*)Addr, Size, [](const char *Entry) { - if (!libc_deregister_frame) { - libc_deregister_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame"); - } - assert(libc_deregister_frame); - jl_profile_atomic([&]() { - libc_deregister_frame(const_cast(Entry)); - __deregister_frame(const_cast(Entry)); - }); + getJITDebugRegistry().libc_frames.libc_deregister_frame(Entry); }); } @@ -1287,12 +1283,6 @@ void deregister_eh_frames(uint8_t *Addr, size_t Size) !defined(_CPU_ARM_) // ARM does not have/use .eh_frame, so we handle this elsewhere #include -struct unw_table_entry -{ - int32_t start_ip_offset; - int32_t fde_offset; -}; - // Skip over an arbitrary long LEB128 encoding. // Return the pointer to the first unprocessed byte. static const uint8_t *consume_leb128(const uint8_t *Addr, const uint8_t *End) @@ -1630,8 +1620,8 @@ uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr) { // Might be called from unmanaged thread jl_lock_profile_impl(); - std::map &objmap = jl_jit_object_registry.getObjectMap(); - std::map::iterator it = objmap.lower_bound(dwAddr); + auto &objmap = getJITDebugRegistry().getObjectMap(); + auto it = objmap.lower_bound(dwAddr); uint64_t ipstart = 0; // ip of the start of the section (if found) if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) { ipstart = (uint64_t)(uintptr_t)(*it).first; diff --git a/src/jitlayers.h b/src/jitlayers.h index ba3f81fa66997..af47102173a7b 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -11,6 +11,7 @@ #include #include "julia_assert.h" +#include "debug-registry.h" // As of LLVM 13, there are two runtime JIT linker implementations, the older // RuntimeDyld (used via orc::RTDyldObjectLinkingLayer) and the newer JITLink @@ -214,6 +215,10 @@ class JuliaOJIT { const DataLayout& getDataLayout() const; const Triple& getTargetTriple() const; size_t getTotalBytes() const; + + JITDebugInfoRegistry &getDebugInfoRegistry() JL_NOTSAFEPOINT { + return DebugRegistry; + } private: std::string getMangledName(StringRef Name); std::string getMangledName(const GlobalValue *GV); @@ -236,6 +241,8 @@ class JuliaOJIT { orc::JITDylib &GlobalJD; orc::JITDylib &JD; + JITDebugInfoRegistry DebugRegistry; + #ifndef JL_USE_JITLINK std::shared_ptr MemMgr; #endif diff --git a/src/processor.h b/src/processor.h index 1d385cfc80b98..f3b571cf9b937 100644 --- a/src/processor.h +++ b/src/processor.h @@ -1,5 +1,8 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license +#ifndef JL_PROCESSOR_H +#define JL_PROCESSOR_H + #include "support/dtypes.h" #include "julia.h" @@ -215,3 +218,5 @@ extern "C" JL_DLLEXPORT std::vector jl_get_llvm_clone_targets( std::string jl_get_cpu_name_llvm(void); std::string jl_get_cpu_features_llvm(void); #endif + +#endif