//===- yaml2obj - Convert YAML to a binary object file --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program takes a YAML description of an object file and outputs the
// binary equivalent.
//
// This is used for writing tests that require binary files.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <vector>
using namespace llvm;
static cl::opt<std::string>
Input(cl::Positional, cl::desc("<input>"), cl::init("-"));
template<class T>
typename llvm::enable_if_c<std::numeric_limits<T>::is_integer, bool>::type
getAs(const llvm::yaml::ScalarNode *SN, T &Result) {
SmallString<4> Storage;
StringRef Value = SN->getValue(Storage);
if (Value.getAsInteger(0, Result))
return false;
return true;
}
// Given a container with begin and end with ::value_type of a character type.
// Iterate through pairs of characters in the the set of [a-fA-F0-9] ignoring
// all other characters.
struct hex_pair_iterator {
StringRef::const_iterator Current, End;
typedef SmallVector<char, 2> value_type;
value_type Pair;
bool IsDone;
hex_pair_iterator(StringRef C)
: Current(C.begin()), End(C.end()), IsDone(false) {
// Initalize Pair.
++*this;
}
// End iterator.
hex_pair_iterator() : Current(), End(), IsDone(true) {}
value_type operator *() const {
return Pair;
}
hex_pair_iterator operator ++() {
// We're at the end of the input.
if (Current == End) {
IsDone = true;
return *this;
}
Pair = value_type();
for (; Current != End && Pair.size() != 2; ++Current) {
// Is a valid hex digit.
if ((*Current >= '0' && *Current <= '9') ||
(*Current >= 'a' && *Current <= 'f') ||
(*Current >= 'A' && *Current <= 'F'))
Pair.push_back(*Current);
}
// Hit the end without getting 2 hex digits. Pair is invalid.
if (Pair.size() != 2)
IsDone = true;
return *this;
}
bool operator ==(const hex_pair_iterator Other) {
return (IsDone == Other.IsDone) ||
(Current == Other.Current && End == Other.End);
}
bool operator !=(const hex_pair_iterator Other) {
return !(*this == Other);
}
};
template <class ContainerOut>
static bool hexStringToByteArray(StringRef Str, ContainerOut &Out) {
for (hex_pair_iterator I(Str), E; I != E; ++I) {
typename hex_pair_iterator::value_type Pair = *I;
typename ContainerOut::value_type Byte;
if (StringRef(Pair.data(), 2).getAsInteger(16, Byte))
return false;
Out.push_back(Byte);
}
return true;
}
/// This parses a yaml stream that represents a COFF object file.
/// See docs/yaml2obj for the yaml scheema.
struct COFFParser {
COFFParser(yaml::Stream &Input) : YS(Input) {
std::memset(&Header, 0, sizeof(Header));
// A COFF string table always starts with a 4 byte size field. Offsets into
// it include this size, so allocate it now.
StringTable.append(4, 0);
}
bool parseHeader(yaml::Node *HeaderN) {
yaml::MappingNode *MN = dyn_cast<yaml::MappingNode>(HeaderN);
if (!MN) {
YS.printError(HeaderN, "header's value must be a mapping node");
return false;
}
for (yaml::MappingNode::iterator i = MN->begin(), e = MN->end();
i != e; ++i) {
yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(i->getKey());
if (!Key) {
YS.printError(i->getKey(), "Keys must be scalar values");
return false;
}
SmallString<32> Storage;
StringRef KeyValue = Key->getValue(Storage);
if (KeyValue == "Characteristics") {
if (!parseHeaderCharacteristics(i->