void MCJITHelper::SymListener::NotifyObjectEmitted(const object::ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { using namespace llvm::object; OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); bool verbose = *verboseFlagPtr; for (symbol_iterator it = DebugObj.symbol_begin(), end = DebugObj.symbol_end(); it != end; ++it) { object::SymbolRef::Type SymType; if (it->getType(SymType)) continue; if (SymType == SymbolRef::ST_Function) { StringRef name; uint64_t addr; if (it->getName(name)) continue; if (it->getAddress(addr)) continue; Table->push_back(AddrSymPair(addr, name.str())); if (verbose) { std::cerr << "Loading native code for function " << name.str() << " at address " << (void*)addr << std::endl; } } } }
void StackMapJITEventListener::NotifyObjectEmitted(const object::ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &LoadedObj) { std::error_code errorCode; for (const object::SectionRef& section: Obj.sections()) { StringRef name; errorCode = section.getName(name); assert(!errorCode); if (name == ".llvm_stackmaps") { uint64_t stackMapAddress = LoadedObj.getSectionLoadAddress(name); assert(stackMapAddress > 0); uint64_t expectedSize = section.getSize(); // check is made by the callee StackMap *map = parseStackMapFromAddress(stackMapAddress, expectedSize); Maps->push_back(map); } } }
void ObjectLoadListener::recordRelocations( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { section_iterator Section = SI->getRelocatedSection(); if (Section == SE) { continue; } StringRef SectionName; std::error_code ErrorCode = Section->getName(SectionName); if (ErrorCode) { assert(false && ErrorCode.message().c_str()); } if (SectionName.startswith(".debug") || SectionName.startswith(".rela.debug") || !SectionName.compare(".pdata") || SectionName.startswith(".eh_frame") || SectionName.startswith(".rela.eh_frame")) { // Skip sections whose contents are not directly reported to the EE continue; } relocation_iterator I = SI->relocation_begin(); relocation_iterator E = SI->relocation_end(); for (; I != E; ++I) { symbol_iterator Symbol = I->getSymbol(); assert(Symbol != Obj.symbol_end()); ErrorOr<section_iterator> SymbolSectionOrErr = Symbol->getSection(); assert(!SymbolSectionOrErr.getError()); object::section_iterator SymbolSection = *SymbolSectionOrErr; const bool IsExtern = SymbolSection == Obj.section_end(); uint64_t RelType = I->getType(); uint64_t Offset = I->getOffset(); uint8_t *RelocationTarget; if (IsExtern) { // This is an external symbol. Verify that it's one we created for // a global variable and report the relocation via Jit interface. ErrorOr<StringRef> NameOrError = Symbol->getName(); assert(NameOrError); StringRef TargetName = NameOrError.get(); auto MapIter = Context->NameToHandleMap.find(TargetName); if (MapIter == Context->NameToHandleMap.end()) { // The xdata gets a pointer to our personality routine, which we // dummied up. We can safely skip it since the EE isn't actually // going to use the value (it inserts the correct one before handing // the xdata off to the OS). assert(!TargetName.compare("ProcessCLRException")); assert(SectionName.startswith(".xdata")); continue; } else { assert(MapIter->second == Context->NameToHandleMap[TargetName]); RelocationTarget = (uint8_t *)MapIter->second; } } else { RelocationTarget = (uint8_t *)(L.getSectionLoadAddress(*SymbolSection) + Symbol->getValue()); } uint64_t Addend = 0; uint64_t EERelType = getRelocationType(RelType); uint64_t SectionAddress = L.getSectionLoadAddress(*Section); assert(SectionAddress != 0); uint8_t *FixupAddress = (uint8_t *)(SectionAddress + Offset); if (Obj.isELF()) { // Addend is part of the relocation ELFRelocationRef ElfReloc(*I); ErrorOr<uint64_t> ElfAddend = ElfReloc.getAddend(); assert(!ElfAddend.getError()); Addend = ElfAddend.get(); } else { // Addend is read from the location to be fixed up Addend = getRelocationAddend(RelType, FixupAddress); } Context->JitInfo->recordRelocation(FixupAddress, RelocationTarget + Addend, EERelType); } } }
void ObjectLoadListener::getDebugInfoForObject( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); // TODO: This extracts DWARF information from the object file, but we will // want to also be able to eventually extract WinCodeView information as well DWARFContextInMemory DwarfContext(DebugObj); // Use symbol info to find the function size. // If there are funclets, they will each have separate symbols, so we need // to sum the sizes, since the EE wants a single report for the entire // function+funclets. uint64_t Addr = UINT64_MAX; uint64_t Size = 0; std::vector<std::pair<SymbolRef, uint64_t>> SymbolSizes = object::computeSymbolSizes(DebugObj); for (const auto &Pair : SymbolSizes) { object::SymbolRef Symbol = Pair.first; SymbolRef::Type SymType = Symbol.getType(); if (SymType != SymbolRef::ST_Function) continue; // Function info ErrorOr<uint64_t> AddrOrError = Symbol.getAddress(); if (!AddrOrError) { continue; // Error. } uint64_t SingleAddr = AddrOrError.get(); uint64_t SingleSize = Pair.second; if (SingleAddr < Addr) { // The main function is always laid out first Addr = SingleAddr; } Size += SingleSize; } uint32_t LastDebugOffset = (uint32_t)-1; uint32_t NumDebugRanges = 0; ICorDebugInfo::OffsetMapping *OM; DILineInfoTable Lines = DwarfContext.getLineInfoForAddressRange(Addr, Size); DILineInfoTable::iterator Begin = Lines.begin(); DILineInfoTable::iterator End = Lines.end(); // Count offset entries. Will skip an entry if the current IL offset // matches the previous offset. for (DILineInfoTable::iterator It = Begin; It != End; ++It) { uint32_t LineNumber = (It->second).Line; if (LineNumber != LastDebugOffset) { NumDebugRanges++; LastDebugOffset = LineNumber; } } // Reset offset LastDebugOffset = (uint32_t)-1; if (NumDebugRanges > 0) { // Allocate OffsetMapping array unsigned SizeOfArray = (NumDebugRanges) * sizeof(ICorDebugInfo::OffsetMapping); OM = (ICorDebugInfo::OffsetMapping *)Context->JitInfo->allocateArray( SizeOfArray); unsigned CurrentDebugEntry = 0; // Iterate through the debug entries and save IL offset, native // offset, and source reason for (DILineInfoTable::iterator It = Begin; It != End; ++It) { int Offset = It->first; uint32_t LineNumber = (It->second).Line; // We store info about if the instruction is being recorded because // it is a call in the column field bool IsCall = (It->second).Column == 1; if (LineNumber != LastDebugOffset) { LastDebugOffset = LineNumber; OM[CurrentDebugEntry].nativeOffset = Offset; OM[CurrentDebugEntry].ilOffset = LineNumber; OM[CurrentDebugEntry].source = IsCall ? ICorDebugInfo::CALL_INSTRUCTION : ICorDebugInfo::STACK_EMPTY; CurrentDebugEntry++; } } // Send array of OffsetMappings to CLR EE CORINFO_METHOD_INFO *MethodInfo = Context->MethodInfo; CORINFO_METHOD_HANDLE MethodHandle = MethodInfo->ftn; Context->JitInfo->setBoundaries(MethodHandle, NumDebugRanges, OM); getDebugInfoForLocals(DwarfContext, Addr, Size); } }
void ObjectLoadListener::recordRelocations( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { section_iterator Section = SI->getRelocatedSection(); if (Section == SE) { continue; } StringRef SectionName; std::error_code ErrorCode = Section->getName(SectionName); if (ErrorCode) { assert(false && ErrorCode.message().c_str()); } if (SectionName.startswith(".debug") || SectionName.startswith(".rela.debug") || !SectionName.compare(".pdata") || SectionName.startswith(".eh_frame") || SectionName.startswith(".rela.eh_frame")) { // Skip sections whose contents are not directly reported to the EE continue; } relocation_iterator I = SI->relocation_begin(); relocation_iterator E = SI->relocation_end(); for (; I != E; ++I) { symbol_iterator Symbol = I->getSymbol(); assert(Symbol != Obj.symbol_end()); ErrorOr<section_iterator> SymbolSectionOrErr = Symbol->getSection(); assert(!SymbolSectionOrErr.getError()); object::section_iterator SymbolSection = *SymbolSectionOrErr; const bool IsExtern = SymbolSection == Obj.section_end(); uint64_t RelType = I->getType(); uint64_t Offset = I->getOffset(); uint8_t *RelocationTarget = nullptr; if (IsExtern) { // This is an external symbol. Verify that it's one we created for // a global variable and report the relocation via Jit interface. ErrorOr<StringRef> NameOrError = Symbol->getName(); assert(NameOrError); StringRef TargetName = NameOrError.get(); assert(Context->NameToHandleMap.count(TargetName) == 1); RelocationTarget = (uint8_t *)Context->NameToHandleMap[TargetName]; } else { RelocationTarget = (uint8_t *)(L.getSectionLoadAddress(*SymbolSection) + Symbol->getValue()); } uint64_t Addend = 0; uint64_t EERelType = getRelocationType(RelType); uint64_t SectionAddress = L.getSectionLoadAddress(*Section); assert(SectionAddress != 0); uint8_t *FixupAddress = (uint8_t *)(SectionAddress + Offset); if (Obj.isELF()) { // Addend is part of the relocation ELFRelocationRef ElfReloc(*I); ErrorOr<uint64_t> ElfAddend = ElfReloc.getAddend(); assert(!ElfAddend.getError()); Addend = ElfAddend.get(); } else { // Addend is read from the location to be fixed up Addend = getRelocationAddend(RelType, FixupAddress); } Context->JitInfo->recordRelocation(FixupAddress, RelocationTarget + Addend, EERelType); } } }