Skip to content

Commit

Permalink
[yaml2obj][obj2yaml] - Teach tools to work with regular archives.
Browse files Browse the repository at this point in the history
This teaches obj2yaml to dump valid regular (not thin) archives.
This also teaches yaml2obj to recognize archives YAML descriptions,
what allows to craft all different kinds of archives (valid and broken ones).

Differential revision: https://reviews.llvm.org/D89949
  • Loading branch information
Georgii Rymar committed Oct 28, 2020
1 parent f53d7f5 commit 47369e1
Show file tree
Hide file tree
Showing 14 changed files with 628 additions and 6 deletions.
77 changes: 77 additions & 0 deletions llvm/include/llvm/ObjectYAML/ArchiveYAML.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===- ArchiveYAML.h - Archive YAMLIO implementation ------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file declares classes for handling the YAML representation of archives.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_OBJECTYAML_ARCHIVEYAML_H
#define LLVM_OBJECTYAML_ARCHIVEYAML_H

#include "llvm/Support/YAMLTraits.h"
#include "llvm/ObjectYAML/YAML.h"
#include "llvm/ADT/MapVector.h"

namespace llvm {
namespace ArchYAML {

struct Archive {
struct Child {
struct Field {
Field() = default;
Field(StringRef Default, unsigned Length)
: DefaultValue(Default), MaxLength(Length) {}
StringRef Value;
StringRef DefaultValue;
unsigned MaxLength;
};

Child() {
Fields["Name"] = {"", 16};
Fields["LastModified"] = {"0", 12};
Fields["UID"] = {"0", 6};
Fields["GID"] = {"0", 6};
Fields["AccessMode"] = {"0", 8};
Fields["Size"] = {"0", 10};
Fields["Terminator"] = {"`\n", 2};
}

MapVector<StringRef, Field> Fields;

Optional<yaml::BinaryRef> Content;
Optional<llvm::yaml::Hex8> PaddingByte;
};

StringRef Magic;
Optional<std::vector<Child>> Members;
Optional<yaml::BinaryRef> Content;
};

} // end namespace ArchYAML
} // end namespace llvm

LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ArchYAML::Archive::Child)

namespace llvm {
namespace yaml {

template <> struct MappingTraits<ArchYAML::Archive> {
static void mapping(IO &IO, ArchYAML::Archive &A);
static std::string validate(IO &, ArchYAML::Archive &A);
};

template <> struct MappingTraits<ArchYAML::Archive::Child> {
static void mapping(IO &IO, ArchYAML::Archive::Child &C);
static std::string validate(IO &, ArchYAML::Archive::Child &C);
};

} // end namespace yaml
} // end namespace llvm

#endif // LLVM_OBJECTYAML_ARCHIVEYAML_H
2 changes: 2 additions & 0 deletions llvm/include/llvm/ObjectYAML/ObjectYAML.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_OBJECTYAML_OBJECTYAML_H
#define LLVM_OBJECTYAML_OBJECTYAML_H

#include "llvm/ObjectYAML/ArchiveYAML.h"
#include "llvm/ObjectYAML/COFFYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
#include "llvm/ObjectYAML/MachOYAML.h"
Expand All @@ -23,6 +24,7 @@ namespace yaml {
class IO;

struct YamlObjectFile {
std::unique_ptr<ArchYAML::Archive> Arch;
std::unique_ptr<ELFYAML::Object> Elf;
std::unique_ptr<COFFYAML::Object> Coff;
std::unique_ptr<MachOYAML::Object> MachO;
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/ObjectYAML/yaml2obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ namespace WasmYAML {
struct Object;
}

namespace ArchYAML {
struct Archive;
}

namespace yaml {
class Input;
struct YamlObjectFile;

using ErrorHandler = llvm::function_ref<void(const Twine &Msg)>;

bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out, ErrorHandler EH);
bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH,
uint64_t MaxSize);
Expand Down
51 changes: 51 additions & 0 deletions llvm/lib/ObjectYAML/ArchiveEmitter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===- ArchiveEmitter.cpp ---------------------------- --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/ObjectYAML/ArchiveYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace ArchYAML;

namespace llvm {
namespace yaml {

bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out, ErrorHandler EH) {
Out.write(Doc.Magic.data(), Doc.Magic.size());

if (Doc.Content) {
Doc.Content->writeAsBinary(Out);
return true;
}

if (!Doc.Members)
return true;

auto WriteField = [&](StringRef Field, uint8_t Size) {
Out.write(Field.data(), Field.size());
for (size_t I = Field.size(); I != Size; ++I)
Out.write(' ');
};

for (const Archive::Child &C : *Doc.Members) {
for (auto &P : C.Fields)
WriteField(P.second.Value, P.second.MaxLength);

if (C.Content)
C.Content->writeAsBinary(Out);
if (C.PaddingByte)
Out.write(*C.PaddingByte);
}

return true;
}

} // namespace yaml
} // namespace llvm
58 changes: 58 additions & 0 deletions llvm/lib/ObjectYAML/ArchiveYAML.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===- ArchiveYAML.cpp - ELF YAMLIO implementation -------------------- ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines classes for handling the YAML representation of archives.
//
//===----------------------------------------------------------------------===//

