Example #1
0
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;
            }
        }
    }
}
Example #2
0
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);
        }
    }
}
Example #3
0
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);
    }
  }
}
Example #4
0
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);
  }
}
Example #5
0
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);
    }
  }
}