Пример #1
0
static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
  uint64_t OldPos = OS.tell();
  OS << Data;
  unsigned SizeSoFar = OS.tell() - OldPos;
  assert(SizeSoFar <= Size && "Data doesn't fit in Size");
  OS.indent(Size - SizeSoFar);
}
Пример #2
0
static void
printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
                  StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
                  bool Thin, const NewArchiveMember &M,
                  sys::TimePoint<std::chrono::seconds> ModTime, unsigned Size) {
  if (isBSDLike(Kind))
    return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
                                M.Perms, Size);
  if (!useStringTable(Thin, M.MemberName))
    return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
                                     M.Perms, Size);
  Out << '/';
  uint64_t NamePos;
  if (Thin) {
    NamePos = StringTable.tell();
    StringTable << M.MemberName << "/\n";
  } else {
    auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
    if (Insertion.second) {
      Insertion.first->second = StringTable.tell();
      StringTable << M.MemberName << "/\n";
    }
    NamePos = Insertion.first->second;
  }
  printWithSpacePadding(Out, NamePos, 15);
  printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size);
}
static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
                      StringRef Suffix) {
    uint64_t Pos = OS.tell();
    OS << Prefix;
    for (unsigned i = OS.tell() - Pos, e = 80 - Suffix.size(); i != e; ++i)
        OS << Fill;
    OS << Suffix << '\n';
}
Пример #4
0
static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
  uint64_t OldPos = OS.tell();
  OS << Data;
  unsigned SizeSoFar = OS.tell() - OldPos;
  assert(Size >= SizeSoFar && "Data doesn't fit in Size");
  unsigned Remaining = Size - SizeSoFar;
  for (unsigned I = 0; I < Remaining; ++I)
    OS << ' ';
}
Пример #5
0
static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
                      StringRef Suffix) {
  size_t Pos = (size_t)OS.tell();
  assert((Prefix.str().size() + Suffix.size() <= MAX_LINE_LEN) &&
         "header line exceeds max limit");
  OS << Prefix;
  for (size_t i = (size_t)OS.tell() - Pos, e = MAX_LINE_LEN - Suffix.size();
         i < e; ++i)
    OS << Fill;
  OS << Suffix << '\n';
}
Пример #6
0
std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
  OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;

  // Populate the hash table generator.
  for (const auto &I : FunctionData)
    Generator.insert(I.getKey(), &I.getValue());

  using namespace llvm::support;
  endian::Writer<little> LE(OS);

  // Write the header.
  IndexedInstrProf::Header Header;
  Header.Magic = IndexedInstrProf::Magic;
  Header.Version = IndexedInstrProf::Version;
  Header.MaxFunctionCount = MaxFunctionCount;
  Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType);
  Header.HashOffset = 0;
  int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t);

  // Only write out all the fields execpt 'HashOffset'. We need
  // to remember the offset of that field to allow back patching
  // later.
  for (int I = 0; I < N - 1; I++)
    LE.write<uint64_t>(reinterpret_cast<uint64_t *>(&Header)[I]);

  // Save a space to write the hash table start location.
  uint64_t HashTableStartLoc = OS.tell();
  // Reserve the space for HashOffset field.
  LE.write<uint64_t>(0);
  // Write the hash table.
  uint64_t HashTableStart = Generator.Emit(OS);

  return std::make_pair(HashTableStartLoc, HashTableStart);
}
Пример #7
0
void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
  for (auto Range : DI.ARanges) {
    auto HeaderStart = OS.tell();
    writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian);
    writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
    writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
    writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
    writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);

    auto HeaderSize = OS.tell() - HeaderStart;
    auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
    ZeroFillBytes(OS, FirstDescriptor - HeaderSize);

    for (auto Descriptor : Range.Descriptors) {
      writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
                                DI.IsLittleEndian);
      writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
                                DI.IsLittleEndian);
    }
    ZeroFillBytes(OS, Range.AddrSize * 2);
  }
}
Пример #8
0
static Expected<std::vector<unsigned>>
getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
  std::vector<unsigned> Ret;

  // In the scenario when LLVMContext is populated SymbolicFile will contain a
  // reference to it, thus SymbolicFile should be destroyed first.
  LLVMContext Context;
  std::unique_ptr<object::SymbolicFile> Obj;
  if (identify_magic(Buf.getBuffer()) == file_magic::bitcode) {
    auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
        Buf, file_magic::bitcode, &Context);
    if (!ObjOrErr) {
      // FIXME: check only for "not an object file" errors.
      consumeError(ObjOrErr.takeError());
      return Ret;
    }
    Obj = std::move(*ObjOrErr);
  } else {
    auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
    if (!ObjOrErr) {
      // FIXME: check only for "not an object file" errors.
      consumeError(ObjOrErr.takeError());
      return Ret;
    }
    Obj = std::move(*ObjOrErr);
  }

  HasObject = true;
  for (const object::BasicSymbolRef &S : Obj->symbols()) {
    if (!isArchiveSymbol(S))
      continue;
    Ret.push_back(SymNames.tell());
    if (auto EC = S.printName(SymNames))
      return errorCodeToError(EC);
    SymNames << '\0';
  }
  return Ret;
}
Пример #9
0
std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
  OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;

  // Populate the hash table generator.
  for (const auto &I : FunctionData)
    Generator.insert(I.getKey(), &I.getValue());

  using namespace llvm::support;
  endian::Writer<little> LE(OS);

  // Write the header.
  LE.write<uint64_t>(IndexedInstrProf::Magic);
  LE.write<uint64_t>(IndexedInstrProf::Version);
  LE.write<uint64_t>(MaxFunctionCount);
  LE.write<uint64_t>(static_cast<uint64_t>(IndexedInstrProf::HashType));

  // Save a space to write the hash table start location.
  uint64_t HashTableStartLoc = OS.tell();
  LE.write<uint64_t>(0);
  // Write the hash table.
  uint64_t HashTableStart = Generator.Emit(OS);

  return std::make_pair(HashTableStartLoc, HashTableStart);
}
Пример #10
0
static Expected<std::vector<MemberData>>
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
                  object::Archive::Kind Kind, bool Thin, bool Deterministic,
                  ArrayRef<NewArchiveMember> NewMembers) {
  static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};

  // This ignores the symbol table, but we only need the value mod 8 and the
  // symbol table is aligned to be a multiple of 8 bytes
  uint64_t Pos = 0;

  std::vector<MemberData> Ret;
  bool HasObject = false;

  // Deduplicate long member names in the string table and reuse earlier name
  // offsets. This especially saves space for COFF Import libraries where all
  // members have the same name.
  StringMap<uint64_t> MemberNames;

  // UniqueTimestamps is a special case to improve debugging on Darwin:
  //
  // The Darwin linker does not link debug info into the final
  // binary. Instead, it emits entries of type N_OSO in in the output
  // binary's symbol table, containing references to the linked-in
  // object files. Using that reference, the debugger can read the
  // debug data directly from the object files. Alternatively, an
  // invocation of 'dsymutil' will link the debug data from the object
  // files into a dSYM bundle, which can be loaded by the debugger,
  // instead of the object files.
  //
  // For an object file, the N_OSO entries contain the absolute path
  // path to the file, and the file's timestamp. For an object
  // included in an archive, the path is formatted like
  // "/absolute/path/to/archive.a(member.o)", and the timestamp is the
  // archive member's timestamp, rather than the archive's timestamp.
  //
  // However, this doesn't always uniquely identify an object within
  // an archive -- an archive file can have multiple entries with the
  // same filename. (This will happen commonly if the original object
  // files started in different directories.) The only way they get
  // distinguished, then, is via the timestamp. But this process is
  // unable to find the correct object file in the archive when there
  // are two files of the same name and timestamp.
  //
  // Additionally, timestamp==0 is treated specially, and causes the
  // timestamp to be ignored as a match criteria.
  //
  // That will "usually" work out okay when creating an archive not in
  // deterministic timestamp mode, because the objects will probably
  // have been created at different timestamps.
  //
  // To ameliorate this problem, in deterministic archive mode (which
  // is the default), on Darwin we will emit a unique non-zero
  // timestamp for each entry with a duplicated name. This is still
  // deterministic: the only thing affecting that timestamp is the
  // order of the files in the resultant archive.
  //
  // See also the functions that handle the lookup:
  // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
  // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
  bool UniqueTimestamps = Deterministic && isDarwin(Kind);
  std::map<StringRef, unsigned> FilenameCount;
  if (UniqueTimestamps) {
    for (const NewArchiveMember &M : NewMembers)
      FilenameCount[M.MemberName]++;
    for (auto &Entry : FilenameCount)
      Entry.second = Entry.second > 1 ? 1 : 0;
  }

  for (const NewArchiveMember &M : NewMembers) {
    std::string Header;
    raw_string_ostream Out(Header);

    MemoryBufferRef Buf = M.Buf->getMemBufferRef();
    StringRef Data = Thin ? "" : Buf.getBuffer();

    // ld64 expects the members to be 8-byte aligned for 64-bit content and at
    // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
    // uniformly.  This matches the behaviour with cctools and ensures that ld64
    // is happy with archives that we generate.
    unsigned MemberPadding =
        isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0;
    unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2);
    StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);

    sys::TimePoint<std::chrono::seconds> ModTime;
    if (UniqueTimestamps)
      // Increment timestamp for each file of a given name.
      ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
    else
      ModTime = M.ModTime;
    printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
                      ModTime, Buf.getBufferSize() + MemberPadding);
    Out.flush();

    Expected<std::vector<unsigned>> Symbols =
        getSymbols(Buf, SymNames, HasObject);
    if (auto E = Symbols.takeError())
      return std::move(E);

    Pos += Header.size() + Data.size() + Padding.size();
    Ret.push_back({std::move(*Symbols), std::move(Header), Data, Padding});
  }
  // If there are no symbols, emit an empty symbol table, to satisfy Solaris
  // tools, older versions of which expect a symbol table in a non-empty
  // archive, regardless of whether there are any symbols in it.
  if (HasObject && SymNames.tell() == 0)
    SymNames << '\0' << '\0' << '\0';
  return Ret;
}
Пример #11
0
void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) {
  debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
  encodeSLEB128(Number, OS);
}
Пример #12
0
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
                             bool Deterministic, ArrayRef<MemberData> Members,
                             StringRef StringTable) {
  // We don't write a symbol table on an archive with no members -- except on
  // Darwin, where the linker will abort unless the archive has a symbol table.
  if (StringTable.empty() && !isDarwin(Kind))
    return;

  unsigned NumSyms = 0;
  for (const MemberData &M : Members)
    NumSyms += M.Symbols.size();

  unsigned Size = 0;
  unsigned OffsetSize = is64BitKind(Kind) ? sizeof(uint64_t) : sizeof(uint32_t);

  Size += OffsetSize; // Number of entries
  if (isBSDLike(Kind))
    Size += NumSyms * OffsetSize * 2; // Table
  else
    Size += NumSyms * OffsetSize; // Table
  if (isBSDLike(Kind))
    Size += OffsetSize; // byte count
  Size += StringTable.size();
  // ld64 expects the members to be 8-byte aligned for 64-bit content and at
  // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
  // uniformly.
  // We do this for all bsd formats because it simplifies aligning members.
  unsigned Alignment = isBSDLike(Kind) ? 8 : 2;
  unsigned Pad = OffsetToAlignment(Size, Alignment);
  Size += Pad;

  if (isBSDLike(Kind)) {
    const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
    printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
                         Size);
  } else {
    const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
    printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
  }

  uint64_t Pos = Out.tell() + Size;

  if (isBSDLike(Kind))
    printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
  else
    printNBits(Out, Kind, NumSyms);

  for (const MemberData &M : Members) {
    for (unsigned StringOffset : M.Symbols) {
      if (isBSDLike(Kind))
        printNBits(Out, Kind, StringOffset);
      printNBits(Out, Kind, Pos); // member offset
    }
    Pos += M.Header.size() + M.Data.size() + M.Padding.size();
  }

  if (isBSDLike(Kind))
    // byte count of the string table
    printNBits(Out, Kind, StringTable.size());
  Out << StringTable;

  while (Pad--)
    Out.write(uint8_t(0));
}
Пример #13
0
void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count,
                      const Twine &Msg) {
  debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]");
  OS.write(Bytes, Count);
}
Пример #14
0
void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) {
  debugWrite(OS.tell(),
             Msg + " [str[" + Twine(String.size()) + "]: " + String + "]");
  encodeULEB128(String.size(), OS);
  OS.write(String.data(), String.size());
}
void WebAssemblyMCCodeEmitter::encodeInstruction(
    const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
    const MCSubtargetInfo &STI) const {
  uint64_t Start = OS.tell();

  uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
  assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet");
  OS << uint8_t(Binary);

  // For br_table instructions, encode the size of the table. In the MCInst,
  // there's an index operand, one operand for each table entry, and the
  // default operand.
  if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
      MI.getOpcode() == WebAssembly::BR_TABLE_I64)
    encodeULEB128(MI.getNumOperands() - 2, OS);

  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
  for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
    const MCOperand &MO = MI.getOperand(i);
    if (MO.isReg()) {
      /* nothing to encode */
    } else if (MO.isImm()) {
      if (i < Desc.getNumOperands()) {
        assert(Desc.TSFlags == 0 &&
               "WebAssembly non-variable_ops don't use TSFlags");
        const MCOperandInfo &Info = Desc.OpInfo[i];
        if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
          encodeSLEB128(int32_t(MO.getImm()), OS);
        } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
          encodeSLEB128(int64_t(MO.getImm()), OS);
        } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
          llvm_unreachable("wasm globals should only be accessed symbolicly");
        } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
          encodeSLEB128(int64_t(MO.getImm()), OS);
        } else {
          encodeULEB128(uint64_t(MO.getImm()), OS);
        }
      } else {
        assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate |
                                WebAssemblyII::VariableOpImmediateIsLabel));
        encodeULEB128(uint64_t(MO.getImm()), OS);
      }
    } else if (MO.isFPImm()) {
      assert(i < Desc.getNumOperands() &&
             "Unexpected floating-point immediate as a non-fixed operand");
      assert(Desc.TSFlags == 0 &&
             "WebAssembly variable_ops floating point ops don't use TSFlags");
      const MCOperandInfo &Info = Desc.OpInfo[i];
      if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
        // TODO: MC converts all floating point immediate operands to double.
        // This is fine for numeric values, but may cause NaNs to change bits.
        float f = float(MO.getFPImm());
        support::endian::Writer<support::little>(OS).write<float>(f);
      } else {
        assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
        double d = MO.getFPImm();
        support::endian::Writer<support::little>(OS).write<double>(d);
      }
    } else if (MO.isExpr()) {
      const MCOperandInfo &Info = Desc.OpInfo[i];
      llvm::MCFixupKind FixupKind;
      size_t PaddedSize;
      if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
        FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32);
        PaddedSize = 5;
      } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
        FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64);
        PaddedSize = 10;
      } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 ||
                 Info.OperandType == WebAssembly::OPERAND_OFFSET32 ||
                 Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
        FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
        PaddedSize = 5;
      } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
        FixupKind = MCFixupKind(WebAssembly::fixup_code_global_index);
        PaddedSize = 5;
      } else {
        llvm_unreachable("unexpected symbolic operand kind");
      }
      Fixups.push_back(MCFixup::create(
          OS.tell() - Start, MO.getExpr(),
          FixupKind, MI.getLoc()));
      ++MCNumFixups;
      encodeULEB128(0, OS, PaddedSize - 1);
    } else {
      llvm_unreachable("unexpected operand kind");
    }
  }

  ++MCNumEmitted; // Keep track of the # of mi's emitted.
}
Пример #16
0
void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) {
  debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]");
  OS << Byte;
}
Пример #17
0
void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
  debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]");
  support::endian::write(OS, Number, support::little);
}