#include "llvm/ObjectYAML/ArchiveYAML.h"

namespace llvm {

namespace yaml {

void MappingTraits<ArchYAML::Archive>::mapping(IO &IO, ArchYAML::Archive &A) {
assert(!IO.getContext() && "The IO context is initialized already");
IO.setContext(&A);
IO.mapTag("!Arch", true);
IO.mapOptional("Magic", A.Magic, "!<arch>\n");
IO.mapOptional("Members", A.Members);
IO.mapOptional("Content", A.Content);
IO.setContext(nullptr);
}

std::string MappingTraits<ArchYAML::Archive>::validate(IO &,
ArchYAML::Archive &A) {
if (A.Members && A.Content)
return "\"Content\" and \"Members\" cannot be used together";
return "";
}

void MappingTraits<ArchYAML::Archive::Child>::mapping(
IO &IO, ArchYAML::Archive::Child &E) {
assert(IO.getContext() && "The IO context is not initialized");
for (auto &P : E.Fields)
IO.mapOptional(P.first.data(), P.second.Value, P.second.DefaultValue);
IO.mapOptional("Content", E.Content);
IO.mapOptional("PaddingByte", E.PaddingByte);
}

std::string
MappingTraits<ArchYAML::Archive::Child>::validate(IO &,
ArchYAML::Archive::Child &C) {
for (auto &P : C.Fields)
if (P.second.Value.size() > P.second.MaxLength)
return ("the maximum length of \"" + P.first + "\" field is " +
Twine(P.second.MaxLength))
.str();
return "";
}

} // end namespace yaml

} // end namespace llvm
2 changes: 2 additions & 0 deletions llvm/lib/ObjectYAML/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
add_llvm_component_library(LLVMObjectYAML
ArchiveEmitter.cpp
ArchiveYAML.cpp
CodeViewYAMLDebugSections.cpp
CodeViewYAMLSymbols.cpp
CodeViewYAMLTypeHashing.cpp
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/ObjectYAML/ObjectYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
*ObjectFile.FatMachO);
} else {
Input &In = (Input &)IO;
if (IO.mapTag("!ELF")) {
if (IO.mapTag("!Arch")) {
ObjectFile.Arch.reset(new ArchYAML::Archive());
MappingTraits<ArchYAML::Archive>::mapping(IO, *ObjectFile.Arch);
std::string Err =
MappingTraits<ArchYAML::Archive>::validate(IO, *ObjectFile.Arch);
if (!Err.empty())
IO.setError(Err);
} else if (IO.mapTag("!ELF")) {
ObjectFile.Elf.reset(new ELFYAML::Object());
MappingTraits<ELFYAML::Object>::mapping(IO, *ObjectFile.Elf);
} else if (IO.mapTag("!COFF")) {
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/ObjectYAML/yaml2obj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
return false;
}

if (Doc.Arch)
return yaml2archive(*Doc.Arch, Out, ErrHandler);
if (Doc.Elf)
return yaml2elf(*Doc.Elf, Out, ErrHandler, MaxSize);
if (Doc.Coff)
Expand Down
Loading

0 comments on commit 47369e1

Please sign in to comment.