Exemple #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;
            }
        }
    }
}
Exemple #2
0
void JuliaOJIT::DebugObjectRegistrar::operator()(ObjectLinkingLayerBase::ObjSetHandleT H, const ObjSetT &Objects,
                const LoadResult &LOS)
{
#ifndef LLVM38
    notifyObjectLoaded(JIT.MemMgr, H);
#endif
    auto oit = Objects.begin();
    auto lit = LOS.begin();
    for (; oit != Objects.end(); ++oit, ++lit) {
#ifdef LLVM39
        const auto &Object = (*oit)->getBinary();
#else
        auto &Object = *oit;
#endif
        auto &LO = *lit;

        OwningBinary<object::ObjectFile> SavedObject = LO->getObjectForDebug(*Object);

        // If the debug object is unavailable, save (a copy of) the original object
        // for our backtraces
        if (!SavedObject.getBinary()) {
            // This is unfortunate, but there doesn't seem to be a way to take
            // ownership of the original buffer
            auto NewBuffer = MemoryBuffer::getMemBufferCopy(Object->getData(), Object->getFileName());
            auto NewObj = ObjectFile::createObjectFile(NewBuffer->getMemBufferRef());
            assert(NewObj);
            SavedObject = OwningBinary<object::ObjectFile>(std::move(*NewObj),std::move(NewBuffer));
        }
        else {
            NotifyGDB(SavedObject);
        }

        SavedObjects.push_back(std::move(SavedObject));

        ORCNotifyObjectEmitted(JuliaListener.get(),
                *Object,
                *SavedObjects.back().getBinary(),
                *LO, JIT.MemMgr);

        // record all of the exported symbols defined in this object
        // in the primary hash table for the enclosing JIT
        for (auto &Symbol : Object->symbols()) {
            auto Flags = Symbol.getFlags();
            if (Flags & object::BasicSymbolRef::SF_Undefined)
                continue;
            if (!(Flags & object::BasicSymbolRef::SF_Exported))
                continue;
            auto NameOrError = Symbol.getName();
            assert(NameOrError);
            auto Name = NameOrError.get();
            orc::JITSymbol Sym = JIT.CompileLayer.findSymbolIn(H, Name, true);
            assert(Sym);
            // note: calling getAddress here eagerly finalizes H
            // as an alternative, we could store the JITSymbol instead
            // (which would present a lazy-initializer functor interface instead)
            JIT.LocalSymbolTable[Name] = (void*)(uintptr_t)Sym.getAddress();
        }
    }
}
Exemple #3
0
void JuliaOJIT::DebugObjectRegistrar::NotifyGDB(OwningBinary<object::ObjectFile> &DebugObj)
{
    const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart();
    size_t      Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize();

    assert(Buffer && "Attempt to register a null object with a debugger.");
    jit_code_entry *JITCodeEntry = new jit_code_entry();

    if (!JITCodeEntry) {
        jl_printf(JL_STDERR, "WARNING: Allocation failed when registering a JIT entry!\n");
    }
    else {
        JITCodeEntry->symfile_addr = Buffer;
        JITCodeEntry->symfile_size = Size;

        NotifyDebugger(JITCodeEntry);
    }
}
Exemple #4
0
LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef OF,
                                    LLVMSectionIteratorRef SI) {
  OwningBinary<ObjectFile> *OB = unwrap(OF);
  return (*unwrap(SI) == OB->getBinary()->section_end()) ? 1 : 0;
}
Exemple #5
0
// ObjectFile Section iterators
LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef OF) {
  OwningBinary<ObjectFile> *OB = unwrap(OF);
  section_iterator SI = OB->getBinary()->section_begin();
  return wrap(new section_iterator(SI));
}
Exemple #6
0
// ObjectFile Symbol iterators
LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef OF) {
  OwningBinary<ObjectFile> *OB = unwrap(OF);
  symbol_iterator SI = OB->getBinary()->symbol_begin();
  return wrap(new symbol_iterator(SI));
}
Exemple #7
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);
  }
}
static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {
  assert(LoadObjects || !UseDebugObj);

  // Load any dylibs requested on the command line.
  loadDylibs();

  // If we don't have any input files, read from stdin.
  if (!InputFileList.size())
    InputFileList.push_back("-");
  for (auto &File : InputFileList) {
    // Instantiate a dynamic linker.
    TrivialMemoryManager MemMgr;
    RuntimeDyld Dyld(MemMgr, MemMgr);

    // Load the input memory buffer.

    ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
        MemoryBuffer::getFileOrSTDIN(File);
    if (std::error_code EC = InputBuffer.getError())
      ErrorAndExit("unable to read input: '" + EC.message() + "'");

    Expected<std::unique_ptr<ObjectFile>> MaybeObj(
      ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));

    if (!MaybeObj) {
      std::string Buf;
      raw_string_ostream OS(Buf);
      logAllUnhandledErrors(MaybeObj.takeError(), OS, "");
      OS.flush();
      ErrorAndExit("unable to create object file: '" + Buf + "'");
    }

    ObjectFile &Obj = **MaybeObj;

    OwningBinary<ObjectFile> DebugObj;
    std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;
    ObjectFile *SymbolObj = &Obj;
    if (LoadObjects) {
      // Load the object file
      LoadedObjInfo =
        Dyld.loadObject(Obj);

      if (Dyld.hasError())
        ErrorAndExit(Dyld.getErrorString());

      // Resolve all the relocations we can.
      Dyld.resolveRelocations();

      if (UseDebugObj) {
        DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
        SymbolObj = DebugObj.getBinary();
        LoadedObjInfo.reset();
      }
    }

    std::unique_ptr<DIContext> Context(
      new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get()));

    std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =
        object::computeSymbolSizes(*SymbolObj);

    // Use symbol info to iterate functions in the object.
    for (const auto &P : SymAddr) {
      object::SymbolRef Sym = P.first;
      Expected<SymbolRef::Type> TypeOrErr = Sym.getType();
      if (!TypeOrErr) {
        // TODO: Actually report errors helpfully.
        consumeError(TypeOrErr.takeError());
        continue;
      }
      SymbolRef::Type Type = *TypeOrErr;
      if (Type == object::SymbolRef::ST_Function) {
        Expected<StringRef> Name = Sym.getName();
        if (!Name) {
          // TODO: Actually report errors helpfully.
          consumeError(Name.takeError());
          continue;
        }
        Expected<uint64_t> AddrOrErr = Sym.getAddress();
        if (!AddrOrErr) {
          // TODO: Actually report errors helpfully.
          consumeError(AddrOrErr.takeError());
          continue;
        }
        uint64_t Addr = *AddrOrErr;

        uint64_t Size = P.second;
        // If we're not using the debug object, compute the address of the
        // symbol in memory (rather than that in the unrelocated object file)
        // and use that to query the DWARFContext.
        if (!UseDebugObj && LoadObjects) {
          auto SecOrErr = Sym.getSection();
          if (!SecOrErr) {
            // TODO: Actually report errors helpfully.
            consumeError(SecOrErr.takeError());
            continue;
          }
          object::section_iterator Sec = *SecOrErr;
          StringRef SecName;
          Sec->getName(SecName);
          uint64_t SectionLoadAddress =
            LoadedObjInfo->getSectionLoadAddress(*Sec);
          if (SectionLoadAddress != 0)
            Addr += SectionLoadAddress - Sec->getAddress();
        }

        outs() << "Function: " << *Name << ", Size = " << Size
               << ", Addr = " << Addr << "\n";

        DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
        for (auto &D : Lines) {
          outs() << "  Line info @ " << D.first - Addr << ": "
                 << D.second.FileName << ", line:" << D.second.Line << "\n";
        }
      }
    }
  }

  return 0;
}
Exemple #9
0
static int printLineInfoForInput() {
  // Load any dylibs requested on the command line.
  loadDylibs();

  // If we don't have any input files, read from stdin.
  if (!InputFileList.size())
    InputFileList.push_back("-");
  for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
    // Instantiate a dynamic linker.
    TrivialMemoryManager MemMgr;
    RuntimeDyld Dyld(MemMgr, MemMgr);

    // Load the input memory buffer.

    ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
        MemoryBuffer::getFileOrSTDIN(InputFileList[i]);
    if (std::error_code EC = InputBuffer.getError())
      return Error("unable to read input: '" + EC.message() + "'");

    ErrorOr<std::unique_ptr<ObjectFile>> MaybeObj(
      ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));

    if (std::error_code EC = MaybeObj.getError())
      return Error("unable to create object file: '" + EC.message() + "'");

    ObjectFile &Obj = **MaybeObj;

    // Load the object file
    std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo =
      Dyld.loadObject(Obj);

    if (Dyld.hasError())
      return Error(Dyld.getErrorString());

    // Resolve all the relocations we can.
    Dyld.resolveRelocations();

    OwningBinary<ObjectFile> DebugObj = LoadedObjInfo->getObjectForDebug(Obj);

    std::unique_ptr<DIContext> Context(
      new DWARFContextInMemory(*DebugObj.getBinary()));

    // Use symbol info to iterate functions in the object.
    for (object::symbol_iterator I = DebugObj.getBinary()->symbol_begin(),
                                 E = DebugObj.getBinary()->symbol_end();
         I != E; ++I) {
      object::SymbolRef::Type SymType;
      if (I->getType(SymType)) continue;
      if (SymType == object::SymbolRef::ST_Function) {
        StringRef  Name;
        uint64_t   Addr;
        uint64_t   Size;
        if (I->getName(Name)) continue;
        if (I->getAddress(Addr)) continue;
        if (I->getSize(Size)) continue;

        outs() << "Function: " << Name << ", Size = " << Size << "\n";

        DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
        DILineInfoTable::iterator  Begin = Lines.begin();
        DILineInfoTable::iterator  End = Lines.end();
        for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
          outs() << "  Line info @ " << It->first - Addr << ": "
                 << It->second.FileName << ", line:" << It->second.Line << "\n";
        }
      }
    }
  }

  return 0;
}
Exemple #10
0
static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {
  assert(LoadObjects || !UseDebugObj);

  // Load any dylibs requested on the command line.
  loadDylibs();

  // If we don't have any input files, read from stdin.
  if (!InputFileList.size())
    InputFileList.push_back("-");
  for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
    // Instantiate a dynamic linker.
    TrivialMemoryManager MemMgr;
    RuntimeDyld Dyld(MemMgr, MemMgr);

    // Load the input memory buffer.

    ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
        MemoryBuffer::getFileOrSTDIN(InputFileList[i]);
    if (std::error_code EC = InputBuffer.getError())
      return Error("unable to read input: '" + EC.message() + "'");

    ErrorOr<std::unique_ptr<ObjectFile>> MaybeObj(
      ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));

    if (std::error_code EC = MaybeObj.getError())
      return Error("unable to create object file: '" + EC.message() + "'");

    ObjectFile &Obj = **MaybeObj;

    OwningBinary<ObjectFile> DebugObj;
    std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;
    ObjectFile *SymbolObj = &Obj;
    if (LoadObjects) {
      // Load the object file
      LoadedObjInfo =
        Dyld.loadObject(Obj);

      if (Dyld.hasError())
        return Error(Dyld.getErrorString());

      // Resolve all the relocations we can.
      Dyld.resolveRelocations();

      if (UseDebugObj) {
        DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
        SymbolObj = DebugObj.getBinary();
        LoadedObjInfo.reset();
      }
    }

    std::unique_ptr<DIContext> Context(
      new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get()));

    std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =
        object::computeSymbolSizes(*SymbolObj);

    // Use symbol info to iterate functions in the object.
    for (const auto &P : SymAddr) {
      object::SymbolRef Sym = P.first;
      if (Sym.getType() == object::SymbolRef::ST_Function) {
        ErrorOr<StringRef> Name = Sym.getName();
        if (!Name)
          continue;
        ErrorOr<uint64_t> AddrOrErr = Sym.getAddress();
        if (!AddrOrErr)
          continue;
        uint64_t Addr = *AddrOrErr;

        uint64_t Size = P.second;
        // If we're not using the debug object, compute the address of the
        // symbol in memory (rather than that in the unrelocated object file)
        // and use that to query the DWARFContext.
        if (!UseDebugObj && LoadObjects) {
          object::section_iterator Sec(SymbolObj->section_end());
          Sym.getSection(Sec);
          StringRef SecName;
          Sec->getName(SecName);
          uint64_t SectionLoadAddress =
            LoadedObjInfo->getSectionLoadAddress(*Sec);
          if (SectionLoadAddress != 0)
            Addr += SectionLoadAddress - Sec->getAddress();
        }

        outs() << "Function: " << *Name << ", Size = " << Size
               << ", Addr = " << Addr << "\n";

        DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
        DILineInfoTable::iterator  Begin = Lines.begin();
        DILineInfoTable::iterator  End = Lines.end();
        for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
          outs() << "  Line info @ " << It->first - Addr << ": "
                 << It->second.FileName << ", line:" << It->second.Line << "\n";
        }
      }
    }
  }

  return 0;
}
static int doDumpReflectionSections(std::string binaryFilename,
                                    StringRef arch) {
  // Note: binaryOrError and objectOrError own the memory for our ObjectFile;
  // once they go out of scope, we can no longer do anything.
  OwningBinary<Binary> binaryOwner;
  std::unique_ptr<llvm::object::ObjectFile> objectOwner;

  binaryOwner = unwrap(llvm::object::createBinary(binaryFilename));
  const llvm::object::Binary *binaryFile = binaryOwner.getBinary();

  // The object file we are doing lookups in -- either the binary itself, or
  // a particular slice of a universal binary.
  const ObjectFile *objectFile;

  if (auto o = dyn_cast<ObjectFile>(binaryFile)) {
    objectFile = o;
  } else {
    auto universal = cast<MachOUniversalBinary>(binaryFile);
    objectOwner = unwrap(universal->getObjectForArch(arch));
    objectFile = objectOwner.get();
  }

  // Field descriptor section
  auto fieldSectionRef = getSectionRef(objectFile, {
    "__swift3_fieldmd", ".swift3_fieldmd"
  });

  if (fieldSectionRef.getObject() == nullptr) {
    std::cerr << binaryFilename;
    std::cerr << " doesn't have a field reflection section!\n";
    return EXIT_FAILURE;
  }

  StringRef fieldSectionContents;
  fieldSectionRef.getContents(fieldSectionContents);

  const FieldSection fieldSection {
    reinterpret_cast<const void *>(fieldSectionContents.begin()),
    reinterpret_cast<const void *>(fieldSectionContents.end())
  };

  // Associated type section - optional
  AssociatedTypeSection associatedTypeSection {nullptr, nullptr};

  auto associatedTypeSectionRef = getSectionRef(objectFile, {
    "__swift3_assocty", ".swift3_assocty"
  });

  if (associatedTypeSectionRef.getObject() != nullptr) {
    StringRef associatedTypeSectionContents;
    associatedTypeSectionRef.getContents(associatedTypeSectionContents);
    associatedTypeSection = {
      reinterpret_cast<const void *>(associatedTypeSectionContents.begin()),
      reinterpret_cast<const void *>(associatedTypeSectionContents.end()),
    };
  }

  // Builtin types section
  BuiltinTypeSection builtinTypeSection {nullptr, nullptr};

  auto builtinTypeSectionRef = getSectionRef(objectFile, {
    "__swift3_builtin", ".swift3_builtin"
  });

  if (builtinTypeSectionRef.getObject() != nullptr) {
    StringRef builtinTypeSectionContents;
    builtinTypeSectionRef.getContents(builtinTypeSectionContents);

    builtinTypeSection = {
      reinterpret_cast<const void *>(builtinTypeSectionContents.begin()),
      reinterpret_cast<const void *>(builtinTypeSectionContents.end())
    };
  }

  // Typeref section
  auto typeRefSectionRef = getSectionRef(objectFile, {
    "__swift3_typeref", ".swift3_typeref"
  });

  if (typeRefSectionRef.getObject() == nullptr) {
    std::cerr << binaryFilename;
    std::cerr << " doesn't have an associated typeref section!\n";
    return EXIT_FAILURE;
  }

  StringRef typeRefSectionContents;
  typeRefSectionRef.getContents(typeRefSectionContents);

  const GenericSection typeRefSection {
    reinterpret_cast<const void *>(typeRefSectionContents.begin()),
    reinterpret_cast<const void *>(typeRefSectionContents.end())
  };

  // Reflection strings section
  auto reflectionStringsSectionRef = getSectionRef(objectFile, {
    "__swift3_reflstr", ".swift3_reflstr"
  });

  if (reflectionStringsSectionRef.getObject() == nullptr) {
    std::cerr << binaryFilename;
    std::cerr << " doesn't have an associated reflection strings section!\n";
    return EXIT_FAILURE;
  }

  StringRef reflectionStringsSectionContents;
  reflectionStringsSectionRef.getContents(reflectionStringsSectionContents);

  const GenericSection reflectionStringsSection {
    reinterpret_cast<const void *>(reflectionStringsSectionContents.begin()),
    reinterpret_cast<const void *>(reflectionStringsSectionContents.end())
  };

  // Construct the reflection context
  auto reader = std::make_shared<InProcessMemoryReader>();
  ReflectionContext<External<RuntimeTarget<8>>> RC(reader);
  RC.addReflectionInfo({
    binaryFilename,
    fieldSection,
    associatedTypeSection,
    builtinTypeSection,
    typeRefSection,
    reflectionStringsSection,
  });

  // Dump everything
  RC.dumpAllSections(std::cout);

  return EXIT_SUCCESS;
}