<div style="font-family: arial, helvetica, sans-serif"><font size="2"><div class="gmail_quote">On Sun, Jun 17, 2012 at 5:34 AM, Michael Spencer <span dir="ltr"><<a href="mailto:bigcheesegs@gmail.com" target="_blank">bigcheesegs@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">On Wed, May 30, 2012 at 8:22 AM, Manuel Klimek <<a href="mailto:klimek@google.com">klimek@google.com</a>> wrote:<br>

> +static cl::opt<std::string><br>
> +  Input(cl::Positional, cl::desc("<input>"));<br>
> +<br>
> +template<class T><br>
> +typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type<br>
><br>
> I think a static assert is more readable than std::enable_if if there<br>
> are no overloads involved.<br>
<br>
</div>There will be other overloads. And this is C++03 so we don't have static assert.<br>
<div class="im"><br>
> +struct COFFParser {<br>
><br>
> I'd add a small class level comment on what kind of YAML this class parses...<br>
><br>
> +  COFFParser(yaml::Stream &Input) : YS(Input) {<br>
> +    std::memset(&Header, 0, sizeof(Header));<br>
><br>
> Would it be nicer to give COFF::header a constructor? (perhaps not in<br>
> this changelist, but in general)<br>
<br>
</div>There's really no sane constructor for it.<br></blockquote><div><br></div><div>You're saying we can't change it?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">
> +    // Initalize the string table size.<br>
> +    StringTable.append(4, 0);<br>
><br>
> It's really hard for me to understand what StringTable is used for,<br>
> and why initializing it with 4 0-characters makes any sense...<br>
<br>
</div>Added explanation.<br>
<div><div class="h5"><br>
> +  }<br>
> +<br>
> +  bool parseHeader(yaml::Node *HeaderN) {<br>
> +    yaml::MappingNode *MN = dyn_cast<yaml::MappingNode>(HeaderN);<br>
> +    if (!MN) {<br>
> +      YS.printError(HeaderN, "header's value must be a mapping node");<br>
> +      return false;<br>
> +    }<br>
> +    for (yaml::MappingNode::iterator i = MN->begin(), e = MN->end();<br>
> +                                     i != e; ++i) {<br>
> +      yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(i->getKey());<br>
> +      if (!Key) {<br>
> +        YS.printError(i->getKey(), "Keys must be scalar values");<br>
> +        return false;<br>
> +      }<br>
> +      SmallString<32> Storage;<br>
> +      StringRef KeyValue = Key->getValue(Storage);<br>
> +      if (KeyValue == "Characteristics") {<br>
> +        yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(i->getValue());<br>
> +        yaml::SequenceNode *SeqValue<br>
> +          = dyn_cast<yaml::SequenceNode>(i->getValue());<br>
> +        if (!Value && !SeqValue) {<br>
> +          YS.printError(i->getValue(),<br>
> +            "Characteristics must either be a number or sequence");<br>
><br>
> "... scalar value or sequence" ?<br>
<br>
</div></div>It needs to be a number, this is checked a few lines down.<br></blockquote><div><br></div><div>Ah, ok. getAs is a little magic for my taste, but, oh well, that's probably taste :)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><div class="h5"><br>
> +          return false;<br>
> +        }<br>
> +        if (Value) {<br>
> +          if (!getAs(Value, Header.Characteristics)) {<br>
> +            YS.printError(Value, "Invalid value for Characteristics");<br>
> +            return false;<br>
> +          }<br>
> +        } else {<br>
> +          for (yaml::SequenceNode::iterator ci = SeqValue->begin(),<br>
> +                                            ce = SeqValue->end();<br>
> +                                            ci != ce; ++ci) {<br>
> +            yaml::ScalarNode *CharValue = dyn_cast<yaml::ScalarNode>(&*ci);<br>
> +            if (!CharValue) {<br>
> +              YS.printError(CharValue,<br>
> +                "Characteristics must be scalar values");<br>
> +              return false;<br>
> +            }<br>
> +            StringRef Char = CharValue->getValue(Storage);<br>
> +            Header.Characteristics |= StringSwitch<COFF::Characteristics>(Char)<br>
> +              .Case( "IMAGE_FILE_RELOCS_STRIPPED"<br>
> +                   , COFF::IMAGE_FILE_RELOCS_STRIPPED)<br>
> +              .Case( "IMAGE_FILE_EXECUTABLE_IMAGE"<br>
> +                   , COFF::IMAGE_FILE_EXECUTABLE_IMAGE)<br>
> +              .Case( "IMAGE_FILE_LINE_NUMS_STRIPPED"<br>
> +                   , COFF::IMAGE_FILE_LINE_NUMS_STRIPPED)<br>
> +              .Case( "IMAGE_FILE_LOCAL_SYMS_STRIPPED"<br>
> +                   , COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED)<br>
> +              .Case( "IMAGE_FILE_AGGRESSIVE_WS_TRIM"<br>
> +                   , COFF::IMAGE_FILE_AGGRESSIVE_WS_TRIM)<br>
> +              .Case( "IMAGE_FILE_LARGE_ADDRESS_AWARE"<br>
> +                   , COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE)<br>
> +              .Case( "IMAGE_FILE_BYTES_REVERSED_LO"<br>
> +                   , COFF::IMAGE_FILE_BYTES_REVERSED_LO)<br>
> +              .Case( "IMAGE_FILE_32BIT_MACHINE"<br>
> +                   , COFF::IMAGE_FILE_32BIT_MACHINE)<br>
> +              .Case( "IMAGE_FILE_DEBUG_STRIPPED"<br>
> +                   , COFF::IMAGE_FILE_DEBUG_STRIPPED)<br>
> +              .Case( "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP"<br>
> +                   , COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)<br>
> +              .Case( "IMAGE_FILE_SYSTEM"<br>
> +                   , COFF::IMAGE_FILE_SYSTEM)<br>
> +              .Case( "IMAGE_FILE_DLL"<br>
> +                   , COFF::IMAGE_FILE_DLL)<br>
> +              .Case( "IMAGE_FILE_UP_SYSTEM_ONLY"<br>
> +                   , COFF::IMAGE_FILE_UP_SYSTEM_ONLY)<br>
> +              .Default(COFF::Characteristics(-1));<br>
><br>
> I don't know whether or-ing -1 is considered idiomatic here, but I'd<br>
> probably prefer a named constant...<br>
<br>
</div></div>The intent was to give a unknown string value. Fixed to do this.<br>
<div class="im"><br>
> +          }<br>
> +        }<br>
><br>
> Those if's have really large contexts, I'd prefer having smaller functions.<br>
<br>
</div>Fixed.<br></blockquote><div><br></div><div>Thx.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
> +      } else {<br>
> +        yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(i->getValue());<br>
> +        if (!Value) {<br>
> +          YS.printError(Value, "Machine must be a scalar value");<br>
><br>
> Why is that not inside the if-"Machine" case?<br>
<br>
</div>All of the following require a scalar value. The error message is wrong. Fixed.<br>
<div><div class="h5"><br>
> +          return false;<br>
> +        }<br>
> +        if (KeyValue == "Machine") {<br>
> +          uint16_t Machine;<br>
> +          if (!getAs(Value, Machine)) {<br>
> +            // It's not a raw number, try matching the string.<br>
> +            StringRef ValueValue = Value->getValue(Storage);<br>
> +            Machine = StringSwitch<COFF::MachineTypes>(ValueValue)<br>
> +              .Case( "IMAGE_FILE_MACHINE_UNKNOWN"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_UNKNOWN)<br>
> +              .Case( "IMAGE_FILE_MACHINE_AM33"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_AM33)<br>
> +              .Case( "IMAGE_FILE_MACHINE_AMD64"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_AMD64)<br>
> +              .Case( "IMAGE_FILE_MACHINE_ARM"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_ARM)<br>
> +              .Case( "IMAGE_FILE_MACHINE_ARMV7"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_ARMV7)<br>
> +              .Case( "IMAGE_FILE_MACHINE_EBC"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_EBC)<br>
> +              .Case( "IMAGE_FILE_MACHINE_I386"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_I386)<br>
> +              .Case( "IMAGE_FILE_MACHINE_IA64"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_IA64)<br>
> +              .Case( "IMAGE_FILE_MACHINE_M32R"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_M32R)<br>
> +              .Case( "IMAGE_FILE_MACHINE_MIPS16"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_MIPS16)<br>
> +              .Case( "IMAGE_FILE_MACHINE_MIPSFPU"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_MIPSFPU)<br>
> +              .Case( "IMAGE_FILE_MACHINE_MIPSFPU16"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_MIPSFPU16)<br>
> +              .Case( "IMAGE_FILE_MACHINE_POWERPC"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_POWERPC)<br>
> +              .Case( "IMAGE_FILE_MACHINE_POWERPCFP"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_POWERPCFP)<br>
> +              .Case( "IMAGE_FILE_MACHINE_R4000"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_R4000)<br>
> +              .Case( "IMAGE_FILE_MACHINE_SH3"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_SH3)<br>
> +              .Case( "IMAGE_FILE_MACHINE_SH3DSP"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_SH3DSP)<br>
> +              .Case( "IMAGE_FILE_MACHINE_SH4"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_SH4)<br>
> +              .Case( "IMAGE_FILE_MACHINE_SH5"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_SH5)<br>
> +              .Case( "IMAGE_FILE_MACHINE_THUMB"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_THUMB)<br>
> +              .Case( "IMAGE_FILE_MACHINE_WCEMIPSV2"<br>
> +                   , COFF::IMAGE_FILE_MACHINE_WCEMIPSV2)<br>
> +              .Default(COFF::MachineTypes(-1));<br>
> +            if (Machine == uint16_t(-1)) {<br>
> +              YS.printError(Value, "Invalid value for Machine");<br>
> +              return false;<br>
> +            }<br>
> +          }<br>
> +          Header.Machine = Machine;<br>
><br>
> What's the reason to not directly work on Header.Machine?<br>
<br>
</div></div>So we can detect unknown strings and error. </blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +        } else if (KeyValue == "NumberOfSections") {<br>
> +          if (!getAs(Value, Header.NumberOfSections)) {<br>
> +              YS.printError(Value, "Invalid value for NumberOfSections");<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "TimeDateStamp") {<br>
> +          if (!getAs(Value, Header.TimeDateStamp)) {<br>
> +              YS.printError(Value, "Invalid value for TimeDateStamp");<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "PointerToSymbolTable") {<br>
> +          if (!getAs(Value, Header.PointerToSymbolTable)) {<br>
> +              YS.printError(Value, "Invalid value for PointerToSymbolTable");<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "NumberOfSymbols") {<br>
> +          if (!getAs(Value, Header.NumberOfSymbols)) {<br>
> +              YS.printError(Value, "Invalid value for NumberOfSymbols");<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "SizeOfOptionalHeader") {<br>
> +          if (!getAs(Value, Header.SizeOfOptionalHeader)) {<br>
> +              YS.printError(Value, "Invalid value for SizeOfOptionalHeader");<br>
> +              return false;<br>
> +          }<br>
> +        } else {<br>
> +          YS.printError(Key, "Unrecognized key in header");<br>
> +          return false;<br>
> +        }<br>
> +      }<br>
> +    }<br>
> +    return true;<br>
> +  }<br>
> +<br>
> +  bool parseSections(yaml::Node *SectionsN) {<br>
> +    yaml::SequenceNode *SN = dyn_cast<yaml::SequenceNode>(SectionsN);<br>
> +    if (!SN) {<br>
> +      errs() << "yaml2obj: Got invalid sequence node!\n";<br>
> +      return false;<br>
> +    }<br>
> +    for (yaml::SequenceNode::iterator i = SN->begin(), e = SN->end();<br>
> +                                      i != e; ++i) {<br>
> +      Section Sec;<br>
> +      std::memset(&Sec.Header, 0, sizeof(Sec.Header));<br>
> +      yaml::MappingNode *SecMap = dyn_cast<yaml::MappingNode>(&*i);<br>
> +      if (!SecMap) {<br>
> +        errs() << "yaml2obj: Got invalid section entry!\n";<br>
> +        return false;<br>
> +      }<br>
> +      for (yaml::MappingNode::iterator si = SecMap->begin(), se =<br>
> SecMap->end();<br>
> +                                       si != se; ++si) {<br>
> +        yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(si->getKey());<br>
> +        if (!Key) {<br>
> +          errs() << "yaml2obj: Got non scalar key!\n";<br>
> +          return false;<br>
> +        }<br>
> +        SmallString<32> Storage;<br>
> +        StringRef KeyValue = Key->getValue(Storage);<br>
><br>
> This seems to be a very common pattern. I wonder whether we can get a<br>
> convenience call for that into the yaml node.<br>
<br>
</div></div>Do you mean just these two lines? Storage has to have the correct scope.<br></blockquote><div><br></div><div>I mean the general pulling out values from scalar nodes & other stuff. My gut feeling is that there are nicer abstractions hiding in here :)</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
> +        yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(si->getValue());<br>
> +        if (KeyValue == "Name") {<br>
> +          // If the name is less than 8 bytes, store it in place, otherwise<br>
> +          // store it in the string table.<br>
> +          StringRef Name = Value->getValue(Storage);<br>
> +          std::fill_n(<a href="http://Sec.Header.Name" target="_blank">Sec.Header.Name</a>, unsigned(COFF::NameSize), 0);<br>
> +          if (Name.size() <= COFF::NameSize) {<br>
> +            std::copy(Name.begin(), Name.end(), <a href="http://Sec.Header.Name" target="_blank">Sec.Header.Name</a>);<br>
> +          } else {<br>
> +            // Add string to the string table and format the index for output.<br>
> +            unsigned Index = getStringIndex(Name);<br>
> +            std::string str = utostr(Index);<br>
> +            if (str.size() > 7) {<br>
> +              errs() << "yaml2obj: String table got too large!\n";<br>
> +              return false;<br>
> +            }<br>
> +            <a href="http://Sec.Header.Name" target="_blank">Sec.Header.Name</a>[0] = '/';<br>
> +            std::copy(str.begin(), str.end(), <a href="http://Sec.Header.Name" target="_blank">Sec.Header.Name</a> + 1);<br>
> +          }<br>
> +        } else if (KeyValue == "VirtualSize") {<br>
> +          if (!getAs(Value, Sec.Header.VirtualSize)) {<br>
> +              errs() << "yaml2obj: Invalid VirtualSize!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "VirtualAddress") {<br>
> +          if (!getAs(Value, Sec.Header.VirtualAddress)) {<br>
> +              errs() << "yaml2obj: Invalid VirtualAddress!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "SizeOfRawData") {<br>
> +          if (!getAs(Value, Sec.Header.SizeOfRawData)) {<br>
> +              errs() << "yaml2obj: Invalid SizeOfRawData!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "PointerToRawData") {<br>
> +          if (!getAs(Value, Sec.Header.PointerToRawData)) {<br>
> +              errs() << "yaml2obj: Invalid PointerToRawData!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "PointerToRelocations") {<br>
> +          if (!getAs(Value, Sec.Header.PointerToRelocations)) {<br>
> +              errs() << "yaml2obj: Invalid PointerToRelocations!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "PointerToLineNumbers") {<br>
> +          if (!getAs(Value, Sec.Header.PointerToLineNumbers)) {<br>
> +              errs() << "yaml2obj: Invalid PointerToLineNumbers!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "NumberOfRelocations") {<br>
> +          if (!getAs(Value, Sec.Header.NumberOfRelocations)) {<br>
> +              errs() << "yaml2obj: Invalid NumberOfRelocations!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "NumberOfLineNumbers") {<br>
> +          if (!getAs(Value, Sec.Header.NumberOfLineNumbers)) {<br>
> +              errs() << "yaml2obj: Invalid NumberOfLineNumbers!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "Characteristics") {<br>
><br>
> Isn't this completely duplicated code from above? If not, it would<br>
> make sense to add a comment to point out the differences.<br>
<br>
</div></div>It's a different set of characteristics.<br></blockquote><div><br></div><div>Yes, but the rest of  the code is the same...</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +          yaml::SequenceNode *SeqValue<br>
> +            = dyn_cast<yaml::SequenceNode>(si->getValue());<br>
> +          if (!Value && !SeqValue) {<br>
> +            errs() << "yaml2obj: Characteristics must be a scalar or seq!\n";<br>
> +            return false;<br>
> +          }<br>
> +          if (Value) {<br>
> +            if (!getAs(Value, Sec.Header.Characteristics)) {<br>
> +              errs() << "yaml2obj: Failed to parse Characteristics!\n";<br>
> +              return false;<br>
> +            }<br>
> +          } else {<br>
> +            for (yaml::SequenceNode::iterator ci = SeqValue->begin(),<br>
> +                                              ce = SeqValue->end();<br>
> +                                              ci != ce; ++ci) {<br>
> +              yaml::ScalarNode *CharValue = dyn_cast<yaml::ScalarNode>(&*ci);<br>
> +              if (!CharValue) {<br>
> +                errs() << "yaml2obj: Failed to parse Characteristics!\n";<br>
> +                return false;<br>
> +              }<br>
> +              StringRef Char = CharValue->getValue(Storage);<br>
> +              Sec.Header.Characteristics<br>
> +                |= StringSwitch<COFF::SectionCharacteristics>(Char)<br>
> +                .Case( "IMAGE_SCN_TYPE_NO_PAD"<br>
> +                     , COFF::IMAGE_SCN_TYPE_NO_PAD)<br>
> +                .Case( "IMAGE_SCN_CNT_CODE"<br>
> +                     , COFF::IMAGE_SCN_CNT_CODE)<br>
> +                .Case( "IMAGE_SCN_CNT_INITIALIZED_DATA"<br>
> +                     , COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)<br>
> +                .Case( "IMAGE_SCN_CNT_UNINITIALIZED_DATA"<br>
> +                     , COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)<br>
> +                .Case( "IMAGE_SCN_LNK_OTHER"<br>
> +                     , COFF::IMAGE_SCN_LNK_OTHER)<br>
> +                .Case( "IMAGE_SCN_LNK_INFO"<br>
> +                     , COFF::IMAGE_SCN_LNK_INFO)<br>
> +                .Case( "IMAGE_SCN_LNK_REMOVE"<br>
> +                     , COFF::IMAGE_SCN_LNK_REMOVE)<br>
> +                .Case( "IMAGE_SCN_LNK_COMDAT"<br>
> +                     , COFF::IMAGE_SCN_LNK_COMDAT)<br>
> +                .Case( "IMAGE_SCN_GPREL"<br>
> +                     , COFF::IMAGE_SCN_GPREL)<br>
> +                .Case( "IMAGE_SCN_MEM_PURGEABLE"<br>
> +                     , COFF::IMAGE_SCN_MEM_PURGEABLE)<br>
> +                .Case( "IMAGE_SCN_MEM_16BIT"<br>
> +                     , COFF::IMAGE_SCN_MEM_16BIT)<br>
> +                .Case( "IMAGE_SCN_MEM_LOCKED"<br>
> +                     , COFF::IMAGE_SCN_MEM_LOCKED)<br>
> +                .Case( "IMAGE_SCN_MEM_PRELOAD"<br>
> +                     , COFF::IMAGE_SCN_MEM_PRELOAD)<br>
> +                .Case( "IMAGE_SCN_ALIGN_1BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_1BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_2BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_2BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_4BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_4BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_8BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_8BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_16BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_16BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_32BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_32BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_64BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_64BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_128BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_128BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_256BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_256BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_512BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_512BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_1024BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_1024BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_2048BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_2048BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_4096BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_4096BYTES)<br>
> +                .Case( "IMAGE_SCN_ALIGN_8192BYTES"<br>
> +                     , COFF::IMAGE_SCN_ALIGN_8192BYTES)<br>
> +                .Case( "IMAGE_SCN_LNK_NRELOC_OVFL"<br>
> +                     , COFF::IMAGE_SCN_LNK_NRELOC_OVFL)<br>
> +                .Case( "IMAGE_SCN_MEM_DISCARDABLE"<br>
> +                     , COFF::IMAGE_SCN_MEM_DISCARDABLE)<br>
> +                .Case( "IMAGE_SCN_MEM_NOT_CACHED"<br>
> +                     , COFF::IMAGE_SCN_MEM_NOT_CACHED)<br>
> +                .Case( "IMAGE_SCN_MEM_NOT_PAGED"<br>
> +                     , COFF::IMAGE_SCN_MEM_NOT_PAGED)<br>
> +                .Case( "IMAGE_SCN_MEM_SHARED"<br>
> +                     , COFF::IMAGE_SCN_MEM_SHARED)<br>
> +                .Case( "IMAGE_SCN_MEM_EXECUTE"<br>
> +                     , COFF::IMAGE_SCN_MEM_EXECUTE)<br>
> +                .Case( "IMAGE_SCN_MEM_READ"<br>
> +                     , COFF::IMAGE_SCN_MEM_READ)<br>
> +                .Case( "IMAGE_SCN_MEM_WRITE"<br>
> +                     , COFF::IMAGE_SCN_MEM_WRITE)<br>
> +                .Default(COFF::SectionCharacteristics(-1));<br>
> +            }<br>
> +          }<br>
> +        } else if (KeyValue == "SectionData") {<br>
> +          yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(si->getValue());<br>
> +          SmallString<32> Storage;<br>
> +          StringRef Data = Value->getValue(Storage);<br>
> +          Sec.Data.assign(Data.begin(), Data.end());<br>
> +        } else<br>
> +          si->skip();<br>
> +      }<br>
> +      Sections.push_back(Sec);<br>
> +    }<br>
> +    return true;<br>
> +  }<br>
> +<br>
> +  bool parseSymbols(yaml::Node *SymbolsN) {<br>
> +    yaml::SequenceNode *SN = dyn_cast<yaml::SequenceNode>(SymbolsN);<br>
> +    if (!SN) {<br>
> +      errs() << "yaml2obj: Got invalid sequence node!\n";<br>
> +      return false;<br>
> +    }<br>
> +    for (yaml::SequenceNode::iterator i = SN->begin(), e = SN->end();<br>
> +                                      i != e; ++i) {<br>
> +      Symbol Sym;<br>
> +      std::memset(&Sym.Header, 0, sizeof(Sym.Header));<br>
> +      yaml::MappingNode *SymMap = dyn_cast<yaml::MappingNode>(&*i);<br>
> +      if (!SymMap) {<br>
> +        errs() << "yaml2obj: Got invalid section entry!\n";<br>
> +        return false;<br>
> +      }<br>
> +      for (yaml::MappingNode::iterator si = SymMap->begin(), se =<br>
> SymMap->end();<br>
> +                                       si != se; ++si) {<br>
> +        yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(si->getKey());<br>
> +        if (!Key) {<br>
> +          errs() << "yaml2obj: Got non scalar key!\n";<br>
> +          return false;<br>
> +        }<br>
> +        SmallString<32> Storage;<br>
> +        StringRef KeyValue = Key->getValue(Storage);<br>
> +<br>
> +        yaml::ScalarNode *Value = dyn_cast<yaml::ScalarNode>(si->getValue());<br>
> +        if (!Value) {<br>
> +          errs() << "yaml2obj: Failed to parse symbol value!\n";<br>
> +          return false;<br>
> +        }<br>
> +        if (KeyValue == "Name") {<br>
> +          // If the name is less than 8 bytes, store it in place, otherwise<br>
> +          // store it in the string table.<br>
> +          StringRef Name = Value->getValue(Storage);<br>
> +          std::fill_n(<a href="http://Sym.Header.Name" target="_blank">Sym.Header.Name</a>, unsigned(COFF::NameSize), 0);<br>
> +          if (Name.size() <= COFF::NameSize) {<br>
> +            std::copy(Name.begin(), Name.end(), <a href="http://Sym.Header.Name" target="_blank">Sym.Header.Name</a>);<br>
> +          } else {<br>
> +            // Add string to the string table and format the index for output.<br>
> +            unsigned Index = getStringIndex(Name);<br>
> +            *reinterpret_cast<support::aligned_ulittle32_t*>(<br>
> +              <a href="http://Sym.Header.Name" target="_blank">Sym.Header.Name</a> + 4) = Index;<br>
> +          }<br>
> +        } else if (KeyValue == "Value") {<br>
> +          if (!getAs(Value, Sym.Header.Value)) {<br>
> +              errs() << "yaml2obj: Invalid Value!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "SimpleType") {<br>
> +          Sym.Header.Type |= StringSwitch<COFF::SymbolBaseType>(<br>
> +            Value->getValue(Storage))<br>
> +            .Case("IMAGE_SYM_TYPE_NULL", COFF::IMAGE_SYM_TYPE_NULL)<br>
> +            .Case("IMAGE_SYM_TYPE_VOID", COFF::IMAGE_SYM_TYPE_VOID)<br>
> +            .Case("IMAGE_SYM_TYPE_CHAR", COFF::IMAGE_SYM_TYPE_CHAR)<br>
> +            .Case("IMAGE_SYM_TYPE_SHORT", COFF::IMAGE_SYM_TYPE_SHORT)<br>
> +            .Case("IMAGE_SYM_TYPE_INT", COFF::IMAGE_SYM_TYPE_INT)<br>
> +            .Case("IMAGE_SYM_TYPE_LONG", COFF::IMAGE_SYM_TYPE_LONG)<br>
> +            .Case("IMAGE_SYM_TYPE_FLOAT", COFF::IMAGE_SYM_TYPE_FLOAT)<br>
> +            .Case("IMAGE_SYM_TYPE_DOUBLE", COFF::IMAGE_SYM_TYPE_DOUBLE)<br>
> +            .Case("IMAGE_SYM_TYPE_STRUCT", COFF::IMAGE_SYM_TYPE_STRUCT)<br>
> +            .Case("IMAGE_SYM_TYPE_UNION", COFF::IMAGE_SYM_TYPE_UNION)<br>
> +            .Case("IMAGE_SYM_TYPE_ENUM", COFF::IMAGE_SYM_TYPE_ENUM)<br>
> +            .Case("IMAGE_SYM_TYPE_MOE", COFF::IMAGE_SYM_TYPE_MOE)<br>
> +            .Case("IMAGE_SYM_TYPE_BYTE", COFF::IMAGE_SYM_TYPE_BYTE)<br>
> +            .Case("IMAGE_SYM_TYPE_WORD", COFF::IMAGE_SYM_TYPE_WORD)<br>
> +            .Case("IMAGE_SYM_TYPE_UINT", COFF::IMAGE_SYM_TYPE_UINT)<br>
> +            .Case("IMAGE_SYM_TYPE_DWORD", COFF::IMAGE_SYM_TYPE_DWORD)<br>
> +            .Default(COFF::IMAGE_SYM_TYPE_NULL);<br>
> +        } else if (KeyValue == "ComplexType") {<br>
> +          Sym.Header.Type |= StringSwitch<COFF::SymbolComplexType>(<br>
> +            Value->getValue(Storage))<br>
> +            .Case("IMAGE_SYM_DTYPE_NULL", COFF::IMAGE_SYM_DTYPE_NULL)<br>
> +            .Case("IMAGE_SYM_DTYPE_POINTER", COFF::IMAGE_SYM_DTYPE_POINTER)<br>
> +            .Case("IMAGE_SYM_DTYPE_FUNCTION", COFF::IMAGE_SYM_DTYPE_FUNCTION)<br>
> +            .Case("IMAGE_SYM_DTYPE_ARRAY", COFF::IMAGE_SYM_DTYPE_ARRAY)<br>
> +            .Default(COFF::IMAGE_SYM_DTYPE_NULL)<br>
> +            << COFF::SCT_COMPLEX_TYPE_SHIFT;<br>
> +        } else if (KeyValue == "StorageClass") {<br>
> +          Sym.Header.StorageClass = StringSwitch<COFF::SymbolStorageClass>(<br>
> +            Value->getValue(Storage))<br>
> +            .Case( "IMAGE_SYM_CLASS_END_OF_FUNCTION"<br>
> +                 , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION)<br>
> +            .Case( "IMAGE_SYM_CLASS_NULL"<br>
> +                 , COFF::IMAGE_SYM_CLASS_NULL)<br>
> +            .Case( "IMAGE_SYM_CLASS_AUTOMATIC"<br>
> +                 , COFF::IMAGE_SYM_CLASS_AUTOMATIC)<br>
> +            .Case( "IMAGE_SYM_CLASS_EXTERNAL"<br>
> +                 , COFF::IMAGE_SYM_CLASS_EXTERNAL)<br>
> +            .Case( "IMAGE_SYM_CLASS_STATIC"<br>
> +                 , COFF::IMAGE_SYM_CLASS_STATIC)<br>
> +            .Case( "IMAGE_SYM_CLASS_REGISTER"<br>
> +                 , COFF::IMAGE_SYM_CLASS_REGISTER)<br>
> +            .Case( "IMAGE_SYM_CLASS_EXTERNAL_DEF"<br>
> +                 , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF)<br>
> +            .Case( "IMAGE_SYM_CLASS_LABEL"<br>
> +                 , COFF::IMAGE_SYM_CLASS_LABEL)<br>
> +            .Case( "IMAGE_SYM_CLASS_UNDEFINED_LABEL"<br>
> +                 , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL)<br>
> +            .Case( "IMAGE_SYM_CLASS_MEMBER_OF_STRUCT"<br>
> +                 , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT)<br>
> +            .Case( "IMAGE_SYM_CLASS_ARGUMENT"<br>
> +                 , COFF::IMAGE_SYM_CLASS_ARGUMENT)<br>
> +            .Case( "IMAGE_SYM_CLASS_STRUCT_TAG"<br>
> +                 , COFF::IMAGE_SYM_CLASS_STRUCT_TAG)<br>
> +            .Case( "IMAGE_SYM_CLASS_MEMBER_OF_UNION"<br>
> +                 , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION)<br>
> +            .Case( "IMAGE_SYM_CLASS_UNION_TAG"<br>
> +                 , COFF::IMAGE_SYM_CLASS_UNION_TAG)<br>
> +            .Case( "IMAGE_SYM_CLASS_TYPE_DEFINITION"<br>
> +                 , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION)<br>
> +            .Case( "IMAGE_SYM_CLASS_UNDEFINED_STATIC"<br>
> +                 , COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC)<br>
> +            .Case( "IMAGE_SYM_CLASS_ENUM_TAG"<br>
> +                 , COFF::IMAGE_SYM_CLASS_ENUM_TAG)<br>
> +            .Case( "IMAGE_SYM_CLASS_MEMBER_OF_ENUM"<br>
> +                 , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM)<br>
> +            .Case( "IMAGE_SYM_CLASS_REGISTER_PARAM"<br>
> +                 , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM)<br>
> +            .Case( "IMAGE_SYM_CLASS_BIT_FIELD"<br>
> +                 , COFF::IMAGE_SYM_CLASS_BIT_FIELD)<br>
> +            .Case( "IMAGE_SYM_CLASS_BLOCK"<br>
> +                 , COFF::IMAGE_SYM_CLASS_BLOCK)<br>
> +            .Case( "IMAGE_SYM_CLASS_FUNCTION"<br>
> +                 , COFF::IMAGE_SYM_CLASS_FUNCTION)<br>
> +            .Case( "IMAGE_SYM_CLASS_END_OF_STRUCT"<br>
> +                 , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT)<br>
> +            .Case( "IMAGE_SYM_CLASS_FILE"<br>
> +                 , COFF::IMAGE_SYM_CLASS_FILE)<br>
> +            .Case( "IMAGE_SYM_CLASS_SECTION"<br>
> +                 , COFF::IMAGE_SYM_CLASS_SECTION)<br>
> +            .Case( "IMAGE_SYM_CLASS_WEAK_EXTERNAL"<br>
> +                 , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL)<br>
> +            .Case( "IMAGE_SYM_CLASS_CLR_TOKEN"<br>
> +                 , COFF::IMAGE_SYM_CLASS_CLR_TOKEN)<br>
> +            .Default(COFF::SymbolStorageClass(-2));<br>
><br>
> -2 seems is a strange constant in the code, can we pull one out?<br>
<br>
</div></div>-1 and 0 are valid storage classes.<br></blockquote><div><br></div><div>Then why not add a constant inside COFF:: for this? COFF::IMAGE_SYM_CLASS_INVALID or something?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5">
> +          if (Sym.Header.StorageClass == -2) {<br>
> +            errs() << "yaml2obj: Invalid StorageClass!\n";<br>
> +            return false;<br>
> +          }<br>
> +        } else if (KeyValue == "SectionNumber") {<br>
> +          if (!getAs(Value, Sym.Header.SectionNumber)) {<br>
> +              errs() << "yaml2obj: Invalid SectionNumber!\n";<br>
> +              return false;<br>
> +          }<br>
> +        } else if (KeyValue == "AuxillaryData") {<br>
> +          StringRef Data = Value->getValue(Storage);<br>
> +          Sym.AuxSymbols.assign(Data.begin(), Data.end());<br>
> +        } else<br>
> +          si->skip();<br>
> +      }<br>
> +      Symbols.push_back(Sym);<br>
> +    }<br>
> +    return true;<br>
> +  }<br>
> +<br>
> +  bool parse() {<br>
> +    yaml::Document &D = *YS.begin();<br>
> +    yaml::MappingNode *Root = dyn_cast<yaml::MappingNode>(D.getRoot());<br>
> +    if (!Root) {<br>
> +      errs() << "yaml2obj: Got invalid root node!\n";<br>
> +      return false;<br>
> +    }<br>
> +    for (yaml::MappingNode::iterator i = Root->begin(), e = Root->end();<br>
> +                                     i != e; ++i) {<br>
> +      yaml::ScalarNode *Key = dyn_cast<yaml::ScalarNode>(i->getKey());<br>
> +      if (!Key) {<br>
> +        errs() << "yaml2obj: Got non scalar top level key!\n";<br>
> +        return false;<br>
> +      }<br>
> +      SmallString<32> Storage;<br>
> +      StringRef KeyValue = Key->getValue(Storage);<br>
> +      if (KeyValue == "header") {<br>
> +        if (!parseHeader(i->getValue()))<br>
> +          return false;<br>
> +      } else if (KeyValue == "sections") {<br>
> +        if (!parseSections(i->getValue()))<br>
> +          return false;<br>
> +      } else if (KeyValue == "symbols") {<br>
> +        if (!parseSymbols(i->getValue()))<br>
> +          return false;<br>
> +      }<br>
> +    }<br>
> +    return true;<br>
> +  }<br>
> +<br>
> +  unsigned getStringIndex(StringRef Str) {<br>
> +    StringMap<unsigned>::iterator i = StringTableMap.find(Str);<br>
> +    if (i == StringTableMap.end()) {<br>
> +      unsigned Index = StringTable.size();<br>
> +      StringTable.append(Str.begin(), Str.end());<br>
> +      StringTable.push_back(0);<br>
> +      StringTableMap[Str] = Index;<br>
> +      return Index;<br>
> +    }<br>
> +    return i->second;<br>
> +  }<br>
> +<br>
> +  yaml::Stream &YS;<br>
> +  COFF::header Header;<br>
> +<br>
> +  struct Section {<br>
> +    COFF::section Header;<br>
> +    std::vector<uint8_t> Data;<br>
> +    std::vector<COFF::relocation> Relocations;<br>
> +  };<br>
> +<br>
> +  struct Symbol {<br>
> +    COFF::symbol Header;<br>
> +    std::vector<uint8_t> AuxSymbols;<br>
> +  };<br>
> +<br>
> +  std::vector<Section> Sections;<br>
> +  std::vector<Symbol> Symbols;<br>
> +  StringMap<unsigned> StringTableMap;<br>
> +  std::string StringTable;<br>
> +};<br>
> +<br>
> +// Take a CP and assign addresses and sizes to everything. Returns false if the<br>
> +// layout is not valid to do.<br>
> +static bool layoutCOFF(COFFParser &CP) {<br>
> +  uint32_t SectionTableStart = 0;<br>
> +  uint32_t SectionTableSize  = 0;<br>
> +  //uint32_t SymbolTableStart  = 0;<br>
> +  //uint32_t SymbolTableSize   = 0;<br>
><br>
> Remove commented out code?<br>
<br>
</div></div>Fixed.<br>
<div><div class="h5"><br>
> +  // The section table starts immediately after the header, including the<br>
> +  // optional header.<br>
> +  SectionTableStart = sizeof(COFF::header) + CP.Header.SizeOfOptionalHeader;<br>
> +  SectionTableSize = sizeof(COFF::section) * CP.Sections.size();<br>
> +<br>
> +  uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize;<br>
> +<br>
> +  // Assign each section data address consecutively.<br>
> +  for (std::vector<COFFParser::Section>::iterator i = CP.Sections.begin(),<br>
> +                                                  e = CP.Sections.end();<br>
> +                                                  i != e; ++i) {<br>
> +    if (!i->Data.empty()) {<br>
> +      i->Header.SizeOfRawData = i->Data.size();<br>
> +      i->Header.PointerToRawData = CurrentSectionDataOffset;<br>
> +      CurrentSectionDataOffset += i->Header.SizeOfRawData;<br>
> +      // TODO: Handle alignment.<br>
> +    } else {<br>
> +      i->Header.SizeOfRawData = 0;<br>
> +      i->Header.PointerToRawData = 0;<br>
> +    }<br>
> +  }<br>
> +<br>
> +  uint32_t SymbolTableStart = CurrentSectionDataOffset;<br>
> +<br>
> +  // Calculate number of symbols.<br>
> +  uint32_t NumberOfSymbols = 0;<br>
> +  for (std::vector<COFFParser::Symbol>::iterator i = CP.Symbols.begin(),<br>
> +                                                 e = CP.Symbols.end();<br>
> +                                                 i != e; ++i) {<br>
> +    if (i->AuxSymbols.size() % COFF::SymbolSize != 0) {<br>
> +      errs() << "AuxillaryData size not a multiple of symbol size!\n";<br>
> +      return false;<br>
> +    }<br>
> +    i->Header.NumberOfAuxSymbols = i->AuxSymbols.size() / COFF::SymbolSize;<br>
> +    NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols;<br>
> +  }<br>
> +<br>
> +  // Store all the allocated start addresses in the header.<br>
> +  CP.Header.NumberOfSections = CP.Sections.size();<br>
> +  CP.Header.NumberOfSymbols = NumberOfSymbols;<br>
> +  CP.Header.PointerToSymbolTable = SymbolTableStart;<br>
> +<br>
> +  *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0])<br>
> +    = CP.StringTable.size();<br>
> +<br>
> +  return true;<br>
> +}<br>
> +<br>
> +template <typename value_type><br>
> +struct binary_le_impl {<br>
> +  value_type Value;<br>
> +  binary_le_impl(value_type V) : Value(V) {}<br>
> +};<br>
> +<br>
> +template <typename value_type><br>
> +raw_ostream &operator <<( raw_ostream &OS<br>
> +                        , const binary_le_impl<value_type> &BLE) {<br>
> +  char Buffer[sizeof(BLE.Value)];<br>
> +  support::endian::write_le<value_type, support::unaligned>(Buffer, BLE.Value);<br>
> +  OS.write(Buffer, sizeof(BLE.Value));<br>
> +  return OS;<br>
> +}<br>
><br>
> What's the reason to not directly use the value type as template parameter?<br>
<br>
</div></div>What do you mean?<br></blockquote><div><br></div><div>Ah, forget it, I hallucinated.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb">
<div class="h5"><br>
> +template <typename value_type><br>
> +binary_le_impl<value_type> binary_le(value_type V) {<br>
> +  return binary_le_impl<value_type>(V);<br>
> +}<br>
> +<br>
> +void writeCOFF(COFFParser &CP, raw_ostream &OS) {<br>
> +  OS << binary_le(CP.Header.Machine)<br>
> +     << binary_le(CP.Header.NumberOfSections)<br>
> +     << binary_le(CP.Header.TimeDateStamp)<br>
> +     << binary_le(CP.Header.PointerToSymbolTable)<br>
> +     << binary_le(CP.Header.NumberOfSymbols)<br>
> +     << binary_le(CP.Header.SizeOfOptionalHeader)<br>
> +     << binary_le(CP.Header.Characteristics);<br>
> +<br>
> +  // Output section table.<br>
> +  for (std::vector<COFFParser::Section>::const_iterator i =<br>
> CP.Sections.begin(),<br>
> +                                                        e = CP.Sections.end();<br>
> +                                                        i != e; ++i) {<br>
> +    OS.write(i->Header.Name, COFF::NameSize);<br>
> +    OS << binary_le(i->Header.VirtualSize)<br>
> +       << binary_le(i->Header.VirtualAddress)<br>
> +       << binary_le(i->Header.SizeOfRawData)<br>
> +       << binary_le(i->Header.PointerToRawData)<br>
> +       << binary_le(i->Header.PointerToRelocations)<br>
> +       << binary_le(i->Header.PointerToLineNumbers)<br>
> +       << binary_le(i->Header.NumberOfRelocations)<br>
> +       << binary_le(i->Header.NumberOfLineNumbers)<br>
> +       << binary_le(i->Header.Characteristics);<br>
> +  }<br>
> +<br>
> +  // Output section data.<br>
> +  for (std::vector<COFFParser::Section>::const_iterator i =<br>
> CP.Sections.begin(),<br>
> +                                                        e = CP.Sections.end();<br>
> +                                                        i != e; ++i) {<br>
> +    if (!i->Data.empty())<br>
> +      OS.write(reinterpret_cast<const char*>(&i->Data[0]), i->Data.size());<br>
> +  }<br>
> +<br>
> +  // Output symbol table.<br>
> +<br>
> +  for (std::vector<COFFParser::Symbol>::const_iterator i = CP.Symbols.begin(),<br>
> +                                                       e = CP.Symbols.end();<br>
> +                                                       i != e; ++i) {<br>
> +    OS.write(i->Header.Name, COFF::NameSize);<br>
> +    OS << binary_le(i->Header.Value)<br>
> +       << binary_le(i->Header.SectionNumber)<br>
> +       << binary_le(i->Header.Type)<br>
> +       << binary_le(i->Header.StorageClass)<br>
> +       << binary_le(i->Header.NumberOfAuxSymbols);<br>
> +    if (!i->AuxSymbols.empty())<br>
> +      OS.write( reinterpret_cast<const char*>(&i->AuxSymbols[0])<br>
> +              , i->AuxSymbols.size());<br>
> +  }<br>
> +<br>
> +  // Output string table.<br>
> +  OS.write(&CP.StringTable[0], CP.StringTable.size());<br>
> +}<br>
> +<br>
> +int main(int argc, char **argv) {<br>
> +  cl::ParseCommandLineOptions(argc, argv);<br>
> +  sys::PrintStackTraceOnErrorSignal();<br>
> +  PrettyStackTraceProgram X(argc, argv);<br>
> +  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.<br>
> +<br>
> +  OwningPtr<MemoryBuffer> Buf;<br>
> +  if (MemoryBuffer::getFileOrSTDIN(Input, Buf))<br>
> +    return 1;<br>
> +<br>
> +  SourceMgr SM;<br>
> +  yaml::Stream S(Buf->getBuffer(), SM);<br>
> +  COFFParser CP(S);<br>
> +  if (!CP.parse()) {<br>
> +    errs() << "yaml2obj: Failed to parse YAML file!\n";<br>
> +    return 1;<br>
> +  }<br>
> +  if (!layoutCOFF(CP)) {<br>
> +    errs() << "yaml2obj: Failed to layout COFF file!\n";<br>
> +    return 1;<br>
> +  }<br>
> +  writeCOFF(CP, outs());<br>
> +}<br>
><br>
> On Tue, May 15, 2012 at 12:54 AM, Michael Spencer <<a href="mailto:bigcheesegs@gmail.com">bigcheesegs@gmail.com</a>> wrote:<br>
>> Add yaml2obj. A utility to convert YAML to binaries.<br>
>><br>
>> yaml2obj takes a textual description of an object file in YAML format<br>
>> and outputs the binary equivalent to stdout. This greatly simplifies writing<br>
>> tests that take binary object files as input.<br>
>><br>
>> The attached patch adds this tool for a subset of COFF and includes<br>
>> documentation.<br>
>><br>
>> I plan to add support for PE, ELF, and MachO. This helps with both<br>
>> LLVMObject and lld tests.<br>
>><br>
>> - Michael Spencer<br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">- Michael Spencer<br>
</font></span></blockquote></div><br></font></div>